home *** CD-ROM | disk | FTP | other *** search
/ Arawak OS/2 Shareware / PAKLED.ISO / docs / edm / edmi2-8.inf (.txt) < prev    next >
Encoding:
OS/2 Help File  |  1994-09-10  |  190.0 KB  |  3,366 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Sept 1994 Title Page ΓòÉΓòÉΓòÉ
  3.  
  4.                                       EDM/2
  5.  
  6.                   The Electronic Developer's Magazine for OS/2
  7.  
  8.                    Portions copyright (c) by Larry Salomon Jr.
  9.                                 Volume 2, issue 8
  10.  
  11. Copyright Notice and Other Stuff 
  12.  
  13. The Editor-in-Chief of this electronic magazine is Larry Salomon, Jr. 
  14.  
  15. Portions of EDM/2 are copyrighted by the editors.  This publication may be 
  16. freely distributed in electronic form provided that all parts are present in 
  17. their original unmodified form.  A reasonable fee may be charged for the 
  18. physical act of distribution; no fee may be charged for the publication itself. 
  19.  
  20. All articles are copyrighted by their authors. No part of any article may be 
  21. reproduced without permission from the original author. 
  22.  
  23. Neither this publication nor the editors are affiliated with International 
  24. Business Machines Corporation. 
  25.  
  26. OS/2 is a registered trademark of International Business Machines Corporation. 
  27. Other trademarks are property of their respective owners.  Any mention of a 
  28. product in this publication does not constitute an endorsement or affiliation 
  29. unless specifically stated in the text. 
  30.  
  31. Administrivia 
  32.  
  33. Oh boy! 
  34.  
  35. What a time it has been.  One never realizes how much a job can take out of you 
  36. until you have a two month break from it.  If you only knew how hard I had to 
  37. kick myself to get back into the routine.  <grin>  So much has happened, and I 
  38. am the worst note-taker in the world; still, I will try my best to tell you all 
  39. about it here. 
  40.  
  41. Internet Relay Chat 
  42.  
  43. Some time ago, I mentioned how addicting this can become.  It should be noted, 
  44. however, that there exists a channel called #os/2 where many people frequent; 
  45. if you have any questions and are lucky enough to have access to this, you 
  46. might want to drop by.  Given the popularity of this chatting program, an idea 
  47. has been considered where seminars could be given on a channel on programming 
  48. techniques.  We will keep you posted. 
  49.  
  50. VIO and the PM Subset 
  51.  
  52. This month sees the beginning of a new series on the development of a library; 
  53. what makes this library so special is that it is a subset of PM for full-screen 
  54. character-mode applications.  The library was written for a project at work 
  55. (which should be on the market soon), but you'll get to see it in depth (along 
  56. with source code, of course) right here. 
  57.  
  58. Sprites Revisited 
  59.  
  60. If you will remember back to the sprite series, I mentioned that the code was 
  61. written with the idea that z-ordering could be added easily at a later date. 
  62. Since then, I have had a some free time on my hands (though not much), so I 
  63. added this useful capability.  The necessary changes are discussed as well as 
  64. the two new APIs that deal with layering in an update to that well-received 
  65. series. 
  66.  
  67. A Helper for the Needy 
  68.  
  69. Have you ever called a function in an application, only to get the "undefined 
  70. prototype" message when you called it?  Antonio "Tony" Tonizzo has gotten that 
  71. message one too many times, and he finally decided to do something about it. 
  72. The result is included with this issue (see API.ZIP); it has the #define 
  73. constant that needs to be defined for each API in OS/2.  Good work, Tony! 
  74.  
  75. For the Short-Sighted 
  76.  
  77. If you hang out in comp.os.os2.programmer.misc, you've probably noticed Dick 
  78. Conklin (the editor of OS/2 Developer) making a post every now and then.  I 
  79. find it exciting that the net is receiving more attention from the media, even 
  80. if it has taken them a long time to do so. 
  81.  
  82. That's it for this month!  Enjoy the issue! 
  83.  
  84. Title Page - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  85.  
  86.  
  87. ΓòÉΓòÉΓòÉ 2. WPS Programming the Easy Way - Part 1 ΓòÉΓòÉΓòÉ
  88.  
  89.  
  90. ΓòÉΓòÉΓòÉ 2.1. Introduction ΓòÉΓòÉΓòÉ
  91.  
  92. WPS Programming the Easy Way - Part 1 
  93.  
  94. Written by Frank Matthijs 
  95.  
  96. Introduction 
  97.  
  98. This is the first of two articles about WPS programming.  As this is an 
  99. introduction, you don't have to know anything at all about WPS programming in 
  100. order to follow the articles.  In fact, they may be too basic for some of you. 
  101. But if you always wondered why all those things on your desktop are called 
  102. objects, and how you are supposed to make your own objects, read on. 
  103.  
  104. After reading these articles, you'll be able to explore the WPS on your own, so 
  105. you can start making your own objects.  You can follow the articles with your 
  106. compiler ready, so you can actually make the objects described in the articles 
  107. and see for yourself how it all works. 
  108.  
  109. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  110.  
  111.  
  112. ΓòÉΓòÉΓòÉ 2.2. Overview ΓòÉΓòÉΓòÉ
  113.  
  114. Overview 
  115.  
  116. Welcome to the magical world of WPS programming.  Since this is a relatively 
  117. new area of programming, there are very few sources of information for 
  118. beginning WPS programmers to find the info they need.  Of course, there are the 
  119. PM Reference and SOM Reference documents, but a reference is only useful when 
  120. you already know something about the subject, or else it rapidly becomes an 
  121. overwhelming collection of unknown terms. 
  122.  
  123. Another source are the numerous sample WPS objects in the IBM toolkit (er, 
  124. actually there is only one, the Car class).  It is very interesting to study 
  125. this example, but unfortunately, it contains a few nasty bugs so that some 
  126. features only nearly work.  Furthermore, it is somewhat difficult to grasp the 
  127. underlying principles just by studying a "working" example. 
  128.  
  129. That's why you're now reading the first of a two-part series on WPS 
  130. programming.  They are intended for as many programmers as possible. Therefore, 
  131. a few very basic concepts are briefly explained (as far as they relate to WPS 
  132. programming), such as inheritance.  Experienced WPS programmers will not find 
  133. these articles of any use, but they could have already guessed so from the 
  134. title of the series. 
  135.  
  136. What You Will Find 
  137.  
  138. This first article will explain some basic concepts of WPS programming. Topics 
  139. covered include object oriented programming (classes, objects, inheritance) and 
  140. SOM programming (class definition file, creating the class DLL, registering the 
  141. DLL).  After that follows a first introduction to the practice of WPS 
  142. programming.  We will build a new (very basic) WPS object, step by step. 
  143.  
  144. In the second article our object will be extended to make it more useful, and 
  145. especially to demonstrate how to use some of the methods and what they're for. 
  146. Our object will offer only part of the functionality of the Car example, but 
  147. the things that are broken there will work here.  Because the articles are 
  148. intended to be a starting point for your own explorations in WPS land, you'll 
  149. be able to add your own functions easily. 
  150.  
  151. After reading the articles and following the examples, you should be able to 
  152. understand most of the explanations in the PM/WPS and SOM references, although 
  153. the descriptions are sometimes too vague or inaccurate to be of any help.  I 
  154. hope there will eventually be enough WPS programmers around to get some 
  155. interesting discussions going in one of the electronic conference areas or 
  156. mailing lists. 
  157.  
  158. What You Will Need 
  159.  
  160. In order to be able to actively follow the programming examples in the articles 
  161. and to get into WPS programming yourself, you need the SOM compiler.  As far as 
  162. I know, this is a problem for programmers using Borland C++ or the GNU GCC or 
  163. EMX development tools.  That is probably the only obstacle on your way to 
  164. becoming a proficient WPS programmer, but it is of course a very serious one. 
  165. I'm afraid you won't be able to enjoy WPS programming if you use one of these 
  166. tools, since I know of no public domain SOM compiler.  Perhaps if you bother 
  167. Borland enough, they'll license the SOM compiler from IBM? 
  168.  
  169. If you're still with us, fine.  You'll also find the SOM reference and the part 
  170. of the PM reference about the Workplace Shell useful, though not as useful as 
  171. it could have been due to vague or incomplete descriptions (but we're used to 
  172. that, aren't we?). 
  173.  
  174. In the examples, I'll assume you use C-Set/2 or C-Set++.  If you use another 
  175. compiler, you may have to modify the makefile, and you should substitute your 
  176. own make program for NMAKE. 
  177.  
  178. What You Need to Know 
  179.  
  180. Since this is an introduction to WPS programming, you don't need to know 
  181. anything about it before you start.  Of course, since the WPS uses the 
  182. Presentation Manager API a lot, it doesn't hurt if you are at least somewhat 
  183. familiar with PM programming.  In these introductory articles, I will stress 
  184. basic WPS stuff, so you don't need to be a PM expert to be able to understand 
  185. what is said. 
  186.  
  187. Because the WPS is based on SOM, and the "O" in "SOM" means "Object", some 
  188. knowledge of object related topics will be a real plus, but I'll try to explain 
  189. the most relevant items in what follows, in case you have never heard of 
  190. objects before (mmm, where have you been the last couple of years, then?). 
  191.  
  192. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  193.  
  194.  
  195. ΓòÉΓòÉΓòÉ 2.3. Object oriented programming ΓòÉΓòÉΓòÉ
  196.  
  197. Object oriented programming 
  198.  
  199. [OO experts, please note:  the following explanation is oversimplified and may 
  200. even be inaccurate.  Its purpose is only to give programmers who know 
  201. absolutely nothing about OO programming enough information to get them started 
  202. with SOM and WPS.  OK?] 
  203.  
  204. In this section, I'll explain some terms and concepts related to OO 
  205. programming.  There's nothing exceptionally spectacular about it, but you'll 
  206. have to know it if you want to fully understand what follows. 
  207.  
  208. Object 
  209.  
  210. An object is nothing more than a collection of data and code. The code is a 
  211. collection of routines, usually called methods.  A linked list for example can 
  212. be an object.  The data could consist of two pointers (start and end of the 
  213. list) and a count of the elements in the list.  Some methods would be provided 
  214. for adding and removing elements to the list, and for determining the number of 
  215. elements in the list. 
  216.  
  217. Good practice dictates that the data be kept private, i.e. unavailable to other 
  218. objects.  If this data must be queryable, you should provide methods to do so. 
  219. This way, you can prevent other objects from tampering with the internal 
  220. representation of your object.  Moreover, if you later decide to change the 
  221. internal workings of your object, you can do so without any problems, provided 
  222. the external specification remains the same.  This separation of the object 
  223. interface from the implementation is a very big advantage of OO programming. 
  224.  
  225. For example:  if you make a List, you could specify the methods Add, Remove, 
  226. and QuerySize.  The set of all methods, together with a specification of how to 
  227. use them, forms the interface of your List.  Everyone using a List must use 
  228. QuerySize to get the number of elements in the List, Add to add an element to 
  229. the List, and so on.  You can change and improve the actual implementation of 
  230. your List (for example, using pointers instead of an array) without this 
  231. affecting its use. In other words:  we can hide the actual implementation 
  232. through the use of abstraction. 
  233.  
  234. Class 
  235.  
  236. Consider the concept Cat.  You can say a lot of general things about Cat, for 
  237. example it is an animal, has four legs and it purrs. These general features 
  238. actually describe a whole class of animals: the class Cat.  The cat of the 
  239. neighbors and the one on your lap are specific instances of the class Cat. 
  240.  
  241. This may sound a little artificial when applied to cats, but these terms are 
  242. also used in OO programming.  A class is a general description of a collection 
  243. of very related objects.  Each of those objects is an instance of that class. 
  244.  
  245. For example, the List in the previous section really is a class (the List 
  246. class).  Every real list is an instance of the List class. 
  247.  
  248. Inheritance 
  249.  
  250. Some classes are related:  a Cat is an Animal, a Rectangle is a Shape, and so 
  251. on.  This "is a" relationship is very common and defines a whole hierarchy of 
  252. classes. Inheritance is the mechanism that allows programmers to express this 
  253. relationship in an object oriented environment. 
  254.  
  255. When some class A "is a" B (e.g. a Data File "is a" File), we can derive class 
  256. A from class B.  The result is that class A inherits all methods of class B. 
  257. All you can do with an object of class B can also be done with an object of 
  258. class A.  Of course, it is still possible to define extra functionality for 
  259. objects of class A, by adding methods to the inherited ones.  If you derive A 
  260. from B, B is called the parent and A the child. 
  261.  
  262. One of the reasons why inheritance is a powerful mechanism, is that you can 
  263. reuse most of the code you wrote for B.  Suppose B is an Editor class, 
  264. implementing a simple text editor, and you want to write a programmable editor, 
  265. you can do so by making a new class, say ProgrammableEditor, and deriving this 
  266. class from Editor.  That way, you inherit all methods from Editor, so you don't 
  267. have to recode the basic editor stuff like moving the cursor and storing the 
  268. text. 
  269.  
  270. Another interesting feature of inheritance is that, when A is derived from B, 
  271. any function that expects an object of class B, can actually be passed 
  272. instances of class A as well.  So you could make a class List with method Add, 
  273. accepting objects of class Link.  The result is you cannot only add objects of 
  274. class Link to your List, but also any object of a class derived from Link. This 
  275. feature is called polymorphism:  you can have a List containing objects of 
  276. different types. 
  277.  
  278. Besides adding methods in a derived class, it is also possible to replace the 
  279. functionality of some inherited methods.  Doing so is called overriding these 
  280. methods.  When A overrides a method it would inherit from B, it is asking to 
  281. call its own version of the method instead of B's version.  Luckily, B's 
  282. version is still available, so A can choose to do its job and then call B's 
  283. version of the method.  This is somewhat similar to chaining interrupt vectors 
  284. in good old DOS. 
  285.  
  286. For example, if we have a class Rectangle, and we want to make a new class 
  287. Square, we can derive Square from Rectangle, because a Square really is a 
  288. (special sort of) Rectangle.  If Rectangle has a method QueryDiagonal, Square 
  289. inherits this method, so you can also query the diagonal of a Square.  You 
  290. could make use of some specific property of a Square in calculating the length 
  291. of the diagonal (e.g. all sides have the same length), so it could be useful to 
  292. override the method QueryDiagonal in Square and provide the optimized 
  293. calculation instead of the old one.  In this example, the old version of 
  294. QueryDiagonal is not called. 
  295.  
  296. The way inheritance is implemented, depends on the object environment (or 
  297. programming language).  Most of the time, the methods are not actually 
  298. duplicated in A, but instead B's methods are called with A's data (the code is 
  299. identical, only the data differs), except for overridden methods.  When you 
  300. call a method A inherited from B, the system determines some way or another 
  301. that A is derived from B, so it in fact calls B's method.  If the method is 
  302. overridden, A's version is called.  What function should be called can be 
  303. determined statically, at compile time, or dynamically, at run time (in C++ for 
  304. example, it's done statically). 
  305.  
  306. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  307.  
  308.  
  309. ΓòÉΓòÉΓòÉ 2.4. SOM programming ΓòÉΓòÉΓòÉ
  310.  
  311. SOM programming 
  312.  
  313. SOM is an object model (System Object Model), meaning it supports all concepts 
  314. introduced in the previous section (and a lot more too). It is built right into 
  315. OS/2, so you can immediately take advantage of it (provided you have a SOM 
  316. compiler, of course). 
  317.  
  318. In SOM, you can define classes and create instances of these classes (it 
  319. wouldn't be of much use otherwise, would it?).  Of course, you'll have to 
  320. produce some code in order to create a class.  So where do we put this code? 
  321. This is where SOM programming differs from "normal" programming: instead of 
  322. making an executable file (a program), in SOM you create classes. The code for 
  323. these classes is contained in a DLL.  Let's see how we can produce such a DLL 
  324. (we'll be making one later on). 
  325.  
  326.  1. When you want to define a class in SOM, you make a text file describing the 
  327.     properties of your class.  Such a text file should have the extension .CSC 
  328.     and is called the class definition file.  You can specify the name of your 
  329.     new class, the class you want to derive from (in SOM, you always derive 
  330.     from some class, you can't create "root" classes), the methods you want to 
  331.     override and the methods you want to add.  This is always the first step 
  332.     when creating classes for SOM. 
  333.  
  334.  2. After that, you use the SOM compiler to convert this .CSC file to a 
  335.     collection of source files (C, C++ or some other language; currently only C 
  336.     and C++ are supported, we'll assume C here).  So now we have something to 
  337.     put our code in. 
  338.  
  339.  3. The .C file contains default implementations for the methods you have 
  340.     overridden or added.  You can then alter the generated source file (by 
  341.     adding you own code).  When you have coded the methods, you have something 
  342.     you can convert to a DLL file.  Note:  when you later have to change your 
  343.     .CSC file, you must recompile it into new source files, but the SOM 
  344.     compiler is smart enough not to overwrite the changes and additions you 
  345.     have made (i.e. it doesn't simply generate a new generic source file). 
  346.  
  347.  4. The last step in the process is informing OS/2 of your new class, so that 
  348.     it can be used system-wide ever after.  This is accomplished by registering 
  349.     your DLL, using a REXX script or a Win API function. After sucessfully 
  350.     registering your class, you and everyone else can create instances of your 
  351.     class (again using a REXX script or a Win function) and use these instances 
  352.     (objects).  There are also functions to deregister a class and to replace a 
  353.     class with another one. 
  354.  
  355. One important thing to know about SOM objects is that they're persistent.  This 
  356. means they continue to exist, even when you shutdown your system and reboot. 
  357. For this to be possible, most objects must save their state and restore it 
  358. afterwards (this can be done by writing the state to one of the OS/2 INI files 
  359. or to extended attributes). 
  360.  
  361. Metaclasses 
  362.  
  363. In SOM, the class of an object is in fact itself an instance of another class, 
  364. its metaclass.  This metaclass can have methods, just like a normal class.  The 
  365. difference with normal, instance methods (which act upon one particular 
  366. instance of the class) is that these class methods act upon the class itself, 
  367. and thus upon all instances of the class.  We'll encounter both types of 
  368. methods in WPS programming. 
  369.  
  370. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  371.  
  372.  
  373. ΓòÉΓòÉΓòÉ 2.5. WPS Programming ΓòÉΓòÉΓòÉ
  374.  
  375. WPS Programming 
  376.  
  377. The Workplace Shell is nothing more than a collection of complex SOM classes 
  378. that make very intensive use of the OS/2 API, especially the Presentation 
  379. Manager API.  That's why concepts like object, class, method, inheritance, 
  380. overriding, etc. were explained in the previous sections: they're needed for 
  381. WPS programming because WPS is based on SOM and SOM is object oriented. 
  382.  
  383. WPS provides us with a number of classes to work with, like WPFolder, defining 
  384. (surprise!) a folder class.  You can create instances of these classes (for 
  385. example, folders) with a REXX script or a Win API function, as described in the 
  386. section about SOM programming.  The Workplace Shell also provides another way 
  387. to make instances of classes: the Templates folder.  Dragging the Folder 
  388. template, for example, actually creates an instance of the class WPFolder. 
  389.  
  390. You can see what classes WPS defines in the PM reference (under the heading 
  391. Workplace).  All objects you see on your desktop are instances of these WPS 
  392. classes.  For example, there are probably a few folders, instances of the class 
  393. WPFolder.  Other objects are instances of WPPrinter, WPShredder, WPProgram, 
  394. WPDataFile, etc. The WP Class List from the IBM Toolkit is itself an object 
  395. listing the class hierarchy of all WPS classes (recall from the previous 
  396. sections that all SOM classes (and therefore all WPS classes) form a hierarchy, 
  397. showing the relationship between them).  We'll use this tool later on. 
  398.  
  399. Another source of information regarding WPS classes and their use is the IBM 
  400. Redbook volume 3:  PM and Workplace Shell and Redbook volume 4:  Application 
  401. development.  The latter provides very useful information about some methods 
  402. and when they're called, along with more in-depth information about SOM and 
  403. WPS.  They are a good addition to this series and I recommend you read them 
  404. thoroughly. 
  405.  
  406. WPS programming is in fact the creation of new classes, most of the time 
  407. derived from existing WPS classes like WPDataFile, WPFolder, WPSound, and 
  408. adding or overriding methods, to obtain a class that fits our needs.  For 
  409. example, you can create a password-protected folder class by deriving from 
  410. WPFolder and overriding some methods.  Because your new folder class inherits 
  411. all methods from WPFolder, you don't have to write the code that implements the 
  412. folder (opens a PM window, displays icons, supports drag and drop, etc.). The 
  413. only thing you would do is plug your password protection code in by overriding 
  414. a few methods.  The trick here is getting to know for each WPS class what 
  415. methods there are and what they do, so that you know what methods to override 
  416. and why. 
  417.  
  418. This series will introduce some methods step by step, and show their function 
  419. within WPS.  Some methods are almost always overridden (the classics), while 
  420. others are only used in specific cases.  This introduction should encourage you 
  421. to browse through the references to see what's possible. 
  422.  
  423. Tips 
  424.  
  425. From time to time you will encounter tips.  Their purpose is mainly to keep 
  426. beginning WPS programmers "on the right track".  WPS programming has its fair 
  427. share of problems and pitfalls, just like any form of programming. There are 
  428. things you had better know about, or else you lose hours finding out what the 
  429. problem is.  There is nothing more frustrating than discovering that the "bug" 
  430. you've been searching for all day really is a pecularity of the environment 
  431. you're working in.  So do read the tips if you want to save yourself hours of 
  432. useless debugging.  A tip looks like this: 
  433.  
  434.  Tip 
  435.  
  436. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  437.  
  438.  
  439. ΓòÉΓòÉΓòÉ 2.6. Making your first WPS object ΓòÉΓòÉΓòÉ
  440.  
  441. Making your first WPS object 
  442.  
  443. OK, lets get started with this WPS programming business.  I encourage you to 
  444. actually compile the examples you'll find in this article, in order to really 
  445. get the "look and feel" of WPS programming. 
  446.  
  447. To make your life easier, I've included a little program (WPS.CMD) that will 
  448. ready the sample files for you.  Thoughout this and the next article, I will 
  449. mark some points as Step 1, Step 2, etc.  When you see this, you can execute 
  450. the WPS program with the number of the step as a parameter.  This will give you 
  451. all the needed files as they are in the article at the corresponding step, 
  452. making it easy to compile and examine the examples and see the results of each 
  453. step on your desktop.  Please note this will only install the files that are 
  454. different from the previous step, so don't skip any steps. 
  455.  
  456.  Tip 
  457.  
  458. First Steps 
  459.  
  460. Suppose you have made a nifty program working with data files.  Wouldn't it be 
  461. very interesting if you could add "WPS integration" to the list of features? 
  462. Why not make a WPS object class to represent your data files? That's exactly 
  463. what we're going to do in this and the next article. 
  464.  
  465. So where do we start?  You'll remember from the explanation of SOM programming 
  466. that in order to create a new class, you need to make a .CSC file. Since we 
  467. want to make a new data file, we derive from WPDataFile (this is the class 
  468. behind the "Plain Text" Data File objects).  The layout of our .CSC file is 
  469. show in listing 1 below, also illustrating the syntax of the Object Interface 
  470. Definition Language used in the class definition file. 
  471.  
  472. #******************************************************************************
  473. #   Include the class definition file for the parent class
  474. #******************************************************************************
  475.  
  476. include <wpdataf.sc>
  477.  
  478. #******************************************************************************
  479. #   Define the new class
  480. #******************************************************************************
  481.  
  482. class: MyDataFile,
  483.        external stem   = dfd,
  484.        local,
  485.        external prefix = dfd_,
  486.        classprefix     = dfdM_,
  487.        major version   = 1,
  488.        minor version   = 1;
  489.  
  490. --
  491. -- CLASS: MyDataFile
  492. --
  493. -- CLASS HIERARCHY:
  494. --
  495. --     SOMObject
  496. --       ΓööΓöÇΓöÇ WPObject
  497. --             ΓööΓöÇΓöÇ WPFileSystem
  498. --                   ΓööΓöÇΓöÇ WPDataFile
  499. --                         ΓööΓöÇΓöÇ  MyDataFile
  500. --
  501.  
  502. #******************************************************************************
  503. #   Specify the parent class
  504. #******************************************************************************
  505.  
  506. parent: WPDataFile;
  507.  
  508. release order:
  509.     wpclsQueryTitle,
  510.     wpclsQueryInstanceType;
  511.  
  512. passthru: C.ih;
  513.  
  514. #define INCL_WIN
  515. #define INCL_DOS
  516. #include <os2.h>
  517.  
  518. endpassthru;
  519.  
  520.  
  521. #******************************************************************************
  522. #   Specify methods being overridden
  523. #******************************************************************************
  524.  
  525. methods:
  526.  
  527. #******************************************************************************
  528. #   Specify class methods being overridden
  529. #******************************************************************************
  530.  
  531. override wpclsQueryTitle, class;
  532. --
  533. -- METHOD: wpclsQueryTitle                                ( ) PRIVATE
  534. --                                                        (X) PUBLIC
  535. -- DESCRIPTION:
  536. --
  537. --   Return the string "Datafile Deluxe".
  538. --
  539.  
  540. override wpclsQueryInstanceType, class;
  541. --
  542. -- METHOD: wpclsQueryInstanceType                         ( ) PRIVATE
  543. --                                                        (X) PUBLIC
  544. -- DESCRIPTION:
  545. --
  546. --    The wpclsQueryInstanceType method is called to allow the class
  547. --    object to specify the file type for instances of its
  548. --    class.
  549. --
  550. -- RETURNS:
  551. --
  552. --    A pointer to a string containing file type.
  553. --
  554.  
  555. Listing 1 
  556.  
  557. The comments in a .CSC file can be either preceeded by a # or by --.  When you 
  558. use the latter, the comment is automatically included in the .C file that will 
  559. be generated by the SOM compiler.  If you look at the example, you can see it's 
  560. in fact quite simple (most of it consists of comments).  The sections in this 
  561. file are as follows: 
  562.  
  563. include 
  564.           You should include the definitions for the parent class here (.SC 
  565.           file). In our example, we need the definitions of the WPDataFile 
  566.           class, which are in the file wpdataf.sc. 
  567.  
  568. class 
  569.           Information about the new class comes here.  The most important item 
  570.           is the class name.  The external stem is sometimes used by SOM to 
  571.           generate filenames, but is not very important.  The prefixes will be 
  572.           used to create unique names for all methods, e.g. wpclsQueryTitle 
  573.           becomes dfdM_wpclsQueryTitle with the prefix in our .CSC file.  As a 
  574.           shortcut, you can use _wpclsQueryTitle in the code to make it more 
  575.           readable.  The version numbers will help determine if your DLL file 
  576.           is recent enough to provide the intended services. 
  577.  
  578.            Tip 
  579.  
  580. parent 
  581.           Here you specify from what class you want to derive your new class, 
  582.           WPDataFile in our example. 
  583.  
  584. release order 
  585.           This tells the compiler in what order it should generate the generic 
  586.           function code. 
  587.  
  588. passthru 
  589.           Your implementation will sometimes need specific header files to be 
  590.           included or things like that.  The place to put these is in the 
  591.           passthru:  C.ih section.  ih stands for implementation header, which 
  592.           is always included in the generated .C file. 
  593.  
  594.            Tip 
  595.  
  596. methods 
  597.           Here you indicate all new methods you want to add, as well as the 
  598.           methods you want to override.  Class methods are indicated by the 
  599.           word "class" at the end.  For each method you specify here, the SOM 
  600.           compiler will generate a code stub for you to alter. 
  601.  
  602. These are the sections you should become familiar with, since they're almost 
  603. always needed in order to define a new class (other sections are possible, but 
  604. we won't use them here).  It's a simple syntax, so you'll get used to it quite 
  605. rapidly. 
  606.  
  607. You probably have noticed that our class definition file specifies two methods 
  608. to be overridden.  Both are class methods, and thus act upon the entire class. 
  609. Let's look at what these methods do, and how we can add our own functionality. 
  610.  
  611. Step 1 
  612.  
  613. We will now compile our class definition file.  I've included a makefile you 
  614. can use for all your WPS programming (adapted from the makefile in the IBM 
  615. toolkit).  Remember:  install the samples and then type WPS 1 in your working 
  616. directory.  This will give you the makefile and the class definition file from 
  617. listing 1. 
  618.  
  619.  Tip 
  620.  
  621. Compile the class definition file by typing the following in the working 
  622. directory: 
  623.  
  624. NMAKE DATADEL.IH
  625.  
  626. This will start the SOM compiler and generate a lot of files.  One of these 
  627. files is DATADEL.C (this is by far the most interesting one).  The generated 
  628. code stubs in this file look like listing 2: 
  629.  
  630. SOM_Scope PSZ   SOMLINK dfdM_wpclsQueryTitle(M_MyDataFile *somSelf)
  631. {
  632.     /* M_MyDataFileData *somThis = M_MyDataFileGetData(somSelf); */
  633.     M_MyDataFileMethodDebug("M_MyDataFile","dfdM_wpclsQueryTitle");
  634.  
  635.     return (parent_wpclsQueryTitle(somSelf));
  636. }
  637.  
  638. Listing 2 
  639.  
  640. This may at first seem a little crowded, but you'll learn to filter the unusual 
  641. stuff out of it.  First of all, read the first line as 
  642.  
  643. PSZ dfdM_wpclsQueryTitle(M_MyDataFile *somSelf)
  644.  
  645. Now we have a function returning a PSZ (string) and accepting a pointer. The 
  646. name of the function is wpclsQueryTitle, and in order to have unique names for 
  647. your class, there's a dfdM prefixed to it.  This is the prefix you specified as 
  648. classprefix in the class definition file, since we're dealing with a class 
  649. method.  In the PM reference, you'll find all methods of each WPS class, and 
  650. whether it is a normal method or a class method.  For clarity, all class method 
  651. contain cls as part of their name.  So now you can see wpclsQueryTitle indeed 
  652. is a class method. I'll explain what this method actually does later on. 
  653.  
  654. The second line of the stub is commented out.  This code makes sure you can 
  655. access the class data of your object, but since you don't have any class data, 
  656. the SOM compiler has commented it out (in fact, you will get an error 
  657. otherwise).  Class data is data that applies to the class, so to all objects of 
  658. that class.  It can only be accessed by class methods. 
  659.  
  660. The third line uses the SOM system to identify this method for debugging 
  661. purposes.  Simply let this line be and it will be very happy. 
  662.  
  663. So the only remaining thing is the actual code of this method.  It is really 
  664. very simple: 
  665.  
  666.     return (parent_wpclsQueryTitle(somSelf));
  667.  
  668. You may already have guessed it:  this code calls the wpclsQueryTitle of the 
  669. parent class.  This means that this code returns the exact same title as the 
  670. WPDataFile class.  Prefixing parent_ in SOM always results in calling the 
  671. corresponding method of the parent class.  This should almost always be done, 
  672. since it allows the parent class to do its job too (most of the time, you only 
  673. want to change part of the functionality, and you can let the parent do the 
  674. rest of the work). 
  675.  
  676. The only thing remaining to be explained, is the somSelf pointer.  This is a 
  677. pointer SOM uses to know what object you're talking about. Remember:  all 
  678. instances of a class actually share the code of the methods.  The only 
  679. difference between the instances is the data.  So in order to tell what 
  680. particular instance a method should act upon, we pass it the somSelf pointer. 
  681. In languages like C++, this is done automatically, here we must do it 
  682. ourselves. 
  683.  
  684. With the gained knowledge, you can see that overriding the method and using the 
  685. code generated by the SOM compiler as it is, has the same effect as not 
  686. overriding the method at all.  After all, if you don't override it, the 
  687. parent's method gets called directly.  But overriding a method provides you 
  688. with a means to plug in your own code.  I hope you can now see what WPS 
  689. programming is all about:  taking an existing class, such as WPDataFile, and 
  690. selectively alter its behaviour.  This way, you end up with your own class, 
  691. behaving in a way exactly like the parent (by means of the inherited methods), 
  692. and differently in another way (by means of overriding some methods). 
  693.  
  694. Now let's start changing some code.  I haven't explained yet exactly what this 
  695. wpclsQueryTitle method does.  Well, it is used in WPS to query the title (read: 
  696. name) of our class.  The Workplace Shell calls this method every time it wants 
  697. to know our title.  This title will appear in the Templates folder, and will be 
  698. the default name for all instances of the class. The first thing you should do 
  699. when you create a new class in WPS is give that class its own title. 
  700. Otherwise, you end up with different templates all having the same name, making 
  701. it sometimes impossible to tell the difference between them.  Moreover, your 
  702. class will be identified by its title everywhere in the WPS, not only in the 
  703. Templates folder, as we will see.  For this reason, you'll need to always 
  704. override the wpclsQueryTitle method. 
  705.  
  706. Step 2 
  707.  
  708. We will call our new class "Datafile Deluxe".  We do this by changing the 
  709. return statement generated by the SOM compiler to: 
  710.  
  711.     return ("Datafile Deluxe");
  712.  
  713. At this point, we have something we can compile to a DLL: by simply typing 
  714.  
  715. NMAKE
  716.  
  717. This will build a DLL with the code for our new class (ignore the RC file for 
  718. now).  Now that we have the DLL, the next step is to register it.  We do this 
  719. by copying the DLL to a directory in our LIBPATH, and running the program 
  720. REG.CMD (you should find it in your working directory): 
  721.  
  722. reg MyDataFile datadel
  723.  
  724. The first parameter is the name of the class we want to register, the second 
  725. parameter is the name of our DLL (without extension). 
  726.  
  727.  Tip 
  728.  
  729. After a while, the class is registered.  When you open the Templates folder, 
  730. you can see the Datafile Deluxe template.  Drag it to create an instance of our 
  731. new class.  Notice that our title also appears in the "Create another" submenu. 
  732. Apart from the title, our object has exactly the same characteristics as 
  733. objects of the WPDataFile class. For example, it still has the type "Plain 
  734. Text" (see the settings notebook, under the tab "Type"). 
  735.  
  736. See how easy it is to make your own WPS objects?  Not counting the class 
  737. definition file, we have written exactly one line of code, and we have an 
  738. object that has a context menu, can be dragged, deleted, opened, edited, 
  739. copied, has a settings notebook, and so on.  Compare this to normal PM 
  740. programming! 
  741.  
  742. So far, our new class hasn't been of much use.  After all, it's nothing more 
  743. than a simple data file, even if its title says otherwise.  We do have a new 
  744. class, however, and this already has some advantages.  For example, you can 
  745. tell any WPS folder only to include objects of this class:  open its settings 
  746. notebook and select the Include tab.  Here you can see part of the WPS class 
  747. hierarchy, not with the actual class names like WPDataFile, MyDataFile and so 
  748. on, but with the class titles (this is another place where the class titles 
  749. appear).  You can easily see here that our class is derived from WPDataFile: 
  750. it appears indented under the Data File item.  To only include objects of our 
  751. class, deselect Object, and select Datafile Deluxe (click somewhere else, e.g. 
  752. in the Name field, to activate your last selection).  Now we have a folder that 
  753. only displays objects of our class. 
  754.  
  755. Perhaps more useful is the ability to find all objects of our class, wherever 
  756. they are.  To test this, drag a few templates to a variety of folders, then 
  757. select Find from the desktop context menu.  Here again we have part of the 
  758. class hierarchy (see why the class title is so important?).  Again deselect 
  759. Object and select Datafile Deluxe.  Don't forget to search all subfolders.  The 
  760. system will now find all Datafile Deluxe objects for you, on the desktop and in 
  761. all subfolders. 
  762.  
  763. When you don't need the class anymore, you can deregister it.  You do this by 
  764. deleting all instances of the class and typing: 
  765.  
  766. dereg MyDataFile
  767.  
  768.  Tip 
  769.  
  770. You can use the WP Class List from the IBM toolkit to show the class hierarchy 
  771. with the actual class names (see figure 1).  This is also a handy tool to 
  772. register and deregister classes, and to create instances of a class. Figure 1 
  773. shows our class MyDataFile, derived from WPDataFile, which is in turn derived 
  774. from WPFileSystem, and so on. 
  775.  
  776. Figure 1 
  777.  
  778. Step 3 
  779.  
  780. Let's make our class more useful by giving it its own type.  We do this by 
  781. overriding the wpclsQueryInstanceType method, just like we did with 
  782. wpclsQueryTitle.  We will return our title as the file type: 
  783.  
  784.     return (_wpclsQueryTitle(somSelf));
  785.  
  786. Using NMAKE again produces our DLL.  After registering it (remember to copy it 
  787. to your LIBPATH), make an instance of our class (drag the template).  When you 
  788. open the settings notebook, you can see it indeed has the type "Datafile 
  789. Deluxe".  We have used the same string for the class title and the instance 
  790. type.  This is to be preferred in general, since doing otherwise will only 
  791. confuse the user.  There's an exception to this: for some types, for example 
  792. Icon, it is convenient to add the corresponding extension, for example .ICO, to 
  793. the title.  This convention is used in the standard WPS classes. 
  794.  
  795. So what's the impact of our introducing a new type on the WPS?  Well, we now 
  796. have an easy and unambiguous way of associating our data file with programs. 
  797. To see this, make a new Program object (you know:  drag the Program template), 
  798. and provide a program name (for example, EPM.EXE).  Then select the Association 
  799. tab.  Under Available types, look who's there!  You can select Datafile Deluxe 
  800. and put it under Current types, associating objects of our class with the 
  801. program. 
  802.  
  803. Having objects of a distinct type can be advantageous when you have programs 
  804. that generate their own datafiles.  You can associate your datafiles with your 
  805. program automatically if you use objects having a type of their own as 
  806. datafiles (just like all objects of class MyDataFile), and add the ASSOCTABLE 
  807. resource to your program.  The first string in this resource is the type you 
  808. want to associate your program with, Datafile Deluxe in our case (see the PM 
  809. Reference for more info). 
  810.  
  811. If your program supports drag and drop, using a distinct type makes it very 
  812. easy to recognize your own datafiles:  the DRAGITEM structure for the item 
  813. dropped on your program contains the hstrType string.  This actually contains 
  814. the type name of the object dropped on it.  If you would drop an object of our 
  815. MyDataFile class, this string would be "Datafile Deluxe".  So the only thing 
  816. you have to do if you want to accept your own datafiles, is using 
  817. DrgVerifyTrueType with the name of the type you want to accept. 
  818.  
  819. In summary, using a distinct type makes it easy to recognize your own datafiles 
  820. when they are dropped on your program, and allows users to simply double click 
  821. a datafile, automatically opening your program.  This is all unambiguous, 
  822. unlike working with extensions:  it's not because a file has the extension .DOT 
  823. that it is one of your datafiles!  But if it has type Datafile Deluxe, you're 
  824. pretty sure it indeed is one of your files. 
  825.  
  826. Another View of Our Object. 
  827.  
  828. Up till now, we have only looked at the object side of our datafile. However, 
  829. all objects of class WPDataFile, or derived from that class, actually represent 
  830. real files, whereas objects of class WPFolder or a derived class represent real 
  831. directories.  In general, objects of class WPFileSystem represent "things" in a 
  832. file system, that is:  files or directories in the FAT or HPFS filesystems (it 
  833. would be nice if the filesystem could also contain other objects, so that we 
  834. could see our program objects in a directory listing, for example). 
  835.  
  836. Since our class MyDataFile is derived from WPDataFile, it actually represents a 
  837. file.  When you create an instance of the class, you actually create a new file 
  838. (with zero size for now; later we'll see how to add data).  So how does the WPS 
  839. know this file is actually an object of class MyDataFile?  The link between the 
  840. file and the WPS object representing the file, is in the extended attributes of 
  841. the file.  There is an attribute called .CLASSINFO, where the class of the 
  842. object is stored (among other things).  This way, the WPS knows what methods it 
  843. has to call in what DLL when the user manipulates the file. 
  844.  
  845. When we give our object a new type by overriding the wpclsQueryInstanceType 
  846. method, this information is also stored in an extended attribute (.TYPE). 
  847.  
  848. If the files are copied or moved, OS/2 preserves the extended attributes, so 
  849. the file keeps its object characteristics.  The only problem is when you copy 
  850. the file in plain DOS (not a DOS box).  DOS knows absolutely nothing about 
  851. EA's, and will only copy or move the contents of the file, not the other 
  852. features.  This results in lost extended attributes, in addition to demoting 
  853. the object to a simple file. 
  854.  
  855. Summarizing: all information about the object is stored in EA's.  To put it 
  856. another way (more intimidating):  objects of class WPFileSystem or a derived 
  857. class are stored on disk and achieve persistence through extended attributes 
  858. (impress your friends with this one). 
  859.  
  860. Knowing that, since our class is derived from WPDataFile, objects of the class 
  861. indeed are datafiles, you know everything you need to make programs using our 
  862. new objects.  As far as your program is concerned, it is working with files 
  863. (having a few special extended attributes).  Your program can open, read, 
  864. write, close the file, just like any other file.  The fact that those files are 
  865. WPS objects (because of the EA's) accounts for the WPS integration of your 
  866. datafiles.  When your program creates a new file, it has to make sure the file 
  867. contains the correct EA's. The easiest way to do this is by using 
  868. WinCreateObject.  This function creates an instance of the class you specify. 
  869. This automatically creates the file and the correct EA's. 
  870.  
  871. Step 4 
  872.  
  873. You've probably wondered what the RC file is doing.  Well, until now, nothing 
  874. at all!  We'll use it now to demonstrate how to load resources from the class 
  875. DLL.  We need the module handle of the DLL for this, so we will first create a 
  876. new method called clsQueryModuleHandle.  This method will return the handle of 
  877. our DLL.  We store the handle in the variable hmod, so the next time anyone 
  878. calls this method, we can simply return this variable. 
  879.  
  880. This is the right time to discuss class data.  Remember an object contains 
  881. methods and data.  This data is called instance data, since it is unique for 
  882. each instance.  In SOM, you can also define class data, for things that all 
  883. instances of the class have in common.  The module handle of the DLL would seem 
  884. to be an ideal candidate for storing in class data:  it is a value all 
  885. instances of the class share.  Well, conceptually this is true, but alas there 
  886. is a little problem.  Class data can only be accessed by class methods, not  by 
  887. normal (instance) methods.  Since we will want to access the module handle from 
  888. normal methods later on, we don't store it in class data.  Instead, we use a 
  889. file scope variable in the file DATADEL.C (hmod). 
  890.  
  891. The class title, however, can be stored in class data.  There are two things we 
  892. should do to make this work:  we need to declare the class data in our class 
  893. definition file, and we must override the wpclsInitData method.  This method is 
  894. called to initialize class data, so it is the perfect method for reading our 
  895. title from the resources and storing in in class data. 
  896.  
  897. The complete class definition file at this point is as in listing 3 (the new 
  898. items are in red).  It should be fairly obvious what's going on. 
  899.  
  900. #******************************************************************************
  901. #   Include the class definition file for the parent class
  902. #******************************************************************************
  903.  
  904. include <wpdataf.sc>
  905.  
  906. #******************************************************************************
  907. #   Define the new class
  908. #******************************************************************************
  909.  
  910. class: MyDataFile,
  911.        external stem   = dfd,
  912.        local,
  913.        external prefix = dfd_,
  914.        classprefix     = dfdM_,
  915.        major version   = 1,
  916.        minor version   = 1;
  917.  
  918. --
  919. -- CLASS: MyDataFile
  920. --
  921. -- CLASS HIERARCHY:
  922. --
  923. --     SOMObject
  924. --       ΓööΓöÇΓöÇ WPObject
  925. --             ΓööΓöÇΓöÇ WPFileSystem
  926. --                   ΓööΓöÇΓöÇ WPDataFile
  927. --                         ΓööΓöÇΓöÇ  MyDataFile
  928. --
  929.  
  930. #******************************************************************************
  931. #   Specify the parent class
  932. #******************************************************************************
  933.  
  934. parent: WPDataFile;
  935.  
  936. release order:
  937.     clsQueryModuleHandle,
  938.     wpclsQueryTitle,
  939.     wpclsQueryInstanceType,
  940.     wpclsInitData;
  941.  
  942. passthru: C.ih;
  943.  
  944. #define INCL_WIN
  945. #define INCL_DOS
  946. #include <os2.h>
  947. #include "datares.h"
  948. #include <string.h>
  949. endpassthru;
  950.  
  951. data:
  952.  
  953. UCHAR szTitle[CCHMAXPATH], class;
  954.  
  955. #******************************************************************************
  956. #   Specify methods being overridden
  957. #******************************************************************************
  958.  
  959. methods:
  960.  
  961. #******************************************************************************
  962. #   Specify class methods being overridden
  963. #******************************************************************************
  964.  
  965. override wpclsInitData, class;
  966. --
  967. -- METHOD: wpclsInitData
  968. --
  969. -- DESCRIPTION:
  970. --
  971. --   Initalize the class data
  972. --
  973.  
  974. override wpclsQueryTitle, class;
  975. --
  976. -- METHOD: wpclsQueryTitle                                ( ) PRIVATE
  977. --                                                        (X) PUBLIC
  978. -- DESCRIPTION:
  979. --
  980. --   Returns the title of our class.
  981. --
  982.  
  983. override wpclsQueryInstanceType, class;
  984. --
  985. -- METHOD: wpclsQueryInstanceType                         ( ) PRIVATE
  986. --                                                        (X) PUBLIC
  987. -- DESCRIPTION:
  988. --
  989. --    The wpclsQueryInstanceType method is called to allow the class
  990. --    object to specify the file type for instances of its
  991. --    class.
  992. --
  993. -- RETURNS:
  994. --
  995. --    A pointer to a string containing file type.
  996. --
  997.  
  998.  
  999. #******************************************************************************
  1000. #   Define class methods
  1001. #******************************************************************************
  1002.  
  1003. HMODULE  clsQueryModuleHandle (), class;
  1004. --
  1005. -- METHOD: clsQueryModuleHandle                           ( ) PRIVATE
  1006. --                                                        (X) PUBLIC
  1007. -- DESCRIPTION
  1008. --
  1009. --   This method returns the module handle of this class.  If this is the
  1010. --   first invocation, DosQueryModuleHandle is called to save the handle
  1011. --   for future invocations.
  1012. --
  1013. -- RETURN:
  1014. --
  1015. --   0              Unsuccessful
  1016. --   non-zero       module handle
  1017. --
  1018. Listing 3 
  1019.  
  1020. When you use the SOM compiler (type NMAKE DATADEL.IH), it will append the new 
  1021. methods to DATADEL.C (you have to move the methods manually if you don't want 
  1022. them at the end of your source file).  Looking at the generated code for 
  1023. clsQueryModuleHandle, we can see that adding a method is not different from 
  1024. overriding one, except we can't call the parent, since it doesn't have our 
  1025. method.  Notice that the first line in each added method is now uncommented, 
  1026. since we have class data.  This line is still commented out in the older 
  1027. methods, since they were generated when there was no class data, and the SOM 
  1028. compiler doesn't change any code already in the source file. 
  1029.  
  1030. Step 5 
  1031.  
  1032. Listing 4 shows the code for our clsQueryModuleHandle method. The only really 
  1033. new item here is the call to _somLocateClassFile. This is a method of 
  1034. SOMClassMgrObject, returning the pathname of the DLL that contains the code for 
  1035. the class whose ID is specified as the second parameter (whew).  We obtain this 
  1036. ID with a call to SOM_IdFromString, giving it the name of our class.  After we 
  1037. obtain the full pathname of our DLL, we simply query its handle. 
  1038.  
  1039. SOM_Scope HMODULE   SOMLINK dfdM_clsQueryModuleHandle(M_MyDataFile *somSelf)
  1040. {
  1041.     APIRET rc;
  1042.  
  1043.     M_MyDataFileData *somThis = M_MyDataFileGetData(somSelf);
  1044.     M_MyDataFileMethodDebug("M_MyDataFile","dfdM_clsQueryModuleHandle");
  1045.  
  1046.     if (hmod == NULLHANDLE) {
  1047.         zString zsPathName;
  1048.         zsPathName = _somLocateClassFile(SOMClassMgrObject,
  1049.              SOM_IdFromString("MyDataFile"),
  1050.              MyDataFile_MajorVersion, MyDataFile_MinorVersion);
  1051.         rc = DosQueryModuleHandle(zsPathName, &hmod);
  1052.         if (rc) {
  1053.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1054.                 (PSZ) "MyDataFile::dfdM_clsQueryModuleHandle",
  1055.                 (PSZ) "Cannot load module handle",
  1056.                 20,
  1057.                 MB_OK | MB_INFORMATION | MB_MOVEABLE);
  1058.             return (HMODULE) 0;
  1059.             }
  1060.         }
  1061.     return hmod;
  1062. }
  1063.  
  1064. Listing 4 
  1065.  
  1066. Now that we have a way of obtaining the module handle of our DLL, implementing 
  1067. the loading of our title is really simple (see listing 5). 
  1068.  
  1069. SOM_Scope void   SOMLINK dfdM_wpclsInitData(M_MyDataFile *somSelf)
  1070. {
  1071.     M_MyDataFileData *somThis = M_MyDataFileGetData(somSelf);
  1072.     M_MyDataFileMethodDebug("M_MyDataFile","dfdM_wpclsInitData");
  1073.  
  1074.     if (!WinLoadString(WinQueryAnchorBlock(HWND_DESKTOP),
  1075.             _clsQueryModuleHandle(somSelf),
  1076.             ID_TITLE, sizeof(_szTitle), _szTitle))
  1077.         strcpy(_szTitle, parent_wpclsQueryTitle(somSelf));
  1078.  
  1079.     parent_wpclsInitData(somSelf);
  1080. }
  1081.  
  1082. Listing 5 
  1083.  
  1084. Notice in listing 5 how we access our class data:  The first line of the code 
  1085. should not be commented out, and we use an underscore to access the title.  In 
  1086. fact, _szTitle really is a shortcut, and it is defined as #define _szTitle 
  1087. (somThis->szTitle) in datadel.ih (the SOM compiler has done this for us).  This 
  1088. explains why the first line is needed and may help you interpret compiler 
  1089. errors when you later forget to uncomment that line in other methods. 
  1090. Prefixing an underscore is not only used to access the data, but also to access 
  1091. the methods, as you can see in the call to clsQueryModuleHandle. 
  1092.  
  1093. Listing 5 also illustrates how you obtain an anchor block for your WPS code: 
  1094. simply obtain the one from the desktop.  This makes sense, since all WPS code 
  1095. actually runs in the PMSHELL.EXE process. 
  1096.  
  1097. The only remaining thing to do is modifying the wpclsQueryTitle method, since 
  1098. it should return the title we loaded into szTitle: 
  1099.  
  1100. SOM_Scope PSZ   SOMLINK dfdM_wpclsQueryTitle(M_MyDataFile *somSelf)
  1101. {
  1102.     M_MyDataFileData *somThis = M_MyDataFileGetData(somSelf);
  1103.     M_MyDataFileMethodDebug("M_MyDataFile","dfdM_wpclsQueryTitle");
  1104.  
  1105.     return (_szTitle);
  1106. }
  1107.  
  1108. Remember to uncomment the first line!  The SOM compiler doesn't change the code 
  1109. we already have, so we have to do it manually.  Later, we will use other 
  1110. resources from the DLL, so our clsQueryModuleHandle method will again be put to 
  1111. good use. 
  1112.  
  1113.  Tip 
  1114.  
  1115. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1116.  
  1117.  
  1118. ΓòÉΓòÉΓòÉ 2.7. Summary ΓòÉΓòÉΓòÉ
  1119.  
  1120. Summary 
  1121.  
  1122. In this article, I've introduced WPS programming by first explaining concepts 
  1123. from object oriented programming and SOM programming.  This allows you to 
  1124. understand what's going on.  After that, we have made our first WPS class, 
  1125. edited it, compiled it, registered it and used it.  This first introduction 
  1126. should give you a fairly good idea of what a WPS class really is, and what WPS 
  1127. programming is all about. 
  1128.  
  1129. The class we've made so far is not very special.  In fact, some of its features 
  1130. can be achieved with normal OS/2 programming (for example, the .TYPE EA).  But 
  1131. it already shows some WPS integration, for example the ability to locate all 
  1132. objects of the class.  This minimal form of integration may be all that is 
  1133. needed, and it may be easier to create a WPS object than to manually write the 
  1134. .TYPE EA to your datafiles. 
  1135.  
  1136. Next time, we will improve the WPS integration, by discussing more methods and 
  1137. showing what the effect is of overriding them. 
  1138.  
  1139. If you have any comments, corrections, additions, or whatever, feel free to 
  1140. contact me (see elsewhere in this issue for information on how to reach me). 
  1141.  
  1142. WPS Programming the Easy Way (Part 1) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1143.  
  1144.  
  1145. ΓòÉΓòÉΓòÉ 3. The Design and Implementation of VIOWIN - Part 1 ΓòÉΓòÉΓòÉ
  1146.  
  1147.  
  1148. ΓòÉΓòÉΓòÉ 3.1. Introduction ΓòÉΓòÉΓòÉ
  1149.  
  1150. VIOWIN (The Fullscreen PM Subset) - Part 1 
  1151.  
  1152. Written by Larry Salomon, Jr. 
  1153.  
  1154. Introduction 
  1155.  
  1156. For my job, I once had to write an application that ran only when OS/2 booted 
  1157. from the floppy diskettes.  Because I had no access to the functionality PM 
  1158. provides, I resorted to a line-oriented interface, where messages were 
  1159. displayed on the screen and scrolled up when necessary.  It was a good 
  1160. interface, I thought; it was fully NLS enabled and had intelligent defaults so 
  1161. the user basically only had to type in the name of the application. 
  1162. Unfortunately, the Quality Assurance team didn't concur with my opinion.  "We 
  1163. want a nice interface!" one exclaimed.  "Yeah, one with different windows and 
  1164. such!" another shouted. 
  1165.  
  1166. I was backed into a corner that I could only get out of one way. 
  1167.  
  1168. This series will describe the design and implementation of VIOWIN, a library 
  1169. that implements a subset of the Win APIs provided by PM for fullscreen 
  1170. sessions.  The reasoning behind writing this series is that it provided me and 
  1171. will hopefully provide you with some unique insights into how a windowing 
  1172. system is developed; and since it is based on PM, your familiarity with the 
  1173. already defined interface will increase your capability to fully understand 
  1174. what is being described. 
  1175.  
  1176. Obviously, this series assumes you have PM application development experience, 
  1177. but it isn't required. 
  1178.  
  1179. The Design and Implementation of VIOWIN (Part 1) - EDM/2 - Sept 1994 - Volume 
  1180. 2, Issue 8 
  1181.  
  1182.  
  1183. ΓòÉΓòÉΓòÉ 3.2. Forethought ΓòÉΓòÉΓòÉ
  1184.  
  1185. Forethought 
  1186.  
  1187. Before I could begin coding, I had to decide where to draw the line.  I 
  1188. couldn't reasonably expect to implement the entire API set, but I didn't want 
  1189. to limit the capabilities of the library unnecessarily.  I must apologize 
  1190. because I did not take any notes when developing this, so the "list" of 
  1191. limitations is probably incomplete.  Most of the limitations were chosen to 
  1192. save time coding the library; after all, I did have an application to write 
  1193. using this library and only two weeks total to complete all of it! 
  1194.  
  1195. The design points are listed below.  First are the "have not's": 
  1196.  
  1197.  1. No multiprocess or multithread application support. 
  1198.  2. No overlapping window support. 
  1199.  3. No movable window support. 
  1200.  4. No mouse support. 
  1201.  5. No profile support. 
  1202.  6. No class styles. 
  1203.  
  1204. ...followed by the "have's": 
  1205.  
  1206.  1. At least 3 implemented window classes - buttons, entryfields, and statics. 
  1207.  2. Input focus support. 
  1208.  3. Timer support. 
  1209.  4. Cursor support. 
  1210.  5. Limited resource support. 
  1211.  6. Window styles. 
  1212.  
  1213. For the window classes, not all styles were implemented (e.g. text fields and 
  1214. group boxes were written, but not rectangles or bitmaps), nor were all messages 
  1215. in each class implemented. 
  1216.  
  1217. Cursor support is limited, due to the nature of the system.  Since we are 
  1218. running in a character-mode fullscreen session, we cannot have dotted boxes 
  1219. around the text of a button, for example. 
  1220.  
  1221. The only resource support that made it into the current version is for the 
  1222. STRINGTABLE.  I would have liked to have added ACCELTABLE and DIALOGTEMPLATE 
  1223. support, but didn't have the time to do it. 
  1224.  
  1225. Additionally, I wanted to have as much similarity to the Win APIs as I could 
  1226. possibly design and code.  Thus, there is an anchor block and message queue 
  1227. (although they are hidden), message loops, window procedures, etc.  The 
  1228. advantages here are that 1) I didn't have to spend additional time designing 
  1229. the paradigm on which my design would be based and 2) users of the library 
  1230. would already be familiar with the ideas, providing they had PM application 
  1231. development experience. 
  1232.  
  1233. There are also some things not mentioned above that were included.  I avoided 
  1234. the issue of output completely by choosing to leave out the Gpi APIs (for 
  1235. obvious reasons), but the static control, for example, had to be able to write 
  1236. its text out.  Thus, the vwDrawText() function was added.  Also, for the 
  1237. limited clipping provided in functions such as vwDrawText(), rectangle support 
  1238. was added.  Also, certain system values were added, as well as the 
  1239. vwQuerySysValue() and vwSetSysValue() functions, and vwAlarm() was needed for 
  1240. audible feedback. 
  1241.  
  1242. The base library consists of the files listed below, followed by a list of the 
  1243. files comprising the window classes, which were kept separate to encourage good 
  1244. programming. 
  1245.  
  1246. VIOWIN.C            Main module, containing miscellaneous functions. 
  1247. VWCLASS.C           Window class support. 
  1248. VWCURS.C            Cursor support. 
  1249. VWDRAW.C            Drawing support. 
  1250. VWMSG.C             Message support. 
  1251. VWRECT.C            Rectangle support. 
  1252. VWRES.C             Resource support. 
  1253. VWTIMER.C           Timer support. 
  1254. VWUTIL.C            Utility functions needed by the library. 
  1255. VWWND.C             Window functions. 
  1256.  
  1257. CLASSES.C           Main module, which registers the window classes. 
  1258. CLBT.C              Button class. 
  1259. CLEF.C              Entryfield class. 
  1260. CLLB.C              Listbox class, never implemented. 
  1261. CLSB.C              Scrollbar class, never implemented. 
  1262. CLST.C              Static class. 
  1263.  
  1264. It should be noted here that exploitation of the Common/2 library was used 
  1265. whenever possible (especially for the linked-list routines). If you are not 
  1266. familiar with this library, it is recommended that you get the latest version 
  1267. (currently 1.6.0) from ftp.cdrom.com. 
  1268.  
  1269. Throughout this series, I will describe each module in depth along with any 
  1270. notes that pop into my head.  I realize that this will detract from the 
  1271. readability of the articles, but - again - I did not originally intend for this 
  1272. series to even exist or for the library to grow to what it has become. 
  1273.  
  1274. The Design and Implementation of VIOWIN (Part 1) - EDM/2 - Sept 1994 - Volume 
  1275. 2, Issue 8 
  1276.  
  1277.  
  1278. ΓòÉΓòÉΓòÉ 3.3. Data Structures ΓòÉΓòÉΓòÉ
  1279.  
  1280. Data Structures 
  1281.  
  1282. This month, we will only look at the four predominant data structures involved. 
  1283. Additional data structures will be discussed as the code involving them is 
  1284. described.  Next month, we will delve into the code proper, and the code will 
  1285. be provided with the next article so that you can do your own "armchair 
  1286. detecting."  (This also gives me more time to insure that the code is 
  1287. well-commented, etc.  <grin>) 
  1288.  
  1289. Note! 
  1290.  
  1291. You will notice that vw is the prevailing prefix used throughout the code. 
  1292. This applies to function names, data types, constants, etc.  A side effect of 
  1293. this is that, since there is HVWWND instead of HWND (et al.), many structures 
  1294. had to be redefined to specify the new data type instead of the original 
  1295. version.  This is tedious at best, and is avoided whenever possible. 
  1296.  
  1297. The Anchor Block Structure 
  1298.  
  1299. typedef struct _VWAB {
  1300.    ULONG ulSzStruct;
  1301.    ULONG ulStatus;
  1302.    HCMMEM hcmWork;
  1303.    HCLLIST hclClasses;
  1304.    HCLLIST hclWindows;
  1305.    HCLLIST hclTimers;
  1306.    HMODULE hmClasses;
  1307.    BOOL bIsSendMsg;
  1308.    struct _VWWND *hwndFocus;
  1309.    struct _VWCURSORINFO *pciCursor;
  1310.    USHORT usCursorState;
  1311.    LONG alSysValues[VWSV_CSYSVALUES];
  1312. } VWAB, *HVWAB;
  1313.  
  1314. The anchor block data structure, shown above, is used to maintain general 
  1315. housekeeping data on the state of the process as a whole (vs per thread in PM). 
  1316. The fields are described below: 
  1317.  
  1318. ulSzStruct          (ULONG) - size of the structure, because I am afraid that 
  1319.                     there is still some thunking going on in the kernel. 
  1320. ulStatus            (ULONG) - status of the library (VW_HABST_* constant). 
  1321. hcmWork             (HCMMEM) - heap manager instance for general purpose 
  1322.                     consumption. 
  1323. hclClasses          (HCLLIST) - linked-list of VWCLASSINFO structures defining 
  1324.                     each registered window class. 
  1325. hclWindows          (HCLLIST) - linked-list of VWWND structures defining the 
  1326.                     existing windows. 
  1327. hclTimers           (HCLLIST) - linked-list of VWTIMERINFO structures defining 
  1328.                     the timers in use. 
  1329. hmClasses           (HMODULE) - handle of the DLL containing the predefined 
  1330.                     classes. 
  1331. bIsSendMsg          (BOOL) - flag set when vwSendMsg() is called. 
  1332. hwndFocus           (HVWWND) - handle of the window with the input focus. 
  1333. pciCursor           (HVWCURSORINFO) - describes the cursor information.  I 
  1334.                     cannot remember exactly why this is a pointer and not the 
  1335.                     structure itself. 
  1336. usCursorState       (USHORT) - a VWCS_* constant, used internally. 
  1337. alSysValues         (LONG) - an array of the system values. 
  1338.  
  1339. The Class Information Structure 
  1340.  
  1341. typedef struct _VWCLASSINFO {
  1342.    CHAR achName[256];
  1343.    PFNVWWP pfnWndProc;
  1344. } VWCLASSINFO, *PVWCLASSINFO;
  1345.  
  1346. achName is the name of the class as registered and pfnWndProc is a pointer to 
  1347. the associated window procedure. 
  1348.  
  1349. The Window Structure 
  1350.  
  1351. typedef struct _VWWND {
  1352.    ULONG ulSzStruct;
  1353.    struct _VWCLASSINFO *pciClass;
  1354.    USHORT usId;
  1355.    ULONG ulStyle;
  1356.    VWSWP swpSwp;
  1357.    LONG lForeClr;
  1358.    LONG lBackClr;
  1359.    PCHAR pchText;
  1360.    PVOID pvData[2];
  1361. } VWWND, *HVWWND;
  1362.  
  1363. ulSzStruct          (ULONG) - again, because I am paranoid. 
  1364. pciClass            (PVWCLASSINFO) - pointer to the VWCLASSINFO structure so to 
  1365.                     optimize the vwSendMsg() function. 
  1366. usId                (USHORT) - identifier of the window.  Like PM, an id of -1 
  1367.                     means that you don't care about the identifier and a 
  1368.                     "duplicate id" check is not made. 
  1369. ulStyle             (ULONG) - window style. 
  1370. swpSwp              (VWSWP) - size and position of the window. 
  1371. lForeClr            (LONG) - foreground color.  See below. 
  1372. lBackClr            (LONG) - background color.  See below. 
  1373. pchText             (PCHAR) - window text. 
  1374. pvData              (PVOID) - array (yes, I too just noticed the incorrect 
  1375.                     field name according to Hungarian notation) of window data. 
  1376.                     The window classes use index 1 and the application can use 
  1377.                     0. 
  1378.  
  1379. Note! 
  1380.  
  1381. The colors are a necessary deviation from PM since there is no Gpi support. 
  1382. Instead of having each window class allocate and manage window words, I decided 
  1383. to do it instead, since it would be a frequently used piece of information. 
  1384.  
  1385. Message Queue Structure 
  1386.  
  1387. typedef struct _VWMQ {
  1388.    ULONG ulSzStruct;
  1389.    VWQMSG aqmMsgs[VW_SIZEQUEUE];
  1390.    ULONG ulHead;
  1391.    ULONG ulTail;
  1392. } VWMQ, *HVWMQ;
  1393.  
  1394. ulSzStruct          (ULONG) - again, because I am paranoid. 
  1395. aqmMsgs             (VWQMSG) - array of VWQMSG structures containing the 
  1396.                     contents of the queue. 
  1397. ulHead              (ULONG) - index of the front of the queue. 
  1398. ulTail              (ULONG) - index of the rear of the queue. 
  1399.  
  1400. Note! 
  1401.  
  1402. This is a circular queue. 
  1403.  
  1404. The Design and Implementation of VIOWIN (Part 1) - EDM/2 - Sept 1994 - Volume 
  1405. 2, Issue 8 
  1406.  
  1407.  
  1408. ΓòÉΓòÉΓòÉ 3.4. Next Month ΓòÉΓòÉΓòÉ
  1409.  
  1410. Next Month 
  1411.  
  1412. That's it for this month.  I hope I have whet your appetite with this 
  1413. installment.  Next month, we will begin looking at the primary modules in the 
  1414. library, which will be followed in subsequent month's by the other, 
  1415. not-as-important modules, and finally by the window classes. 
  1416.  
  1417. Any comments are most definately welcome to my email address.  See you next 
  1418. month! 
  1419.  
  1420. The Design and Implementation of VIOWIN (Part 1) - EDM/2 - Sept 1994 - Volume 
  1421. 2, Issue 8 
  1422.  
  1423.  
  1424. ΓòÉΓòÉΓòÉ 4. Sprites and Animation - Reprise ΓòÉΓòÉΓòÉ
  1425.  
  1426.  
  1427. ΓòÉΓòÉΓòÉ 4.1. Introduction ΓòÉΓòÉΓòÉ
  1428.  
  1429. Sprites and Animation - Reprise 
  1430.  
  1431. Written by Larry Salomon, Jr. 
  1432.  
  1433. Introduction 
  1434.  
  1435. And when you had thought that this topic had been exhaustively treated, here it 
  1436. comes again.  This final article of the series will discuss the necessary 
  1437. changes to implement z-ordering within the sprite library; these changes will 
  1438. be discussed using the Common/2 library.  Have no fear, however; as promised, 
  1439. the source for the module has been included with this article. 
  1440.  
  1441. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1442.  
  1443.  
  1444. ΓòÉΓòÉΓòÉ 4.2. Voodoo Chili (Slight Return) ΓòÉΓòÉΓòÉ
  1445.  
  1446. Voodoo Chili (Slight Return) 
  1447.  
  1448. (Yes, the misspelling was intended.) 
  1449.  
  1450. When you think of z-ordering, you think of layering.  The problem of designing 
  1451. and implementing z-ordering was approached with the latter term in mind, since 
  1452. it helps ease the transition from the abstract to the codable. Consider the 
  1453. algorithm for drawing a sprite, given the concept of sprite layering: 
  1454.  
  1455.  1. Draw the background 
  1456.  
  1457.  2. Draw all sprites below the sprite to be drawn (the current sprite), if and 
  1458.     only if they overlap the bounding rectangle of the current sprite. 
  1459.  
  1460.  3. Draw the current sprite. 
  1461.  
  1462.  4. Draw all sprites above the current sprite, if and only if they overlap the 
  1463.     bounding rectangle of the current sprite. 
  1464.  
  1465. Simple enough, eh?  Before you roll up your sleeves to code this yourself 
  1466. <grin>, consider the following: 
  1467.  
  1468.  1. How the sprites are to be drawn 
  1469.  2. Performance 
  1470.  
  1471. Drawing 
  1472.  
  1473. The first item can no longer use the method developed in the first part of this 
  1474. series (see EDM/2 - Volume 2, Issue 5), since that blatently overpaints the 
  1475. bounding rectangle of the current sprite with the corresponding section of the 
  1476. background, effectively wiping out the drawing of the underlying sprites noted 
  1477. in step 2 of the drawing algorithm.  Instead, we must draw each sprite sans 
  1478. background, in order to preserve the sprites below the current sprite.  To get 
  1479. the background, then, we draw it as a separate step. 
  1480.  
  1481. Of course, this requires modification to our drawing routines, as we will see 
  1482. shortly. 
  1483.  
  1484. Performance 
  1485.  
  1486. Then, there is the issue of performance.  Given the worst-case scenario, 
  1487. suppose all sprites are of the maximum size, and they all overlap the current 
  1488. sprite.  When we have to draw the current sprite, if we completely (that's the 
  1489. operative word) draw each of the overlapping sprites, our performance drops 
  1490. through the floor.  Instead, we should calculate which portion of each 
  1491. overlapping sprite is actually overlapping and draw only that. This requires 
  1492. more thought up front, but saves us much in the long run. 
  1493.  
  1494. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1495.  
  1496.  
  1497. ΓòÉΓòÉΓòÉ 4.3. Coding the Changes ΓòÉΓòÉΓòÉ
  1498.  
  1499. Coding the Changes 
  1500.  
  1501. Before any coding can take place, we must understand how z-ordering will be 
  1502. represented in the data structures.  The easiest way, in my opinion, is by 
  1503. changing the interpretation of the current data structures, i.e. use the array 
  1504. of sprites in the playground data structure (ahsSprites).  The handle in index 
  1505. 0 is the bottom-most sprite, while the handle in the highest index is the 
  1506. top-most sprite.  This is nice, because it enables us to use simple for-loops 
  1507. when enumerating the sprites by z-order. 
  1508.  
  1509. There are three routines which have changed to implement z-ordering: 
  1510. drawSpriteAt(), CmnSprDrawSprite(), and CmnSprSetSpritePosition().  We look at 
  1511. each of these in detail below. 
  1512.  
  1513. drawSpriteAt() 
  1514.  
  1515. This workhorse function of the drawing routines now accepts the rectangle of 
  1516. the sprite to be drawn, assuming a lower-left corner of (0,0). 
  1517.  
  1518. static BOOL drawSpriteAt(HPS hpsDraw,
  1519.                          HCSSPRITE hsSprite,
  1520.                          PSIZEL pszlPlay,
  1521.                          PPOINTL pptlSprite,
  1522.                          PRECTL prclSprite)
  1523. //-------------------------------------------------------------------------
  1524. // This function draws the sprite at the specified position.  It is assumed
  1525. // that the background has already been drawn into hpsDraw before this
  1526. // function is called.
  1527. //
  1528. // Input:  hpsDraw - handle of the presentation space to draw in
  1529. //         hsSprite - handle of the sprite to draw
  1530. //         pszlPlay - points to the size of hpsDraw.  If NULL, the size
  1531. //                    of the playground is used.
  1532. //         pptlSprite - points to the point specifying the position.  If
  1533. //                      NULL, the sprite's current position is used.
  1534. //         prclSprite - points to the rectangle within the sprite to draw,
  1535. //                      i.e. a rectangle bounded by (0,0)-(cx,cy) which
  1536. //                      is added to the sprite's position to determine
  1537. //                      how much of the sprite is to be drawn.  If NULL,
  1538. //                      the entire sprite is drawn.
  1539. // Returns:  TRUE if successful, FALSE otherwise
  1540. //-------------------------------------------------------------------------
  1541.  
  1542. The change in the code is actually quite simple.  Instead of assuming (0,0) as 
  1543. the lower left corner and (cx,cy) as the upper right corner, we use the values 
  1544. provided (if provided). 
  1545.  
  1546. {
  1547.    SIZEL szlUsePlay;
  1548.    POINTL ptlUseSpr;
  1549.    RECTL rclUseSpr;
  1550.    POINTL aptlPoints[4];
  1551.  
  1552.    if ((!hsSprite->hpgPlay->bUpdate) || (!hsSprite->bVisible)) {
  1553.       return TRUE;
  1554.    } /* endif */
  1555.  
  1556.    //----------------------------------------------------------------------
  1557.    // Initialize the local variables with either what was passed in or
  1558.    // the defaults as noted above in the function prologue
  1559.    //----------------------------------------------------------------------
  1560.    if (pszlPlay==NULL) {
  1561.       CmnSprQueryPlaygroundSize(hsSprite->hpgPlay,&szlUsePlay);
  1562.    } else {
  1563.       szlUsePlay=*pszlPlay;
  1564.    } /* endif */
  1565.  
  1566.    if (pptlSprite==NULL) {
  1567.       ptlUseSpr=hsSprite->ptlPos;
  1568.    } else {
  1569.       ptlUseSpr=*pptlSprite;
  1570.    } /* endif */
  1571.  
  1572.    if (prclSprite==NULL) {
  1573.       rclUseSpr.xLeft=0;
  1574.       rclUseSpr.yBottom=0;
  1575.       rclUseSpr.xRight=hsSprite->bmihMask.cx;
  1576.       rclUseSpr.yTop=hsSprite->bmihMask.cy;
  1577.    } else {
  1578.       rclUseSpr=*prclSprite;
  1579.    } /* endif */
  1580.  
  1581.    //----------------------------------------------------------------------
  1582.    // Convert the xRight/yTop pair to the size of the sprite
  1583.    //----------------------------------------------------------------------
  1584.    rclUseSpr.xRight-=rclUseSpr.xLeft;
  1585.    rclUseSpr.yTop-=rclUseSpr.yBottom;
  1586.  
  1587.    aptlPoints[0].x=ptlUseSpr.x+rclUseSpr.xLeft;
  1588.    aptlPoints[0].y=ptlUseSpr.y+rclUseSpr.yBottom;
  1589.    aptlPoints[1].x=aptlPoints[0].x+rclUseSpr.xRight-1;
  1590.    aptlPoints[1].y=aptlPoints[0].y+rclUseSpr.yTop-1;
  1591.    aptlPoints[2].x=rclUseSpr.xLeft;
  1592.    aptlPoints[2].y=rclUseSpr.yBottom;
  1593.    aptlPoints[3].x=aptlPoints[2].x+rclUseSpr.xRight;
  1594.    aptlPoints[3].y=aptlPoints[2].y+rclUseSpr.yTop;
  1595.  
  1596.    if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlUsePlay)) {
  1597.       //-------------------------------------------------------------------
  1598.       // Blit the mask and then the bitmap
  1599.       //-------------------------------------------------------------------
  1600.       GpiWCBitBlt(hpsDraw,
  1601.                   hsSprite->hbmMask,
  1602.                   4,
  1603.                   aptlPoints,
  1604.                   ROP_SRCAND,
  1605.                   BBO_IGNORE);
  1606.  
  1607.       GpiWCBitBlt(hpsDraw,
  1608.                   hsSprite->hbmBitmap,
  1609.                   4,
  1610.                   aptlPoints,
  1611.                   ROP_SRCPAINT,
  1612.                   BBO_IGNORE);
  1613.    } /* endif */
  1614.  
  1615.    return TRUE;
  1616. }
  1617.  
  1618. CmnSprDrawSprite() 
  1619.  
  1620. This code no longer is so concise, although it still is rather simple.  We do 
  1621. not simply call drawBackAt(), drawSpriteAt(), and return; now, we must loop 
  1622. through the sprites, drawing the intersecting rectangles of each.  Note:  the 
  1623. intersecting rectangle of the current sprite with itself is an identity 
  1624. function, so no special checking needs to be performed. 
  1625.  
  1626. SPRERROR EXPENTRY CmnSprDrawSprite(HPS hpsDraw,HCSSPRITE hsSprite)
  1627. //-------------------------------------------------------------------------
  1628. // This function draws a sprite
  1629. //
  1630. // Input:  hpsDraw - handle to the HPS to draw the sprite in
  1631. //         hsSprite - handle to the sprite
  1632. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1633. //-------------------------------------------------------------------------
  1634. {
  1635.    USHORT usSemAction;
  1636.    RECTL rclSprite;
  1637.    ULONG ulIndex;
  1638.    HCSSPRITE hsLayer;
  1639.    RECTL rclLayer;
  1640.    RECTL rclInter;
  1641.  
  1642.    if (queryHandle(hsSprite)!=QH_HCSSPRITE) {
  1643.       return SPR_ERR_BADHANDLE;
  1644.    } /* endif */
  1645.  
  1646.    usSemAction=accessSem((PCMNHANDLE)hsSprite,ACCSEM_SET);
  1647.  
  1648.    if (hsSprite->hpgPlay==NULL) {
  1649.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1650.       return SPR_ERR_HASNOPLAYGROUND;
  1651.    } /* endif */
  1652.  
  1653.    if ((!hsSprite->bVisible) || (!hsSprite->hpgPlay->bUpdate)) {
  1654.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1655.       return SPR_ERR_NOERROR;
  1656.    } /* endif */
  1657.  
  1658.    CmnSprQuerySpriteRect(hsSprite,&rclSprite);
  1659.  
  1660.    rclSprite.xRight++;
  1661.    rclSprite.yTop++;
  1662.  
  1663.    drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSprite);
  1664.  
  1665.    rclSprite.xRight--;
  1666.    rclSprite.yTop--;
  1667.  
  1668.    for (ulIndex=0; ulIndex<hsSprite->hpgPlay->ulNumMembers; ulIndex++) {
  1669.       hsLayer=hsSprite->hpgPlay->ahsSprites[ulIndex];
  1670.  
  1671.       CmnSprQuerySpriteRect(hsLayer,&rclLayer);
  1672.  
  1673.       WinIntersectRect(hsSprite->hpgPlay->habAnchor,
  1674.                        &rclInter,
  1675.                        &rclSprite,
  1676.                        &rclLayer);
  1677.  
  1678.       if (!WinIsRectEmpty(hsSprite->hpgPlay->habAnchor,&rclInter)) {
  1679.          rclInter.xLeft-=rclLayer.xLeft;
  1680.          rclInter.yBottom-=rclLayer.yBottom;
  1681.          rclInter.xRight-=rclLayer.xLeft;
  1682.          rclInter.yTop-=rclLayer.yBottom;
  1683.  
  1684.          rclInter.xRight++;
  1685.          rclInter.yTop++;
  1686.  
  1687.          drawSpriteAt(hpsDraw,hsLayer,NULL,NULL,&rclInter);
  1688.       } /* endif */
  1689.    } /* endfor */
  1690.  
  1691.    accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1692.    return SPR_ERR_NOERROR;
  1693. }
  1694.  
  1695. It should be obvious that the real work is done in the loop body.  If there is 
  1696. an intersection of bounding rectangles, a call to drawSpriteAt() is made. 
  1697.  
  1698. CmnSprSetSpritePosition() 
  1699.  
  1700. Of the three functions, this one has the most new code, but that isn't saying 
  1701. much, since the code up to this point hasn't been very difficult to understand. 
  1702. If you'll remember, this function takes one of two paths, depending on whether 
  1703. the new position overlaps the old.  Fortunately for us, in the original code, 
  1704. one of the paths called CmnSprDrawSprite(), so no change is needed in that 
  1705. case. 
  1706.  
  1707. SPRERROR EXPENTRY CmnSprSetSpritePosition(HPS hpsDraw,
  1708.                                           HCSSPRITE hsSprite,
  1709.                                           PPOINTL pptlNew)
  1710. //-------------------------------------------------------------------------
  1711. // This function changes the position of the sprite.  This function is
  1712. // optimized so that, if the rectangle bounding the sprite at the new
  1713. // position overlaps the old, only one "bit blit" to the specified HPS
  1714. // is done, eliminating flicker.
  1715. //
  1716. // Input:  hpsDraw - handle to the HPS to draw the sprite in once it is
  1717. //                   moved
  1718. //         hsSprite - handle to the sprite
  1719. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1720. //-------------------------------------------------------------------------
  1721. {
  1722.    USHORT usSemAction;
  1723.    SIZEL szlPlay;
  1724.    SIZEL szlWork;
  1725.    RECTL rclOld;
  1726.    RECTL rclNew;
  1727.    RECTL rclUnion;
  1728.    RECTL rclSrc;
  1729.    RECTL rclDest;
  1730.    ULONG ulIndex;
  1731.    HCSSPRITE hsLayer;
  1732.    RECTL rclLayer;
  1733.    RECTL rclInter;
  1734.    POINTL ptlWork;
  1735.    POINTL aptlPoints[4];
  1736.  
  1737.    if (queryHandle(hsSprite)!=QH_HCSSPRITE) {
  1738.       return SPR_ERR_BADHANDLE;
  1739.    } /* endif */
  1740.  
  1741.    usSemAction=accessSem((PCMNHANDLE)hsSprite,ACCSEM_SET);
  1742.  
  1743.    if (hsSprite->hpgPlay==NULL) {
  1744.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1745.       return SPR_ERR_HASNOPLAYGROUND;
  1746.    } /* endif */
  1747.  
  1748.    if ((hsSprite->bVisible) && (hsSprite->hpgPlay->bUpdate)) {
  1749.       szlWork.cx=MAX_SPRITE_CX*2;
  1750.       szlWork.cy=MAX_SPRITE_CY*2;
  1751.  
  1752.       CmnSprQueryPlaygroundSize(hsSprite->hpgPlay,&szlPlay);
  1753.  
  1754.       CmnSprQuerySpriteRect(hsSprite,&rclOld);
  1755.       hsSprite->ptlPos=*pptlNew;
  1756.       CmnSprQuerySpriteRect(hsSprite,&rclNew);
  1757.  
  1758.       WinUnionRect(hsSprite->habAnchor,&rclUnion,&rclOld,&rclNew);
  1759.  
  1760.       if ((rclUnion.xRight-rclUnion.xLeft>MAX_SPRITE_CX*2) ||
  1761.           (rclUnion.yTop-rclUnion.yBottom>MAX_SPRITE_CY*2)) {
  1762.  
  1763.          rclSrc.xLeft=rclOld.xLeft;
  1764.          rclSrc.yBottom=rclOld.yBottom;
  1765.          rclSrc.xRight=rclSrc.xLeft+hsSprite->bmihBitmap.cx;
  1766.          rclSrc.yTop=rclSrc.yBottom+hsSprite->bmihBitmap.cy;
  1767.  
  1768.          drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSrc);
  1769.  
  1770.          CmnSprDrawSprite(hpsDraw,hsSprite);
  1771.       } else {
  1772.          rclSrc=rclUnion;
  1773.          rclSrc.xRight++;
  1774.          rclSrc.yTop++;
  1775.  
  1776.          rclDest.xLeft=0;
  1777.          rclDest.yBottom=0;
  1778.          rclDest.xRight=rclUnion.xRight-rclUnion.xLeft;
  1779.          rclDest.yTop=rclUnion.yTop-rclUnion.yBottom;
  1780.  
  1781.          drawBackAt(hsSprite->hpgPlay->hpsWork,
  1782.                     hsSprite->hpgPlay,
  1783.                     &rclDest,
  1784.                     &szlWork,
  1785.                     &rclSrc);
  1786.  
  1787.          for (ulIndex=0; ulIndex<hsSprite->hpgPlay->ulNumMembers; ulIndex++) {
  1788.             hsLayer=hsSprite->hpgPlay->ahsSprites[ulIndex];
  1789.  
  1790.             CmnSprQuerySpriteRect(hsLayer,&rclLayer);
  1791.  
  1792.             WinIntersectRect(hsSprite->hpgPlay->habAnchor,
  1793.                              &rclInter,
  1794.                              &rclUnion,
  1795.                              &rclLayer);
  1796.  
  1797.             if (!WinIsRectEmpty(hsSprite->hpgPlay->habAnchor,&rclInter)) {
  1798.                ptlWork.x=hsLayer->ptlPos.x-rclUnion.xLeft;
  1799.                ptlWork.y=hsLayer->ptlPos.y-rclUnion.yBottom;
  1800.  
  1801.                rclInter.xLeft-=rclLayer.xLeft;
  1802.                rclInter.yBottom-=rclLayer.yBottom;
  1803.                rclInter.xRight-=rclLayer.xLeft;
  1804.                rclInter.yTop-=rclLayer.yBottom;
  1805.  
  1806.                rclInter.xRight++;
  1807.                rclInter.yTop++;
  1808.  
  1809.                drawSpriteAt(hsSprite->hpgPlay->hpsWork,
  1810.                             hsLayer,
  1811.                             &szlWork,
  1812.                             &ptlWork,
  1813.                             &rclInter);
  1814.             } /* endif */
  1815.          } /* endfor */
  1816.  
  1817.          //----------------------------------------------------------------
  1818.          // GpiBitBlt is non-inclusive on source AND target
  1819.          //----------------------------------------------------------------
  1820.          aptlPoints[0].x=rclUnion.xLeft;
  1821.          aptlPoints[0].y=rclUnion.yBottom;
  1822.          aptlPoints[1].x=rclUnion.xRight+1;
  1823.          aptlPoints[1].y=rclUnion.yTop+1;
  1824.          aptlPoints[2].x=0;
  1825.          aptlPoints[2].y=0;
  1826.          aptlPoints[3].x=rclUnion.xRight-rclUnion.xLeft+1;
  1827.          aptlPoints[3].y=rclUnion.yTop-rclUnion.yBottom+1;
  1828.  
  1829.          if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlPlay)) {
  1830.             GpiBitBlt(hpsDraw,
  1831.                       hsSprite->hpgPlay->hpsWork,
  1832.                       4,
  1833.                       aptlPoints,
  1834.                       ROP_SRCCOPY,
  1835.                       BBO_IGNORE);
  1836.          } /* endif */
  1837.       } /* endif */
  1838.    } else {
  1839.       hsSprite->ptlPos=*pptlNew;
  1840.    } /* endif */
  1841.  
  1842.    accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1843.    return SPR_ERR_NOERROR;
  1844. }
  1845.  
  1846. As with CmnSprDrawSprite(), the real work is done in the loop; however, since 
  1847. there is an offset from the bottom of the workspace, the code is slightly 
  1848. different than the previous loop. 
  1849.  
  1850. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1851.  
  1852.  
  1853. ΓòÉΓòÉΓòÉ 4.4. New Functions ΓòÉΓòÉΓòÉ
  1854.  
  1855. New Functions 
  1856.  
  1857. So, now we have this fancy capability in our library, but we have no way of 
  1858. changing the z-order of a sprite once it has been established (save removing 
  1859. all of the sprites from the playing and re-adding them in the desired order). 
  1860. To alleviate this, two new functions were added which simply operate on the 
  1861. ahsSprites array of the playground.  The code is presented below but will not 
  1862. be discussed. 
  1863.  
  1864. SPRERROR EXPENTRY CmnSprSetLayering(HPS hpsDraw,HCSSPRITE hsSprite,LONG lPos)
  1865. //-------------------------------------------------------------------------
  1866. // This function sets the z-order of a sprite.
  1867. //
  1868. // Input:  hpsDraw - handle to the HPS to make the updates in.
  1869. //         hsSprite - handle to the sprite whose z-order is to be changed
  1870. //         lPos - an absolute layer number (0 to MAX_SPRITES-1) or an
  1871. //                SSL_* constant.
  1872. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1873. //-------------------------------------------------------------------------
  1874. {
  1875.    USHORT usSemAction;
  1876.    SPRERROR seError;
  1877.    LONG lOld;
  1878.    LONG lNew;
  1879.    LONG lOldDx;
  1880.    LONG lNewDx;
  1881.    HCSSPRITE ahsCopy[MAX_SPRITES];
  1882.    ULONG ulIndex;
  1883.  
  1884.    if (queryHandle(hsSprite)!=QH_HCSSPRITE) {
  1885.       return SPR_ERR_BADHANDLE;
  1886.    } /* endif */
  1887.  
  1888.    usSemAction=accessSem((PCMNHANDLE)hsSprite,ACCSEM_SET);
  1889.  
  1890.    if (hsSprite->hpgPlay==NULL) {
  1891.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1892.       return SPR_ERR_HASNOPLAYGROUND;
  1893.    } /* endif */
  1894.  
  1895.    seError=CmnSprQueryLayering(hsSprite,&lOld);
  1896.    if (seError!=SPR_ERR_NOERROR) {
  1897.       return seError;
  1898.    } /* endif */
  1899.  
  1900.    lNew=lOld;
  1901.  
  1902.    switch (lPos) {
  1903.    case SSL_TOP:
  1904.       lNew=hsSprite->hpgPlay->ulNumMembers-1;
  1905.       break;
  1906.    case SSL_BOTTOM:
  1907.       lNew=0;
  1908.       break;
  1909.    case SSL_UP:
  1910.       lNew=lOld+1;
  1911.       break;
  1912.    case SSL_DOWN:
  1913.       lNew=lOld-1;
  1914.       break;
  1915.    default:
  1916.       lNew=lPos;
  1917.    } /* endswitch */
  1918.  
  1919.    if ((lNew<0) || (lNew>hsSprite->hpgPlay->ulNumMembers-1)) {
  1920.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1921.       return SPR_ERR_BADLAYER;
  1922.    } /* endif */
  1923.  
  1924.    if ((lNew==lOld) || (hsSprite->hpgPlay->ulNumMembers==1)) {
  1925.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1926.       return SPR_ERR_NOERROR;
  1927.    } /* endif */
  1928.  
  1929.    memset(ahsCopy,0,sizeof(ahsCopy));
  1930.    ahsCopy[lNew]=hsSprite->hpgPlay->ahsSprites[lOld];
  1931.  
  1932.    lOldDx=0;
  1933.    lNewDx=0;
  1934.  
  1935.    for (ulIndex=0; ulIndex<hsSprite->hpgPlay->ulNumMembers-1; ulIndex++) {
  1936.       if (ulIndex==lOld) {
  1937.          lOldDx=1;
  1938.       } else
  1939.       if (ulIndex==lNew) {
  1940.          lNewDx=1;
  1941.       } /* endif */
  1942.  
  1943.       ahsCopy[ulIndex+lNewDx]=hsSprite->hpgPlay->ahsSprites[ulIndex+lOldDx];
  1944.    } /* endfor */
  1945.  
  1946.    memcpy(hsSprite->hpgPlay->ahsSprites,ahsCopy,sizeof(ahsCopy));
  1947.  
  1948.    CmnSprDrawSprite(hpsDraw,hsSprite);
  1949.  
  1950.    accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1951.    return SPR_ERR_NOERROR;
  1952. }
  1953.  
  1954. SPRERROR EXPENTRY CmnSprQueryLayering(HCSSPRITE hsSprite,PLONG plPos)
  1955. //-------------------------------------------------------------------------
  1956. // This function sets the z-order of a sprite.
  1957. //
  1958. // Input:  hsSprite - handle to the sprite whose z-order is to be queried
  1959. //         plPos - points to the variable to receive the layer number.
  1960. // Output:  plPos - points to the layer number (0 to MAX_SPRITES-1).
  1961. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1962. //-------------------------------------------------------------------------
  1963. {
  1964.    USHORT usSemAction;
  1965.    ULONG ulIndex;
  1966.  
  1967.    if (queryHandle(hsSprite)!=QH_HCSSPRITE) {
  1968.       return SPR_ERR_BADHANDLE;
  1969.    } /* endif */
  1970.  
  1971.    usSemAction=accessSem((PCMNHANDLE)hsSprite,ACCSEM_SET);
  1972.  
  1973.    if (hsSprite->hpgPlay==NULL) {
  1974.       accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1975.       return SPR_ERR_HASNOPLAYGROUND;
  1976.    } /* endif */
  1977.  
  1978.    for (ulIndex=0; ulIndex<hsSprite->hpgPlay->ulNumMembers; ulIndex++) {
  1979.       if (hsSprite->hpgPlay->ahsSprites[ulIndex]==hsSprite) {
  1980.          *plPos=ulIndex;
  1981.          return SPR_ERR_NOERROR;
  1982.       } /* endif */
  1983.    } /* endfor */
  1984.  
  1985.    accessSem((PCMNHANDLE)hsSprite,usSemAction);
  1986.    return SPR_ERR_NOTFOUND;
  1987. }
  1988.  
  1989. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  1990.  
  1991.  
  1992. ΓòÉΓòÉΓòÉ 4.5. Collision Detection ΓòÉΓòÉΓòÉ
  1993.  
  1994. Collision Detection 
  1995.  
  1996. (This section describes the concepts of collision detection, although no code 
  1997. has yet been written to implement this.) 
  1998.  
  1999. Collision detection, a necessary function in most video games, is the method by 
  2000. which it is determined if two objects are touching at any point. Consider the 
  2001. following two sprites: 
  2002.  
  2003. It is obvious that this is far more complicated a matter than simply checking 
  2004. the bounding rectangles, since the object drawn within will probably not 
  2005. encompass the entire bounding rectangle, nor will they be as regularly shaped 
  2006. as the examples above. 
  2007.  
  2008. Et Tu, Brute? 
  2009.  
  2010. As in most Computer Science problems, brute force could be applied here to 
  2011. solve this problem: 
  2012.  
  2013.  1. If the bounding rectangles do not overlap, then the test fails. 
  2014.  
  2015.  2. Calculate the union of the bounding rectangles 
  2016.  
  2017.  3. For each pel in the union rectangle, check each sprite to see if it has a 
  2018.     pel in that position also.  If we find one, the test succeeds. 
  2019.  
  2020.  4. The test fails if we reach this point. 
  2021.  
  2022. While this algorithm would probably work, the performance is O(n*n), which is 
  2023. unacceptable for programs - such as video games - where pseudo-real-time 
  2024. response is necessary.  However, this approach is not entirely without its 
  2025. merits... 
  2026.  
  2027. Consider step 3 in the pseudo-code above, since that is the performance-eater. 
  2028. If we could reduce the CPU requirements of this step to below some threshold 
  2029. that we define, the algorithm becomes quite usable. Since the problem lies in 
  2030. our double-loop plus system call, that should be our area of concentration. 
  2031.  
  2032. The first step in solving this is to figure out how we would implement the step 
  2033. in its unmodified state.  The only fault-proof way that I could think of was to 
  2034. use the masks of each sprite, since they are not contaminated by the background 
  2035. bitmap.  By adjusting our indices to allow for offsets of each mask relative to 
  2036. the positions of the corresponding sprites, we can easily determine if the 
  2037. sprite has a pel at any given position or not. 
  2038.  
  2039. Some of you might already see the solution. 
  2040.  
  2041. Using the monochrome property of the masks, we could speed up this algorithm 
  2042. considerable if we call GpiBitBlt() to copy each of the masks into a workspace 
  2043. and then check for the intersection of the two (black pels, if you do not 
  2044. remember.  See the first article in this series.). However, the double loop 
  2045. still keeps the performance at O(n*n), although the prefixing coefficient is no 
  2046. longer as large. 
  2047.  
  2048. The final step is to convert this to a linear operation, instead of a 
  2049. two-dimensional one.  This is done by calling GpiQueryBitmapBits() and then 
  2050. using memchr() to search for any byte that is non-255. (If you don 't 
  2051. understand that, remember that we have a monochrome bitmap, so each white pel 
  2052. is represented by a set bit.  All white therefore equates to 255, but we are 
  2053. looking for a single black pel.)  Since monochrome bitmaps take very little 
  2054. memory and since the library has an inherent maximum size for sprites, we can 
  2055. allocate the memory to hold the bitmap bits during the CmnSprCreatePlayground() 
  2056. call and use the workspace that we are already allocating (hpsWork) for the 
  2057. GpiBitBlt() call. 
  2058.  
  2059. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  2060.  
  2061. If you are impatient, you can code this before I do.  <grin> 
  2062.  
  2063. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2064.  
  2065.  
  2066. ΓòÉΓòÉΓòÉ 4.6. Summary ΓòÉΓòÉΓòÉ
  2067.  
  2068. Summary 
  2069.  
  2070. In this final article, we looked at how z-ordering can and is implemented in 
  2071. our sprite library.  If you get version 1.6.0 of the Common/2 library (now on 
  2072. ftp.cdrom.com) and compile the included I-495 sample to use this library, you 
  2073. will find that the performance does not suffer noticably. 
  2074.  
  2075. Additionally, we looked into collision detection and how it could be 
  2076. implemented with maximum performance; this will undoubtedly be added to a 
  2077. future version of Common/2 to ease the burden of those inspired writers who 
  2078. wish to translate their favorite "shoot-em up" game to their favorite operating 
  2079. system. 
  2080.  
  2081. Sprites and Animation (Reprise) - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2082.  
  2083.  
  2084. ΓòÉΓòÉΓòÉ 5. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
  2085.  
  2086.  
  2087. ΓòÉΓòÉΓòÉ 5.1. Introduction ΓòÉΓòÉΓòÉ
  2088.  
  2089. /dev/EDM2/BookReview 
  2090.  
  2091. Written by Carsten Whimster 
  2092.  
  2093. Introduction 
  2094.  
  2095. /dev/EDM2/BookReview is a monthly column which focuses on development oriented 
  2096. books and materials.  The column is from a beginning PM programmer's eyes, 
  2097. because that's what I am.  Pick up whichever book strikes your fancy, and join 
  2098. the growing group of people following our PM programming columns.  I will 
  2099. review books aimed at beginners for a while, and then move on from there. 
  2100.  
  2101. Please send me your comments and thoughts so that I can make this column as 
  2102. effective as possible.  All mail to me gets read and responded to. 
  2103.  
  2104. Mastering OS/2 REXX is an introductory REXX programming book. It assumes little 
  2105. or no previous programming knowledge. 
  2106.  
  2107. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2108.  
  2109.  
  2110. ΓòÉΓòÉΓòÉ 5.2. Errata ΓòÉΓòÉΓòÉ
  2111.  
  2112. Errata 
  2113.  
  2114. I have been working a bit more on my OS/2 WWW page, but I need a more permanent 
  2115. place to put it, as I have to pay for the current location separately, so you 
  2116. won't see it advertized any more, until I find a new spot :) 
  2117.  
  2118. It has been quiet with respect to mail from readers again.  It would be nice if 
  2119. more readers would take the time to send in their thoughts and comments, both 
  2120. positive and negative, but then we are all busy. 
  2121.  
  2122. Watcom C/C++ 10.0 is here.  It looks really good, but I haven't had the time to 
  2123. look closer yet.  It came in a package the size of a hard-cover book, 
  2124. containing only the CD-ROM (in case you hadn't guessed that I chose this 
  2125. format), a "Getting Started" booklet, and some flyers.  The complete 
  2126. documentation package can be had for around $100 as an update (to 9.5), or $150 
  2127. for the whole deal.  I decided to live with the on-line version for now, as the 
  2128. price for the documentation is the same whether you buy it right away or not. 
  2129.  
  2130. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2131.  
  2132.  
  2133. ΓòÉΓòÉΓòÉ 5.3. Mastering OS/2 REXX ΓòÉΓòÉΓòÉ
  2134.  
  2135. Mastering OS/2 REXX 
  2136.  
  2137. Mastering OS/2 REXX  is a how-to book on REXX programming for rank novices.  It 
  2138. does a lot of hand-holding along the way, and is very unintimidating.  It is 
  2139. aimed squarely at people who have either never programmed, or have programmed 
  2140. very little.  It introduces new concepts with great patience, and has many 
  2141. little sample programs to illustrate key concepts and functionality.  The 
  2142. following are the chapters: 
  2143.  
  2144.  1. What You Can Do With REXX 
  2145.  2. Where Does REXX Fit in on OS/2? 
  2146.  3. How to Create and Execute a REXX Program 
  2147.  4. REXX Syntax:  The Rules of the Language 
  2148.  5. The Basics:  Some Simple REXX Verbs 
  2149.  6. IF - the Conditional 
  2150.  7. String Manipulation:  The Parse Instruction 
  2151.  8. Debugging 
  2152.  9. Trapping Errors 
  2153. 10. Math 
  2154. 11. SELECT:  The Case Structure 
  2155. 12. Executing OS/2 Commands 
  2156. 13. Built-in Functions 
  2157. 14. User-Written Functions/Subroutines 
  2158. 15. Looping 
  2159. 16. Queueing Data with REXX 
  2160. 17. Compound Variables 
  2161. 18. Reading and Writing Files 
  2162. 19. The INTERPRET Instruction 
  2163. 20. Converting from Batch Files 
  2164. 21. Appendix A:  Problems and Solutions 
  2165. 22. Appendix B:  OS/2 Commands 
  2166. 23. Appendix C:  REXX Instructions 
  2167. 24. Appendix D:  REXX Functions 
  2168. 25. Appendix E:  REXX Reserved Variables 
  2169.  
  2170. The first two chapters are very introductory in nature, and only describe 
  2171. briefly what can be done with REXX, and how REXX is accessed on OS/2. 
  2172.  
  2173. Chapter 3 introduces REXX properly, and eventually introduces the first little 
  2174. snippet of REXX code, but first it describes in (excrutiating, for those of us 
  2175. familiar with EPM and WPS) detail what shadows are, how to make a directory for 
  2176. your programs, how to start the editor (EPM), a brief tutorial on EPM, how to 
  2177. run your REXX programs on the commandline, and how to use PMREXX to run your 
  2178. REXX programs in the WPS environment.  It also shows how to tell where your 
  2179. program is being executed, from within your program. Tokenizing of a program is 
  2180. demonstrated as well.  Although this all sounds terribly slow for the 
  2181. experienced user, it surprises you a little from time to time with unexpected 
  2182. nuggets of obscure information. 
  2183.  
  2184. Chapter 3 was only a brief demonstration, and in chapter 4 the syntax and some 
  2185. of REXX's peculiarities are explained.  Numbers, literals, and variables are 
  2186. introduced, and some of the more basic keywords of REXX as well.  Chapter 5 
  2187. introduces SAY, PULL, ARG, ECHO, and EXIT.  By the way, each chapter is fairly 
  2188. short (with a couple of exceptions), and at the end there is a question 
  2189. section, with the answers at the back of the book.  This really helps the 
  2190. novice to test his or her newly gained knowledge at an early stage, and 
  2191. reinforces the material well. 
  2192.  
  2193. Chapter 6 explains the various uses of IF, including using NOP, comparisons, 
  2194. fuzzy comparisons, and boolean operators. 
  2195.  
  2196. Chapter 7 is more difficult, and introduces the PARSE instruction. This chapter 
  2197. is not as easy as what came before, and Gargiulo is very careful not to lose 
  2198. his reader.  Many of the numerous permutations of the PARSE instruction are 
  2199. demonstrated.  I suspect Gargiulo has extensive experience teaching REXX, 
  2200. something which is supported by his claim to offer several REXX-based courses 
  2201. on various operating systems. 
  2202.  
  2203. Chapter 8 gets a little deeper, and introduces debugging.  Both interactive 
  2204. debugging, and tracing is shown.  In the same vein, chapter 9 continues the 
  2205. trouble-shooting thread into the trapping of errors.  Many types of errors are 
  2206. eplained, along with the trapping techniques required to handle them. 
  2207.  
  2208. Chapter 10 leaves trouble-shooting behind, and introduces math under REXX. REXX 
  2209. is particularly flexible in math, and you can have any precision you desire. 
  2210. Precision and rounding are explained, and how to display numbers. 
  2211.  
  2212. Just a quick note here:  many of the preceding chapters were very short, and 
  2213. although every new topic is accompanied by an example, it would be nice to see 
  2214. some more elaborate examples from time to time.  This would enable the novice 
  2215. programmer to get a better feel for what the various constructs and 
  2216. instructions are used for in the real world, and not just the typical half-page 
  2217. programs used more or less through-out the book. 
  2218.  
  2219. Chapter 11 is dedicated to the SELECT structure, and again, this chapter is 
  2220. relatively short, although four examples were used to demonstrate the use. This 
  2221. all just goes to show that this book is for novice programmers, but doesn't 
  2222. teach programming, only REXX. 
  2223.  
  2224. Executing OS/2 commands is the topic of chapter 12, and REXX's built-in 
  2225. functions are in chapter 13.  Passing parameters is explained in more detail, 
  2226. and how to do this with OS/2 commands is explained.  A good-sized list of 
  2227. available REXX functions is given.  The list is well organized into categories 
  2228. to help dissipate the unavoidable confusion when confronted with a slew of new 
  2229. functions in one go.  Many of these functions will have to be tried, or looked 
  2230. up in the on-line reference before the meaning becomes clear, but after the 
  2231. list, the more important ones are explained in more detail.  The logical 
  2232. follow-up to chapter 13 is given in chapter 14, User-written 
  2233. Functions/Subroutines.  This chapter shows how to use the RESULT variable, 
  2234. parameter passing and parsing, the RETURN keyword, labels, how to avoid sharing 
  2235. variables, and then compares internal and external REXX functions. Some 
  2236. pointers are given on style too, something which the book in general only shows 
  2237. through the snippets. 
  2238.  
  2239. Chapter 15 shows the many types of loops available in REXX, and tries to 
  2240. explain where to use the different kinds.  This is explained mainly through 
  2241. showing the constraints of each kind, and the higher level theory of the use of 
  2242. the different kinds is skipped over.  Again, style and actual programming isn't 
  2243. really taught that much here, only REXX.  From time to time there is a little 
  2244. something, but not much. 
  2245.  
  2246. Chapter 16 surprised me a bit.  Queueing is not a basic concept, yet Gargiulo 
  2247. teaches it with the same thoroughness that he teaches the simpler concepts. 
  2248. Simple process-to-process communication is explained, but not the need for it. 
  2249. The novice must be scratching his or her head at this point, saying "ok, but 
  2250. why?".  The answer:  look elsewhere for a why, this is a REXX how-to. 
  2251.  
  2252. Compund variables are treated rather late in chapter 17, but the possible 
  2253. real-world use is skipped again. 
  2254.  
  2255. File input and output is introduced in chapter 18, including reading from and 
  2256. writing to COM ports, the keyboard, printers, and the STD file streams, STDIN, 
  2257. STDOUT, and STDERR. 
  2258.  
  2259. Chapter 19 demonstrates the INTERPRET instruction in three pages (now you know 
  2260. why many of the preceding paragraphs don't seem to say much more than the title 
  2261. of the chapters). 
  2262.  
  2263. Finally, the book is wrapped up in chapter 20 by explaining how to convert from 
  2264. batch files to REXX programs, and when this is desirable. 
  2265.  
  2266. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2267.  
  2268.  
  2269. ΓòÉΓòÉΓòÉ 5.4. Summary ΓòÉΓòÉΓòÉ
  2270.  
  2271. Summary 
  2272.  
  2273. This book is very slow-moving, and is not aimed at anyone reasonably familiar 
  2274. with any modern programming language.  It is very tutorial in nature, and 
  2275. introduces only the most basic concepts most of the time.  The various looping 
  2276. constructs and so on are all explained as if you have never seen them before in 
  2277. any language.  The verbal language used by Gargiulo is also very tutorial, as 
  2278. opposed to informational.  This leaves me wondering why he skipped the 
  2279. high-level explanations of programming.  Usually, introductory books aim to 
  2280. teach programming, and then choose a language to do it.  It almost seems as if 
  2281. this book aims only to teach REXX, and not programming.  I cannot imagine what 
  2282. kind of person would know how to program, but not be familiar with any actual 
  2283. language?  In any case, the book teaches REXX very thoroughly, and it does 
  2284. hand-hold you through some slightly intermediate concepts.  I have no problem 
  2285. recommending this book to bright would-be programmers, but I might hesitate a 
  2286. little before recommending it to someone whose computer knowledge is a little 
  2287. more sparse. 
  2288.  
  2289. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2290.  
  2291.  
  2292. ΓòÉΓòÉΓòÉ 5.5. Books Reviewed ΓòÉΓòÉΓòÉ
  2293.  
  2294. Books Reviewed 
  2295.  
  2296. This table contains all books I have reviewed, so that you can find what you 
  2297. are looking for at a glance.  I will be careful to rate books fairly.  If I 
  2298. feel a need to adjust ratings, I will adjust all of them at the same time, and 
  2299. write a note explaining why I felt this necessary.  Please note that books 
  2300. aimed at different audiences should only be compared with great care, if at 
  2301. all.  I intend to concentrate on the strong points of the books I review, but I 
  2302. will point out any weaknesses in a constructive manner. 
  2303.  
  2304. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2305. ΓöéBOOK                                ΓöéAUDIENCE    ΓöéMARKΓöéCOMMENTS                                         Γöé
  2306. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2307. ΓöéReal-World Programming for OS/2 2.1,ΓöéIntermediateΓöéB+  ΓöéLots of good code examples, but sometimes it is  Γöé
  2308. ΓöéBlain, Delimon, and English, SAMS   Γöéto Advanced Γöé    Γöétoo complex for novices. Accurate.  Well         Γöé
  2309. ΓöéPublishing.  ISBN 0-672-30300-0.    ΓöéPM C        Γöé    Γöéorganized.  The index needs a little beefing up. Γöé
  2310. ΓöéUS$40, CAN$50.                      Γöéprogrammers Γöé    ΓöéGood, but not entirely complete how-to reference.Γöé
  2311. Γöé                                    Γöé            Γöé    ΓöéGood purchase.                                   Γöé
  2312. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2313. ΓöéLearning to Program OS/2 2.0        ΓöéBeginning PMΓöéB-  ΓöéThis book can be both frustrating and very       Γöé
  2314. ΓöéPresentation Manager by Example,    ΓöéC           Γöé    Γöérewarding.  It is not very large, and a bit      Γöé
  2315. ΓöéKnight, Van Nostrand Reinhold.  ISBNΓöéProgrammers Γöé    Γöépricey, but has some excellent chapters on       Γöé
  2316. Γöé0-442-01292-6.  US$40, CAN$50.      Γöé            Γöé    Γöécertain beginning topics, such as messages,      Γöé
  2317. Γöé                                    Γöé            Γöé    Γöéresources, IPF, and dialog boxes.  Strictly for  Γöé
  2318. Γöé                                    Γöé            Γöé    Γöébeginners.  This book has only one (large) sampleΓöé
  2319. Γöé                                    Γöé            Γöé    Γöéprogram!                                         Γöé
  2320. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2321. ΓöéWriting OS/2 2.1 Device Drivers in  ΓöéAdvanced C  ΓöéA-  ΓöéThe only thing a device driver programmer would  Γöé
  2322. ΓöéC, 2nd Edition, Mastrianni, Van     ΓöéProgrammers,Γöé    Γöénot find in here is how to write SCSI, ADD, and  Γöé
  2323. ΓöéNostrand Reinhold.  ISBN            Γöéfamiliar    Γöé    ΓöéIFS drivers.  Most everything else is in here,   Γöé
  2324. Γöé0-442-01729-4.  US$35, CAN$45.      Γöéwith        Γöé    Γöéalong with skeleton examples.  An optional DevHlpΓöé
  2325. Γöé                                    Γöéhardware    Γöé    Γöélibrary of C-callable functions can be purchased Γöé
  2326. Γöé                                    Γöéprogramming Γöé    Γöéby those who don't have time to write their own. Γöé
  2327. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2328. ΓöéOS/2 Presentation Manager GPI, Winn,ΓöéIntermediateΓöéC+  ΓöéThis book needs updating for OS/2 2.x.  It is a  Γöé
  2329. ΓöéVan Nostrand Reinhold. ISBN         Γöéto advanced Γöé    Γöéwell-written in-depth coverage of the OS/2 way ofΓöé
  2330. Γöé0-442-00739-6.  US$35, CAN$45.      ΓöéPM C        Γöé    Γöéprogramming for graphics.  It is not an          Γöé
  2331. Γöé                                    Γöéprogrammers Γöé    Γöéintroductory PM or graphics programming book.    Γöé
  2332. Γöé                                    Γöé            Γöé    ΓöéYou should know the basics of PM programming     Γöé
  2333. Γöé                                    Γöé            Γöé    Γöéalready.                                         Γöé
  2334. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2335. ΓöéThe Art of OS/2 2.1 C Programming,  ΓöéBeginning   ΓöéB+  ΓöéThis is a great introductory PM programming book.Γöé
  2336. ΓöéPanov, Salomon, and Panov,          ΓöéOS/2 and PM Γöé    ΓöéIt covers basic OS/2 issues like threads before  Γöé
  2337. ΓöéWiley-QED.  ISBN 0-471-58802-4.     Γöéprogrammers Γöé    Γöéit jumps into PM programming.  The coverage is   Γöé
  2338. ΓöéUS$40, CAN$50.                      Γöé            Γöé    Γöéquite thourough, with just enough reference      Γöé
  2339. Γöé                                    Γöé            Γöé    Γöématerial to make it useful after you read it     Γöé
  2340. Γöé                                    Γöé            Γöé    Γöéthrough the first time.  The upcoming revised    Γöé
  2341. Γöé                                    Γöé            Γöé    Γöéedition should be a killer.                      Γöé
  2342. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2343. ΓöéMastering OS/2 REXX, Gargiulo,      ΓöéIntermediateΓöéB   ΓöéThis book is very easy to understand.  If you    Γöé
  2344. ΓöéWiley-QED.  ISBN 0-471-51901-4.     ΓöéOS/2 users  Γöé    Γöéprogram with any regularity, look elsewhere, but Γöé
  2345. ΓöéUS$40, CAN$50.                      Γöéand novice  Γöé    Γöéif you need an easily read, well-explained       Γöé
  2346. Γöé                                    Γöéprogrammers Γöé    Γöébeginner's book, look no further.  Some more     Γöé
  2347. Γöé                                    Γöé            Γöé    Γöédetailed, and complex real-world examples might  Γöé
  2348. Γöé                                    Γöé            Γöé    Γöébe useful as you learn the material.  Good       Γöé
  2349. Γöé                                    Γöé            Γöé    Γöécoverage of REXX's capabilities.                 Γöé
  2350. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2351.  
  2352. LEGEND: 
  2353.  
  2354. BOOK:  The name of the book, author(s), publishing company, ISBN, and 
  2355. approximate price. 
  2356.  
  2357. AUDIENCE:  This is a description of the audience I think the book targets best. 
  2358. This is not intended as gospel, just a guideline for people not familiar with 
  2359. the book. 
  2360.  
  2361. MARK:  My opinion of the success of the book's presentation, and how well it 
  2362. targets its audience.  Technical content, accuracy, organization, readability, 
  2363. and quality of index all weigh heavily here, but the single most important item 
  2364. is how well the book covers what it says it covers. 
  2365.  
  2366. ΓöîΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2367. ΓöéA+ ΓöéGround-breaking, all-around outstanding book                                 Γöé
  2368. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2369. ΓöéA  ΓöéExcellent book.  This is what I want to see happen a lot                     Γöé
  2370. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2371. ΓöéA- ΓöéExcellent book with minor flaws                                              Γöé
  2372. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2373. ΓöéB+ ΓöéVery good book with minor flaws or omissions                                 Γöé
  2374. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2375. ΓöéB  ΓöéGood book with some flaws and omissions                                      Γöé
  2376. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2377. ΓöéB- ΓöéGood book, but in need of improvement                                        Γöé
  2378. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2379. ΓöéC+ ΓöéMediocre book with some potential, but in need of some updating              Γöé
  2380. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2381. ΓöéC  ΓöéMediocre book with some good sections, but badly in need of fixing           Γöé
  2382. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2383. ΓöéC- ΓöéMediocre book, little good material, desperately in need of an overhaul      Γöé
  2384. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2385. ΓöéD  ΓöéDon't buy this book unless you need it, and nothing else exists              Γöé
  2386. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2387. ΓöéF  ΓöéDon't buy this book.  Period                                                 Γöé
  2388. ΓööΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2389.  
  2390. COMMENTS:  This is a very brief summary of the review proper. 
  2391.  
  2392. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2393.  
  2394.  
  2395. ΓòÉΓòÉΓòÉ 5.6. Coming Up ΓòÉΓòÉΓòÉ
  2396.  
  2397. Coming Up 
  2398.  
  2399. Next month I will be looking at REXX Reference Summary Handbook, Goran.  The 
  2400. books I intend to review are (not necessarily in this order): 
  2401.  
  2402. o REXX Reference Summary Handbook, Goran 
  2403. o OS/2 Presentation Manager Programming, Petzold 
  2404. o Application Development Using OS/2 REXX, Rudd 
  2405. o The Design of OS/2, 2nd Edititon, Kogan and Deitel - 1994 - not published yet 
  2406.   (or is it?) 
  2407.  
  2408. I am considering reviewing the IBM OS/2 Redbooks, since they are readily and 
  2409. cheaply available, and look like good reference. 
  2410.  
  2411. I am also considering reviewing Designing OS/2 Applications, Reich, mostly 
  2412. because it promises to present a different angle on OS/2 programming, namely 
  2413. that of how to design OS/2 applications, rather than how to program  OS/2 
  2414. applications. 
  2415.  
  2416. Finally, I am considering reviewing OS/2 Unleashed, but it is not strictly 
  2417. speaking a development book, so I'm going to wait until the list of real 
  2418. development books has diminished a bit.  I hear that there is a CD-ROM version 
  2419. of it out now, and I will try to get a copy of this. 
  2420.  
  2421. If anyone has a book they want to see reviewed, I will be happy to oblige as 
  2422. long as I can afford it.  Of course, requests can be satisfied quicker when 
  2423. accompanied by a book :)  Publishers can send me books at the address on my 
  2424. personal page at the end of the magazine, and I will review all OS/2 
  2425. development-related and advanced user books I receive. 
  2426.  
  2427. /dev/EDM/BookReview - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2428.  
  2429.  
  2430. ΓòÉΓòÉΓòÉ 6. C++ Corner ΓòÉΓòÉΓòÉ
  2431.  
  2432.  
  2433. ΓòÉΓòÉΓòÉ 6.1. Introduction ΓòÉΓòÉΓòÉ
  2434.  
  2435. C++ Corner 
  2436.  
  2437. Written by Gordon Zeglinski 
  2438.  
  2439. Introduction 
  2440.  
  2441. This column deviates from the usual C++ stuff; instead, we will be exploring 
  2442. SOM's OOP model.  More precisely, the SOMobjects Developer Toolkit, which ships 
  2443. with SOM 2 and DSOM, will be examined. 
  2444.  
  2445. C++ Corner - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2446.  
  2447.  
  2448. ΓòÉΓòÉΓòÉ 6.2. What is SOM? ΓòÉΓòÉΓòÉ
  2449.  
  2450. What is SOM? 
  2451.  
  2452. SOM, the System Object Model, is a language neutral object model.  An Object in 
  2453. SOM is defined using an Interface Definition Language.  The interface language 
  2454. is then "compiled" into a language specific form. For instance, if one were 
  2455. using C to implement the object, the SOM compiler would be used to produce .C, 
  2456. .IH, and .H files.  The language specific form created by the SOM compiler has 
  2457. function stubs that the programmer would fill in.  These stubs are the bodies 
  2458. to the member functions defined in the IDL. Because SOM objects can be used 
  2459. across different languages and compilers, they use the same linkage as OS/2's 
  2460. API and their names are not mangled like in C++. 
  2461.  
  2462. OS/2 2.11 and previous versions of OS/2 2.x use SOM 1 in the Workplace Shell 
  2463. (WPS).  SOM 1 is also central to the design of VX-Rexx, and VisPro REXX. (Of 
  2464. course, any WPS based application is also SOM based.)  Not too worry, SOM 1 
  2465. based applications will still run when SOM 2 is installed because SOM 2 is 
  2466. backwards compatible to SOM 1. 
  2467.  
  2468. The following list specifies some of the ways in which SOM 2 differs from SOM 
  2469. 1: 
  2470.  
  2471.  1. allows multiple inheritance 
  2472.  2. allows derived metaclasses 
  2473.  3. is CORBA compliant 
  2474.  4. methods can return structures 
  2475.  5. multiple classes can be packaged within a single file 
  2476.  
  2477. Objects in SOM can be packaged in DLLs or in EXEs.  Using DLLs offers the 
  2478. greatest flexibility.  In fact, this is how one can extend the WPS and the 
  2479. other SOM based programs mentioned above. 
  2480.  
  2481. DSOM 
  2482.  
  2483. DSOM (Distributed System Object Model) allows SOM objects to be manipulated 
  2484. across processes.  These processes can even be on different machines.  In 
  2485. theory, this could make extending the WPS much easier than it presently is. If 
  2486. the WPS is writen to use DSOM objects, then it will be posible to write WPS 
  2487. objects that can run in their own EXE and debug that EXE instead of the whole 
  2488. WPS. 
  2489.  
  2490. Note:  the WARP II beta ships with SOM 2. 
  2491.  
  2492. The toolkit ships with a few goodies.  The first item, called "Replication 
  2493. Frameworks", allows an object to exist in multiple processes at the same time, 
  2494. even across networks.  Changes to any replicated object will be relayed to all 
  2495. replicas of the object.  The network type and other details are abstracted from 
  2496. the programmer.  Next is the "Persistence Frameworks"; it is used to stored 
  2497. objects on to disk.  The "Event Management Frameworks" can be used to 
  2498. encapsulate event based activities, like the PM message loop. 
  2499.  
  2500. Now that we have briefly looked at some of the features in the SOM toolkit, 
  2501. we'll move on to a quick look at the SOM OOP model. 
  2502.  
  2503. C++ Corner - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2504.  
  2505.  
  2506. ΓòÉΓòÉΓòÉ 6.3. SOM OOP vs C++ OOP ΓòÉΓòÉΓòÉ
  2507.  
  2508. SOM OOP vs C++ OPP 
  2509.  
  2510. First, let's take a quick look at how the two OOP models differ.  SOM uses a 
  2511. more runtime oriented OOP model.  That is, the exact function that is being 
  2512. called, or the size of the object may not be known until the code is executed. 
  2513. Methods are called using one of the following schemes: 
  2514.  
  2515.  1. Offset resolution (default) 
  2516.  2. Name-lookup resolution 
  2517.  3. Dispatch-function resolution 
  2518.  
  2519. The above list is ordered by decreasing execution speed.  Offset resolution is 
  2520. similar to "virtual functions" used in C++.  The name-lookup method allows a 
  2521. method whose name is not known until run-time to be called.  The most flexible 
  2522. and time consuming resolution method uses the dispatch-function. This method 
  2523. allows methods to be called using application specific rules.  As mentioned 
  2524. before, method names are not mangled like they are in C++; this is because, 
  2525. unlike C++, SOM does not allow operators to be overloaded. 
  2526.  
  2527. Metaclasses 
  2528.  
  2529. Coming from a C++ background, this is where things get confusing.  In C++, the 
  2530. most fundamental object is a class.  Class methods or data members were 
  2531. declared as "static" member of the class.  This is not the case in SOM. Classes 
  2532. are instances of metaclasses, and objects are instances of classes. The 
  2533. metaclass contains all the class specific functions and data.  Roughly 
  2534. speaking, a metaclass can contain data and methods that were either explicitly 
  2535. of implicitly defined as being static in C++. 
  2536.  
  2537. Note:  constructors are implicitly static member functions in C++. 
  2538.  
  2539. C++ Corner - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2540.  
  2541.  
  2542. ΓòÉΓòÉΓòÉ 6.4. A Simple Example ΓòÉΓòÉΓòÉ
  2543.  
  2544. A Simple Example 
  2545.  
  2546. We'll take the "Hello World" example created by IBM and add some class data and 
  2547. methods to it.  The source code presented here will have the IBM disclaimers 
  2548. stripped, if you really want to read them, see the source code files.  We start 
  2549. by looking at HELLO.IDL. 
  2550.  
  2551. #ifndef hello_h
  2552. #define hello_h
  2553.  
  2554. #include <somcls.idl>
  2555.  
  2556. interface M_Hello;
  2557. interface Hello : SOMObject
  2558. {
  2559.     string hello_();
  2560.     attribute string hellomsg;
  2561.  
  2562.    void sayHello();
  2563.  
  2564. #ifdef __SOMIDL__
  2565. implementation
  2566. {
  2567.     releaseorder: hello_, _get_hellomsg, _set_hellomsg,sayHello;
  2568.     callstyle=oidl;
  2569.     filestem = hello;
  2570.     metaclass = M_Hello;
  2571.     somInit: override;
  2572. };
  2573. #endif /* __SOMIDL__ */
  2574. };
  2575.  
  2576. interface M_Hello : SOMClass
  2577. {
  2578.     attribute string ClassData;
  2579.  
  2580.     Hello HelloCreate(in string msg);
  2581.     // This method creates an instance of the Hello class and
  2582.     // uses the value of "msg" to initialise it.
  2583. #ifdef __SOMIDL__
  2584. implementation
  2585. {
  2586.    releaseorder: HelloCreate,_get_ClassData,_set_ClassData;
  2587.    callstyle=oidl;
  2588.    filestem = hello;
  2589.    functionprefix=M_;
  2590.    somInitMIClass: override;
  2591.    somInit: override; // just a test for parent call macros
  2592. };
  2593. #endif /* __SOMIDL__ */
  2594. };
  2595.  
  2596. #endif /* hello_h */
  2597.  
  2598. To the Hello class, I have added the member void sayHello().  To the M_Hello 
  2599. metaclass, I have added the member attribute string ClassData.  An attribute is 
  2600. merely a data member that has _get_ and _set_ methods automatically defined for 
  2601. it.  The original code can be found in the \som\samples\somk\cpp\derived 
  2602. directory if the samples were installed with the toolkit.  The code for 
  2603. sayHello() is shown below.  This code illustrates how to access instance data 
  2604. and class data.  The code below is written using the C++ bindings. 
  2605.  
  2606. SOM_Scope void  SOMLINK sayHello(Hello *somSelf)
  2607. {
  2608.     //the folowing two lines are created by the som compiler.
  2609.     HelloData *somThis = HelloGetData(somSelf);
  2610.     HelloMethodDebug("Hello","sayHello");
  2611.  
  2612.     // Get the CLASS instance
  2613.     M_Hello *helloCls=(M_Hello *)somSelf->somGetClass();
  2614.  
  2615.     printf("%s an instance of %s\n",somSelf->_get_hellomsg(),helloCls->_get_ClassData());
  2616. }
  2617.  
  2618. It is worth noting that the data/attributes are accessed by calling methods 
  2619. rather than by explicitly using the attributes name.  Also, class data is 
  2620. accessed by using a pointer to an instance of the M_Hello metaclass. 
  2621.  
  2622. Note:  M_Hello is the metaclass for Hello. 
  2623.  
  2624. Now lets put this code to work. 
  2625.  
  2626.  
  2627. int main(int argc, char *argv[])
  2628. {
  2629.    Hello *a,*b,*c;
  2630.  
  2631.    // create an instance of the M_Hello metaclass
  2632.    M_Hello *helloClsObj=HelloNewClass(Hello_MajorVersion,Hello_MinorVersion);
  2633.  
  2634.    //set the class data
  2635.    helloClsObj->_set_ClassData("Class 1");
  2636.  
  2637.    //call the M_Hello class method HelloCreate to create an instance of
  2638.    //the class Hello
  2639.  
  2640.    a=helloClsObj->HelloCreate("Hello from A");
  2641.    b=helloClsObj->HelloCreate("Hello from B");
  2642.    c=helloClsObj->HelloCreate("Hello from C");
  2643.  
  2644.    //call the sayHello method for each object
  2645.    a->sayHello();
  2646.    b->sayHello();
  2647.    c->sayHello();
  2648.  
  2649.    // free up each of the objects
  2650.    a->somFree();
  2651.    b->somFree();
  2652.    c->somFree();
  2653.  
  2654.    return 0;
  2655. }
  2656.  
  2657. C++ Corner - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2658.  
  2659.  
  2660. ΓòÉΓòÉΓòÉ 6.5. Wrapping Things Up ΓòÉΓòÉΓòÉ
  2661.  
  2662. Wrapping Things Up 
  2663.  
  2664. We briefly looked at some of the components of the SOMobjects Developers 
  2665. Toolkit.  In adition a simple SOM 2 example was presented.  In the next issue, 
  2666. we will look at creating a SOM class that encapsulates the INI interface. 
  2667.  
  2668. C++ Corner - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2669.  
  2670.  
  2671. ΓòÉΓòÉΓòÉ 7. Introduction to PM Programming ΓòÉΓòÉΓòÉ
  2672.  
  2673.  
  2674. ΓòÉΓòÉΓòÉ 7.1. Introduction ΓòÉΓòÉΓòÉ
  2675.  
  2676. Introduction to PM Programming 
  2677.  
  2678. Written by Larry Salomon, Jr. 
  2679.  
  2680. Introduction 
  2681.  
  2682. The purpose of this column is to provide the readers out there who are not 
  2683. familiar with PM application development the information necessary to satisfy 
  2684. their curiousity, educate themselves, and give them an advantage over the 
  2685. documentation supplied by IBM.  Of course, much of this stuff could probably be 
  2686. found in one of the many books out there, but the problem with books in general 
  2687. is that they don't answer the questions you have after you read the book the 
  2688. first time through. 
  2689.  
  2690. I will gladly entertain feedback from the readers about what was "glossed over" 
  2691. or what was detailed well, what tangential topics need to be covered and what 
  2692. superfluous crap should have been removed.  This feedback is essential in 
  2693. guaranteeing that you get what you pay for.  :) 
  2694.  
  2695. It should be said that you must not depend solely on this column to teach you 
  2696. how to develop PM applications; instead, this should be viewed as a supplement 
  2697. to your other information storehouses (books, the network conferences, etc.). 
  2698. Because this column must take a general approach, there will be some topics 
  2699. that you would like to see discussed that really do not belong here.  Specific 
  2700. questions can be directed to the Scratch Patch, where an attempt to answer them 
  2701. will be made. 
  2702.  
  2703. Last Month 
  2704.  
  2705. Last month, we began looking at the WC_LISTBOX window class, how it is used, 
  2706. what its limitations are, and some of the messages associated with it.  We 
  2707. resume this track this month, and take another look at nameDlgProc() in HELLO.C 
  2708. (see intro.zip). 
  2709.  
  2710. Introduction to PM Programming - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2711.  
  2712.  
  2713. ΓòÉΓòÉΓòÉ 7.2. nameDlgProc() and Listboxes ΓòÉΓòÉΓòÉ
  2714.  
  2715. nameDlgProc() and Listboxes 
  2716.  
  2717. If you'll look at HELLO.C, you will see comments to the right of the source 
  2718. code of the form "@n", where n is a number. These are landmarks that are 
  2719. referenced, so if you don't have the source handy, please make it available. 
  2720. Our first one is... 
  2721.  
  2722. Macros 
  2723.  
  2724. landmark number 7. 
  2725.  
  2726. WinInsertLboxItem(hwndLb,LIT_END,achText);                  // @7
  2727.  
  2728. This line, while it looks like a function call, is a macro defined in the 
  2729. Programmer's Toolkit.  This macro expands to: 
  2730.  
  2731. #define WinInsertLboxItem(hwndLbox, index, psz) \
  2732. ((LONG)WinSendMsg(hwndLbox, LM_INSERTITEM, MPFROMLONG(index), \
  2733. MPFROMP(psz)))
  2734.  
  2735. There are two points to this:  1)  there are handy macros which can shorten 
  2736. your coding time if you know what they are, and 2) this function call is really 
  2737. nothing more than the sending of an LM_INSERTITEM message, which we looked at 
  2738. briefly last month. 
  2739.  
  2740. Now, find numbers... 
  2741.  
  2742. Notifications 
  2743.  
  2744. 8 and 9.  This is a notification sent to the owner of the listbox - the dialog 
  2745. - via the WM_CONTROL message. 
  2746.  
  2747. case WM_CONTROL:                                                  // @8
  2748.    switch (SHORT1FROMMP(mpParm1)) {
  2749.    case DNAME_LB_NAMELIST:
  2750.       switch (SHORT2FROMMP(mpParm1)) {
  2751.       case LN_SELECT:                                             // @9
  2752.          {
  2753.             HWND hwndLb;
  2754.             SHORT sIndex;
  2755.  
  2756.             hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);
  2757.  
  2758.             sIndex=WinQueryLboxSelectedItem(hwndLb);
  2759.             WinQueryLboxItemText(hwndLb,
  2760.                                  sIndex,
  2761.                                  pndiInfo->achName,
  2762.                                  sizeof(pndiInfo->achName));
  2763.  
  2764.             WinSetDlgItemText(hwndWnd,
  2765.                               DNAME_EF_NAME,
  2766.                               pndiInfo->achName);
  2767.          }
  2768.          break;
  2769.  
  2770. The notification LN_SELECT is sent to let you know that an item was selected by 
  2771. the user.  This could be using the mouse or the keyboard (using the up and down 
  2772. arrows, if single-select, or the spacebar, if multi-select).  It needs to be 
  2773. pointed out that the item that was selected is not passed as a parameter of the 
  2774. message, and no matter how many complaints were filed when this was noticed, 
  2775. IBM would not change it. 
  2776.  
  2777. "Big deal", you think.  For single-select listboxes, this is not a problem, but 
  2778. for multi-select it is a huge problem.  Consider why:  you determine the 
  2779. selected item using the message LM_QUERYSELECTION which returns the first 
  2780. selected item after the index specified, or the macro WinQueryLboxItemText() 
  2781. which always searches from the beginning. However, what happens if the user 
  2782. selects one item, and then an item following the first selection?  There is a 
  2783. solution to this problem, fortunately, but it will not be discussed until we 
  2784. look at ownerdraw listboxes. 
  2785.  
  2786. The next notification is at landmark 10. 
  2787.  
  2788. case LN_ENTER:                                        // @10
  2789.    WinPostMsg(hwndWnd,WM_COMMAND,MPFROMSHORT(DID_OK),0);
  2790.    break;
  2791.  
  2792. This notification comes whenever the user double-clicks on an item in the 
  2793. listbox or presses the ENTER key while the listbox has the input focus.  As 
  2794. with the LN_SELECT notification, this has its shortcomings.  The first is the 
  2795. same as the last notification - finding out which item was selected in a 
  2796. multi-select listbox.  The second occurs whenever you have a default pushbutton 
  2797. and the user presses the ENTER key (vs. double-clicking, which doesn't have 
  2798. this problem).  A default pushbutton is one the acts as though it was selected 
  2799. if the user presses ENTER and the window with the input focus is not a 
  2800. pushbutton.  In this scenario, you receive both the LN_ENTER notification and 
  2801. the WM_COMMAND message (which is sent by the pushbutton). Unfortunately, there 
  2802. is no good solution to this problem other than to avoid placing yourself in 
  2803. this situation. 
  2804.  
  2805. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  2806.  
  2807. We are slowly, but surely, making progress in dissecting HELLO.C.  We will 
  2808. return for the last time when we have looked at buttons, but I suspect that by 
  2809. now you have already figured out the rest of the program. 
  2810.  
  2811. Introduction to PM Programming - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2812.  
  2813.  
  2814. ΓòÉΓòÉΓòÉ 7.3. More Messages ΓòÉΓòÉΓòÉ
  2815.  
  2816. More Messages 
  2817.  
  2818. Let's look at more of the common messages used by the listbox.  Unlike the 
  2819. entryfield, we will not examine all of the listbox messages, nor all of the 
  2820. messages of any future controls we will look at.  This is because, with few 
  2821. exceptions, each control has so many messages that it would quickly become a 
  2822. hinderance to this column's effectiveness. 
  2823.  
  2824. LM_DELETEITEM 
  2825.  
  2826. This message is sent to delete an item from the listbox. 
  2827.  
  2828. Parameters 
  2829.  
  2830.    param1 
  2831.  
  2832.       lIndex (LONG) 
  2833.  
  2834.          0-based index of the item to be deleted. 
  2835.  
  2836.    param2 
  2837.  
  2838.       ulReserved (ULONG) 
  2839.  
  2840.          Reserved, 0. 
  2841.  
  2842. Returns 
  2843.  
  2844.    reply 
  2845.  
  2846.       bSuccess (BOOL) 
  2847.  
  2848.          TRUE      successful completion 
  2849.          FALSE     error occurred 
  2850.  
  2851. LM_DELETEALL 
  2852.  
  2853. This message is sent to delete all items from the listbox. 
  2854.  
  2855. Parameters 
  2856.  
  2857.    param1 
  2858.  
  2859.       ulReserved (ULONG) 
  2860.  
  2861.          Reserved, 0. 
  2862.  
  2863.    param2 
  2864.  
  2865.       ulReserved (ULONG) 
  2866.  
  2867.          Reserved, 0. 
  2868.  
  2869. Returns 
  2870.  
  2871.    reply 
  2872.  
  2873.       bSuccess (BOOL) 
  2874.  
  2875.          TRUE      successful completion 
  2876.          FALSE     error occurred 
  2877.  
  2878. Introduction to PM Programming - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2879.  
  2880.  
  2881. ΓòÉΓòÉΓòÉ 7.4. Notes and Next Month ΓòÉΓòÉΓòÉ
  2882.  
  2883. Notes and Next Month 
  2884.  
  2885. I do apologize for the snail's pace being taken in this column, but I do not 
  2886. want to overwhelm anyone by presenting too much information.  I have received 
  2887. little feedback and even though it was positive, the ether is too silent for me 
  2888. to think that I am doing everything correctly.  Please send me your comments 
  2889. about this column and any questions you might have about topics that I 
  2890. delicately skirt. 
  2891.  
  2892. Next month, we will begin looking at the WC_BUTTON class, specifically the 
  2893. pushbutton, and also will look at the ownerdraw window from both a listbox and 
  2894. a pushbutton perspective. 
  2895.  
  2896. Introduction to PM Programming - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2897.  
  2898.  
  2899. ΓòÉΓòÉΓòÉ 8. Scratch Patch ΓòÉΓòÉΓòÉ
  2900.  
  2901.  
  2902. ΓòÉΓòÉΓòÉ 8.1. Introduction ΓòÉΓòÉΓòÉ
  2903.  
  2904. Scratch Patch 
  2905.  
  2906. Written by Larry Salomon, Jr. 
  2907.  
  2908. Introduction 
  2909.  
  2910. Welcome to this month's "Scratch Patch"!  Each month, I collect various items 
  2911. that fit into this column sent to me via email. The ones that I feel contribute 
  2912. the most to developers, whether in terms of information or as a nifty trick to 
  2913. tuck into your cap, get published in this column. 
  2914.  
  2915. To submit an item, send it via email to my address - os2man@panix.com - and be 
  2916. sure to grant permission to publish it (those that forget will not be 
  2917. considered for publication). 
  2918.  
  2919. Scratch Patch - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2920.  
  2921.  
  2922. ΓòÉΓòÉΓòÉ 8.2. Gotcha Notes! ΓòÉΓòÉΓòÉ
  2923.  
  2924. Gotcha Notes! 
  2925.  
  2926. It appears that if you have the following: 
  2927.  
  2928. DosOpen("A:",...)
  2929.  
  2930. do {
  2931.    DosDevIOCtl(...,IOCTL_GETDEVICEPARAMS,...)
  2932.  
  2933.    ulSzDestDrive= ... ;
  2934.  
  2935.    if (ulSzSourceDrive!=ulSzDestDrive) promptUser(...);
  2936. } while (ulSzSourceDrive!=ulSzDestDrive);
  2937.  
  2938. If the user removes the diskette when prompted, the next call to DosDevIOCtl() 
  2939. will return ERROR_NOT_DOS_DISK even though the diskette is formatted.  The way 
  2940. around this is to close the drive and reopen using DosOpen(). 
  2941.  
  2942. Scratch Patch - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2943.  
  2944.  
  2945. ΓòÉΓòÉΓòÉ 8.3. Questions and Answers ΓòÉΓòÉΓòÉ
  2946.  
  2947. Questions and Answers 
  2948.  
  2949. James P Robertson (robertso@ecn.purdue.edu) writes: 
  2950.  
  2951. I was just wondering if there was an easy way to have a "tool bar".  A menu of 
  2952. buttons underneath the standard system menu.  I looked into value set controls, 
  2953. but I don't think that is what I am looking for.  It seems as though quite a 
  2954. few applications have this tool bar. 
  2955.  
  2956. Good question, with a complex answer.  There are actually two approaches to 
  2957. this problem: 
  2958.  
  2959.  1. You can create the tool bar on top of your client.  This has the advantage 
  2960.     of simplicity, but you must insure that the client never overlaps the tool 
  2961.     bar in the z-order. 
  2962.  
  2963.  2. You can create the tool bar as another frame control.  This has the 
  2964.     advantage of being cleaner, but it is more difficult to do correctly. 
  2965.  
  2966. To implement the first solution, you need to do a trick that was used by many 
  2967. wallpaper programs before better techniques were developed.  Intercept the 
  2968. WM_PAINT message in your client window procedure as always, but just before 
  2969. exiting the window procedure, call WinSetWindowPos() to change the z-order to 
  2970. HWND_BOTTOM. 
  2971.  
  2972. The second solution requires a bit more coding and lot more patience and 
  2973. involves a couple of steps. 
  2974.  
  2975.  1. Subclass the frame and intercept the WM_QUERYFRAMECTLCOUNT and 
  2976.     WM_FORMATFRAME. 
  2977.  2. For the former message, call the old frame window procedure, add 1 to the 
  2978.     result, and return this value.  This message is sent to query the number of 
  2979.     frame controls (system menu, titlebar, etc.).  The "+1" is for the tool 
  2980.     bar. 
  2981.  3. For the latter message, call the old frame window procedure, loop through 
  2982.     the array of SWP structures passed in mpParm1 and adjust the value of the 
  2983.     client window accordingly.  Use WinQueryWindowUShort() on the hwnd field of 
  2984.     the SWP structure and look for FID_CLIENT. 
  2985.  4. Insert your SWP values as the last item in the array. 
  2986.  
  2987. That should do it, but be patient.  The second method isn't exactly 
  2988. well-documented anywhere and there are snags which I have undoubtedly 
  2989. forgotten. 
  2990.  
  2991. Scratch Patch - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  2992.  
  2993.  
  2994. ΓòÉΓòÉΓòÉ 8.4. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
  2995.  
  2996. Snippet(s) of the Month 
  2997.  
  2998. Another, from my "library" of interesting functions which I use frequently. It 
  2999. can be found in scratch.zip. 
  3000.  
  3001. #include <os2.h>
  3002. #include <stdio.h>
  3003. #include <string.h>
  3004. #include <ctype.h>
  3005.  
  3006. SHORT EXPENTRY writeBinaryData(FILE *pfFile,PVOID pvBuf,USHORT usSzBuf)
  3007. //-------------------------------------------------------------------------
  3008. // This function writes the binary data in hexadecimal/ASCII format (a la
  3009. // Norton's disk editor) to the specified file.
  3010. //
  3011. // Input:  pfFile - points to the FILE structure
  3012. //         pvBuf - points to the data to be written
  3013. //         usSzBuf - specifies the size of the buffer pointed to by pvBuf
  3014. // Returns:  number of characters written if successful, -1 otherwise
  3015. //-------------------------------------------------------------------------
  3016. {
  3017.    USHORT usOffset;
  3018.    CHAR achChars[32];
  3019.    USHORT usLine;
  3020.  
  3021.    for (usOffset=0; usOffset<usSzBuf; usOffset+=16) {
  3022.       memset(achChars,0,sizeof(achChars));
  3023.       fprintf(pfFile,"  ");
  3024.  
  3025.       for (usLine=usOffset; usLine<usOffset+16; usLine++) {
  3026.          if (usLine<usSzBuf) {
  3027.             fprintf(pfFile,"%02X ",((PBYTE)pvBuf)[usLine]);
  3028.  
  3029.             if (isprint(((PCHAR)pvBuf)[usLine])) {
  3030.                achChars[usLine-usOffset]=((PCHAR)pvBuf)[usLine];
  3031.             } else {
  3032.                achChars[usLine-usOffset]='.';
  3033.             } /* endif */
  3034.          } else {
  3035.             fprintf(pfFile,"   ");
  3036.             achChars[usLine-usOffset]=' ';
  3037.          } /* endif */
  3038.       } /* endfor */
  3039.  
  3040.       fprintf(pfFile,"| %s\n",achChars);
  3041.    } /* endfor */
  3042.  
  3043.    fflush(pfFile);
  3044.    return usSzBuf;
  3045. }
  3046.  
  3047. Scratch Patch - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3048.  
  3049.  
  3050. ΓòÉΓòÉΓòÉ 8.5. Want Ads ΓòÉΓòÉΓòÉ
  3051.  
  3052. Want Ads 
  3053.  
  3054. Below are the hot topics as of this issue's writing.  Feel free to write on any 
  3055. of these. 
  3056.  
  3057. Workplace Shell Programming (hot) - given that Taligent has released a beta 
  3058. version of the application frameworks, we should all be scrambling to learn how 
  3059. to program WPS objects so that we can leapfrog into the next generation of 
  3060. operating systems when the technology is completely subsumed by current 
  3061. systems. 
  3062.  
  3063. Client/Server (hot) - using either named pipes (with or without a network) or 
  3064. sockets, client/server programming is all the rage these days.  On a related 
  3065. note, some people have also expressed an interest in learning about interfacing 
  3066. with the various protocol drivers (e.g.  NDIS, IPX/SPX, etc.).  Any articles in 
  3067. this area are most welcome. 
  3068.  
  3069. Multimedia (warm) - we recently had two articles on this topic.  However, they 
  3070. both dealt with sound, which we all know is not the only alternative media 
  3071. type.  Articles on anything else - MIDI, video, etc. - are needed. 
  3072.  
  3073. Graphics (warm) - using the Gpi is a complicated topic which can easily sport a 
  3074. number of articles (correlations, transformations, etc.).  I'm sure that this 
  3075. would be well received by the readers. 
  3076.  
  3077. Scratch Patch - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3078.  
  3079.  
  3080. ΓòÉΓòÉΓòÉ 9. Contributors to this Issue ΓòÉΓòÉΓòÉ
  3081.  
  3082. Are You a Potential Author? 
  3083.  
  3084. We are always looking for (new) authors.  If you have a topic about which you 
  3085. would like to write, send a brief description of the topic electronically to 
  3086. any of the editors, whose addresses are listed below, by the 15th of the month 
  3087. before the month in which your article will appear.  This alerts us that you 
  3088. will be sending an article so that we can plan the issue layout accordingly. 
  3089. After you have done this, get the latest copy of the Article Submission 
  3090. Guidelines  from ftp.cdrom.com  in the /pub/os2/2_x/program/newsltr directory. 
  3091. (the file is artsub.zip)  The completed text of your article should be sent to 
  3092. us no later than five days prior to the last day of the month; any articles 
  3093. received after that time may be pushed to the next issue. 
  3094.  
  3095. The editors can be reached at the following email addresses: 
  3096.  
  3097. o Larry Salomon - os2man@panix.com (Internet). 
  3098. o Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet). 
  3099.  
  3100. The following people contributed to this issue in one form or another (in 
  3101. alphabetical order): 
  3102.  
  3103. o Frank Matthijs 
  3104. o Larry Salomon, Jr. 
  3105. o Carsten Whimster 
  3106. o Gordon Zeglinski 
  3107. o Network distributors 
  3108.  
  3109. Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3110.  
  3111.  
  3112. ΓòÉΓòÉΓòÉ 9.1. Frank Matthijs ΓòÉΓòÉΓòÉ
  3113.  
  3114. Frank Matthijs 
  3115.  
  3116. Frank Matthijs received his Master's degree in Civil Engineering, Computer 
  3117. Science at the Katholieke Universiteit Leuven (Catholic University of Louvain, 
  3118. Belgium).  He is currently a PhD student at the same university, researching 
  3119. Input/Output frameworks for parallel/distributed systems.  He started 
  3120. programming in DOS using Pascal and Assembler, started using and programming 
  3121. OS/2 since version 2.0 and now uses C and C++ almost exclusively. 
  3122.  
  3123. He can be reached electronically on the Internet as 
  3124. Frank.Matthijs@cs.kuleuven.ac.be or frankm@cs.kuleuven.ac.be.  You may contact 
  3125. him for any reason. 
  3126.  
  3127. He can also be reached at the following address: 
  3128.  
  3129. Frank Matthijs
  3130. Windekindstraat 6
  3131. 1850 Grimbergen
  3132. Belgium
  3133.  
  3134. Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3135.  
  3136.  
  3137. ΓòÉΓòÉΓòÉ 9.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
  3138.  
  3139. Larry Salomon, Jr. 
  3140.  
  3141. Larry Salomon, Jr. wrote his first Presentation Manager application for OS/2 
  3142. version 1.1 in 1989.  Since that time, he has written numerous VIO and PM 
  3143. applications, including the Scramble applet included with OS/2 and the 
  3144. I-Brow/Magnify/Screen Capture trio being distributed by IBM with the 
  3145. Professional Developers Kit CD-ROM.  Currently, he works for Cheyenne Software 
  3146. in Roslyn, New York and resides in Bellerose, New York with his wife Lisa. 
  3147.  
  3148. Larry can be reached electronically via the Internet at os2man@panix.com. 
  3149.  
  3150. Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3151.  
  3152.  
  3153. ΓòÉΓòÉΓòÉ 9.3. Carsten Whimster ΓòÉΓòÉΓòÉ
  3154.  
  3155. Carsten Whimster 
  3156.  
  3157. Carsten is an undergraduate Computer Science student at the University of 
  3158. Waterloo, and an huge OS/2 enthusiast as of OS/2 2.0.  Currently, he is using 
  3159. OS/2 2.11 GA, and is waiting for the Warp II CD-ROM. 
  3160.  
  3161. He is currently in his third year, taking operating system, language, compiler, 
  3162. and graphics courses and enjoying it.  This fall he is working at the 
  3163. University of Waterloo as a tutor (course assistant) for CS241, an introductory 
  3164. course to compilers. 
  3165.  
  3166. Carsten is a beginning OS/2 PM programmer with a few projects on the go, and 
  3167. many more in his head.  He uses Watcom C/C++ 10.0, Watcom VX-REXX 2.0b, and 
  3168. occasionally emx08h with gcc 2.5.7.  Carsten is also a TEAM-OS/2 member. 
  3169.  
  3170. Carsten is the author of POVPanel, a shareware dashboard-like front-end for the 
  3171. POV-Ray 2.x compiler. 
  3172.  
  3173. You may reach Carsten... 
  3174.  
  3175. ...via email: 
  3176.  
  3177. bcrwhims@undergrad.math.uwaterloo.ca  - Internet 
  3178.  
  3179. ...via snail mail (notice the changed address): 
  3180.  
  3181. Carsten Whimster
  3182. 318 Spruce Street, front house
  3183. Waterloo, Ontario
  3184. Canada
  3185. N2L 3E7
  3186.  
  3187.  Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3188.  
  3189.  
  3190. ΓòÉΓòÉΓòÉ 9.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
  3191.  
  3192. Gordon Zeglinski 
  3193.  
  3194. Gordon Zeglinski is a freelance programmer/consultant who received his Master's 
  3195. degree in Mechanical Engineering with a thesis on C++ sparse matrix objects. 
  3196. He has been programming in C++ for 6 years and also has a strong background in 
  3197. FORTRAN.  He started developing OS/2 applications with version 2.0 . 
  3198.  
  3199. His current projects include a client/server communications program that 
  3200. utilitizes OS/2's features which has entered beta testing.  Additionally, he is 
  3201. involved in the development of a "real-time" automated vehicle based on OS/2 
  3202. and using C++ in which he does device driver development and designs the 
  3203. applications that comprise the control logic and user interface. 
  3204.  
  3205. He can be reached via the Internet at zeglins@cc.umanitoba.ca. 
  3206.  
  3207. Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3208.  
  3209.  
  3210. ΓòÉΓòÉΓòÉ 9.5. Network distributors ΓòÉΓòÉΓòÉ
  3211.  
  3212. Network Distributors 
  3213.  
  3214. These people are part of our distribution system to provide EDM/2 on networks 
  3215. other than the Internet.  Their help to provide access to this magazine for 
  3216. others is voluntary and we appreciate them a lot! 
  3217.  
  3218. o Paul Hethmon (hethmon@apac.ag.utk.edu) - Compuserve 
  3219. o Gess Shankar (gess@knex.mind.org) - Internet 
  3220. o David Singer (singer@almaden.ibm.com) - IBM Internal 
  3221. o Andre Asselin (ASSELIN AT RALVM12) - IBM Internal 
  3222.  
  3223. If you would like to become a "network distributor", be sure to contact the 
  3224. editors so that we can give you the credit you deserve! 
  3225.  
  3226. Contributors - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3227.  
  3228.  
  3229. ΓòÉΓòÉΓòÉ 10. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
  3230.  
  3231. How Do I Get EDM/2? 
  3232.  
  3233. EDM/2 can be obtained in any of the following ways: 
  3234.  
  3235. On the Internet 
  3236.  
  3237. o All back issues are available via anonymous FTP from the following sites: 
  3238.  
  3239.    - ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory. 
  3240.    - ftp.luth.se in the /pub/os2/programming/newsletter directory. 
  3241.    - generalhq.pc.cc.cmu.edu 
  3242.  
  3243. o The EDM/2 mailing list.  Send an empty message to edm2-info@knex.mind.org to 
  3244.   receive a file containing (among other things) instructions for subscribing 
  3245.   to EDM/2.  This is a UUCP connection, so be patient please. 
  3246. o IBM's external gopher/WWW server in Almaden. The address is 
  3247.   index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of the 
  3248.   "OS/2 Information" menu; the URL is 
  3249.   "gopher://index.almaden.ibm.com/1nonibm/os2nonib.70". 
  3250.  
  3251. On Compuserve 
  3252.  
  3253. All back issues are available in the OS/2 Developers Forum 2. 
  3254.  
  3255. IBM Internal 
  3256.  
  3257. o IBM's internal gopher/WWW server in Almaden. The address is 
  3258.   n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; the 
  3259.   URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70". 
  3260. o IBM's REQUEST command on all internal VM systems.  Enter the VM command 
  3261.   REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable packages 
  3262.   will be sent to you; in this list are the names of the packages containing 
  3263.   the EDM/2 issues. 
  3264.  
  3265. How do I Get EDM/2? - EDM/2 - Sept 1994 - Volume 2, Issue 8 
  3266.  
  3267.  
  3268. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3269.  
  3270. This is a tip. 
  3271.  
  3272.  
  3273. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3274.  
  3275. You must install the sample files before you can use them.  To do this, unzip 
  3276. the files for this article and type the following at any OS/2 prompt (in the 
  3277. directory where you unzipped the files): 
  3278.  
  3279. WPS INSTALL
  3280.  
  3281. When the program is running, you can specify a directory to install the samples 
  3282. in.  This will be your working directory for compiling the sample classes.  I 
  3283. suggest you assign a separate directory for this purpose. 
  3284.  
  3285. After successfully installing the files, you can use the WPS program in your 
  3286. working directory to ready the correct files for each step. 
  3287.  
  3288.  
  3289. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3290.  
  3291. The most natural thing to do with the first version of your class would be to 
  3292. give it version number 1.0, wouldn't it? 
  3293.  
  3294. Well, don't do that, because for some reason or another, SOM doesn't like 
  3295. version numbers to be equal to zero.  So you better use 1.1 as your first 
  3296. version number, because if you use zeroes, your class will not register.  In 
  3297. fact, the first attempt will only complete part of the registering process, 
  3298. while the second try will complete the process (try it to see for yourself). 
  3299.  
  3300.  
  3301. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3302.  
  3303. Even if you yourself don't use anything from the OS/2 API, you still have to 
  3304. include <os2.h> because most methods use types such as PSZ that are defined in 
  3305. the os2.h file.  You'll get compiler errors if you don't include this file. 
  3306.  
  3307.  
  3308. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3309.  
  3310. Before using the makefile, you should edit it to adapt it to your system. All 
  3311. specific information is contained in the first section called Specific 
  3312. settings.  There you will find the paths for the SOM compiler, the include 
  3313. files and the libraries.  Please alter these to reflect your own directory 
  3314. structure. 
  3315.  
  3316.  
  3317. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3318.  
  3319. You may have added the current directory (.) to your libpath.  Don't rely on 
  3320. this to work when registering WPS classes.  The system has its own current 
  3321. directory, and this will probably not be the one your DLL is in.  The result is 
  3322. the system will not be able to find your DLL and the registering process fails. 
  3323.  
  3324.  
  3325. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3326.  
  3327. After you've deregistered the class, you'll notice the DLL is still locked by 
  3328. the system and there still is a Datafile Deluxe template.  The next time you 
  3329. reboot, the DLL will be unlocked.  This is in fact very inconvenient, since you 
  3330. would have to reboot every time you want to register a new version of your 
  3331. class (you can't overwrite the old DLL when it is locked). 
  3332.  
  3333. Alas, there's not much you can do about this.  However, when you manage to 
  3334. delete the template, the DLL will also be unlocked.  Deleting the template is 
  3335. not as easy as it sounds, though.  Fortunately, a very nice WPS class called 
  3336. Black Hole, written by Gregory Czaja, will do the job nicely.  You can probably 
  3337. find this class where you found EDM/2. 
  3338.  
  3339. Note that you also have to delete all instances of the class in order to unlock 
  3340. the DLL.  In summary, I suggest you delete all instances, as well as the 
  3341. template, every time you've deregistered a class.  When you later change the 
  3342. code for that class, you'll have no problems copying your new DLL over the old 
  3343. one. 
  3344.  
  3345. This is the most convenient procedure I know (I used to kill PMSHELL.EXE before 
  3346. I found this one out :-) ). If you know a better way, please tell me!  It's not 
  3347. so bad, after all:  you have to get rid of the template yourself, anyway. 
  3348. Rebooting won't do this for you. 
  3349.  
  3350.  
  3351. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  3352.  
  3353. Feel free to experiment with the object we have created.  You can simply alter 
  3354. the resource file if you want to replace "Datafile Deluxe"  with something 
  3355. else.  There is one thing you should know about the way OS/2 handles types, 
  3356. however. 
  3357.  
  3358. OS/2 is very smart and can remember all types it has once known.  Isn't that 
  3359. nice?  Well, no!  Every new type you create will be added to the list of 
  3360. available types, but you cannot simply delete types you don't need anymore, 
  3361. using standard OS/2 utilities. 
  3362.  
  3363. The available types are stored in OS2.INI under the application name 
  3364. PMWP_ASSOC_TYPE.  For every possible type, this application name has a key 
  3365. name.  You'll have to use an INI editor or write a REXX script to delete the 
  3366. keys you no longer need.