home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 32 Periodic / 32-Periodic.zip / edmi2-6.zip / EDMI2-6.INF (.txt) < prev    next >
OS/2 Help File  |  1994-06-06  |  278KB  |  4,711 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. June 1994 Title Page ΓòÉΓòÉΓòÉ
  3.  
  4.           Welcome to EDM/2 - The Electronic OS/2 Developer's Magazine!
  5.                    Portions copyright (c) by Larry Salomon Jr.
  6.                                 Volume 2, issue 6
  7.  
  8. Copyright Notice and Other Stuff 
  9.  
  10. The Editor-in-Chief of this electronic magazine is Larry Salomon, Jr. 
  11.  
  12. Portions of EDM/2 are copyrighted by the editors.  This publication may be 
  13. freely distributed in electronic form provided that all parts are present in 
  14. their original unmodified form.  A reasonable fee may be charged for the 
  15. physical act of distribution; no fee may be charged for the publication itself. 
  16.  
  17. All articles are copyrighted by their authors. No part of any article may be 
  18. reproduced without permission from the original author. 
  19.  
  20. Neither this publication nor the editors are affiliated with International 
  21. Business Machines Corporation. 
  22.  
  23. OS/2 is a registered trademark of International Business Machines Corporation. 
  24. Other trademarks are property of their respective owners.  Any mention of a 
  25. product in this publication does not constitute an endorsement or affiliation 
  26. unless specifically stated in the text. 
  27.  
  28. Administrivia 
  29.  
  30. This month has been another hectic one.  After a couple of months, when 
  31. releasing a new issue meant around the 10th or so, I decided to get this one 
  32. out on time. 
  33.  
  34. You can see how well I did. 
  35.  
  36. At least one good thing has happened this past month:  we now have cable here 
  37. at our house, so my wife watches the Chinese channel (she's from the mainland) 
  38. instead of griping about how much time I spend on the computer. 
  39.  
  40. Seriously, there is a lot of stuff in this issue.  The Scratch Patch is teeming 
  41. with goodies for you to snatch up, and there is part 2 of the sprites series as 
  42. well as how to interpret and decompile resources from EXE and DLL files.  Great 
  43. stuff! 
  44.  
  45. Format Change 
  46.  
  47. In the quest to make EDM/2 easier to concatenate, Carsten suggested adding a 
  48. header to the beginning of each article and column, to show the title of the 
  49. article or column you are reading.  This inspired me to also add a footer at 
  50. the bottom of each section with the article/column/panel name, the date, and 
  51. the volume and issue number.  These have been done this issue; contact us to 
  52. let us know what you think about them. 
  53.  
  54. While I'm talking about him, let me publicly acknowledge the work 
  55. above-and-beyond the call of duty that Carsten has put into each issue.  The 
  56. quality, in my not-so-humble opinion, has gone up considerably since he started 
  57. catching my mistakes and those of the authors.  Thanks a lot for your hard 
  58. work! 
  59.  
  60. Conferences 
  61.  
  62. PC Expo is just around the corner.  If you plan to be in New York City, I'm 
  63. interested in meeting you.  Send me email.  Speaking of which, become more than 
  64. a Team OS/2 member; become more than an OS/2 Evangelist; become an EDM/2 
  65. Promoter.  If you go to a SIG that either has OS/2 as its reason for existence, 
  66. or is multi-platform oriented with development being the primary focus, let me 
  67. know; for the IBM PSP Conference, I drew some fliers that I handed out 
  68. throughout the week that I was there, and I can easily send you a PostScript 
  69. version of the flyer so that you can tell everyone about EDM/2 at your next 
  70. gathering. 
  71.  
  72. Title Page - EDM/2 - June 1994 - Volume 2, Issue 6 
  73.  
  74.  
  75. ΓòÉΓòÉΓòÉ 2. Features for June 1994 ΓòÉΓòÉΓòÉ
  76.  
  77. The following articles constitute this issue's features: 
  78.  
  79. o Sprites and Animation - Part 2 
  80. o Resources and Decompiling Them 
  81. o Visual REXX Faceoff 
  82.  
  83. Features - EDM/2 - June 1994 - Volume 2, Issue 6 
  84.  
  85.  
  86. ΓòÉΓòÉΓòÉ 2.1. Sprites and Animation - Part 2 ΓòÉΓòÉΓòÉ
  87.  
  88.  
  89. ΓòÉΓòÉΓòÉ 2.1.1. Introduction ΓòÉΓòÉΓòÉ
  90.  
  91. Sprites and Animation - Part 2 
  92.  
  93. Written by Larry Salomon, Jr. 
  94.  
  95. Introduction 
  96.  
  97. Last month, we took a good look at the beginnings of a sprite library that is 
  98. well-suited for simple animation.  We looked at: 
  99.  
  100. o how a sprite is drawn 
  101. o how the drawing of sprites requires a mask, which adds an extra burden on the 
  102.   management of the sprite data structure by the library 
  103. o how a sprite is moved in a manner that minimizes flicker 
  104.  
  105. But even discussing these things left some holes, namely the background and the 
  106. workarea that enables the flicker-free movement.  This month, we will wrap up 
  107. our discussion on the design of the library and will begin delving into the 
  108. code for the sprite library itself.  Next month's conclusion will look into the 
  109. intricacies of animating a set of sprites using the i495.exe sample as a 
  110. starting point. 
  111.  
  112. Ch-Ch-Ch-Changes 
  113.  
  114. Ah, there's nothing like quintessential Bowie... 
  115.  
  116. Since last month, I have integrated the sprite library into the Common/2 
  117. library that was on hobbes (if this new version isn't there already, wait for a 
  118. week and remind me if I still have forgotten). However, I have kept the 
  119. original version and have modified it to provide semaphore exclusion to the 
  120. data structures (actually, I surgically cut-n-pasted the related functions from 
  121. Common/2 <grin>), and it is this version that we will present in this series. 
  122. It should be noted, though, that the version in Common/2 does come complete 
  123. with an online reference. 
  124.  
  125. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  126.  
  127.  
  128. ΓòÉΓòÉΓòÉ 2.1.2. Monkey Bars and the Like ΓòÉΓòÉΓòÉ
  129.  
  130. Monkey Bars and the Like 
  131.  
  132. A distinguishing characteristic between a sprite and a bitmap is that the 
  133. former has a transparency color which means that whatever is below the sprite 
  134. shows through it.  If the background were simply a solid color, this could be 
  135. done through sleight-of-hand by drawing the bitmap with the background color in 
  136. the areas that are to be see-through.  Movement would be quite simple, reduced 
  137. to a few WinFillRect() calls and a single GpiWCBitBlt(). 
  138.  
  139. Unfortunately, a sprite can make no assumptions about the underlying surface: 
  140. it could be a solid color or it could be a complex drawing or it even could be 
  141. another sprite.  Worse yet, we cannot simply take what is already on the 
  142. screen, for what shall we restore there if - for example - the sprite has its 
  143. visibility state set to FALSE? 
  144.  
  145. Because of this (and other reasons), we need to maintain yet another data 
  146. structure which will, among other things, manage a static bitmap to be used for 
  147. the background; we will call it a playground since it is the area in which we 
  148. will let the sprites play.  Conceptually, a playground is the "blackboard" 
  149. while each sprite is just a chalk drawing on the blackboard, so all drawing 
  150. related functions are considered to be associated with a playground instead of 
  151. the sprites that occupy a playground. 
  152.  
  153. The playground support must provide the following functions: 
  154.  
  155. o Create a playground 
  156. o Destroy a playground 
  157. o Add a sprite to the playground 
  158. o Remove a sprite from the playground 
  159. o Draw the entire playground 
  160.  
  161. Adding and removing sprites from the playground is needed so that we can access 
  162. data structures in the playground given the sprite handle.  For example, only 
  163. one work area is needed per playground since one thread at most can access an 
  164. HPS, so we put the work area in the playground, but need to access this work 
  165. area from each sprite. 
  166.  
  167. Drawing a playground involves drawing the background and then looping through 
  168. its membership list to draw each sprite at its current position.  This is 
  169. intended to provide a simple method of processing the WM_PAINT message within 
  170. an application. 
  171.  
  172. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  173.  
  174. If all of these design issues get confusing, remember that I have the power of 
  175. hindsight and you do not, so do not get dismayed or (worse yet) think that I 
  176. have some divine capability to think of these things before writing a line of 
  177. code; I had the same trial-n-error development process that you would have were 
  178. our places exchanged. 
  179.  
  180. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  181.  
  182.  
  183. ΓòÉΓòÉΓòÉ 2.1.3. Final Design Considerations ΓòÉΓòÉΓòÉ
  184.  
  185. Final Design Considerations 
  186.  
  187. In even the most elementary computer programming classes, the concept of code 
  188. reuse is hammered into the brains of the students; here, this concept is 
  189. stressed as well.  There are many code blocks that are needed in various places 
  190. throughout the library, so these code blocks were turned into functions. 
  191.  
  192. Mutually exclusive access to the data structures is also an important part of 
  193. any good library, and it is implemented here through the use of a mutex 
  194. sempahore and a status flag; the status flag indicates if access has already 
  195. been granted to a function, i.e. if a function calls another function, the 
  196. called function will deadlock if it requests the semaphore.  The 
  197. access-granting function is accessSem(), and it would be worth the time to 
  198. understand how this is implemented to avoid confusion later. 
  199.  
  200. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  201.  
  202.  
  203. ΓòÉΓòÉΓòÉ 2.1.4. Where's Your Library Card? ΓòÉΓòÉΓòÉ
  204.  
  205. Where's Your Library Card? 
  206.  
  207. Since utilitizing the library involves far more complex coding than the code 
  208. for the library itself (did I ever say that animation was easy?), we will look 
  209. at the library itself.  If you have not already done so, unzip the source.zip 
  210. file and take a look at the files within. 
  211.  
  212. MAKEFILE            the makefile for the library 
  213.  
  214. SPRITE.C            the source file 
  215.  
  216. SPRITE.HPP          the .H preprocessor file.  This is fed to HEADER.EXE which 
  217.                     generates an implementor's .H file and a user's .H file. 
  218.                     You should change the first two lines of this file so that 
  219.                     the paths make sense. 
  220.  
  221.                                         //@HEADER OUTFILE INT D:\SOURCE\SPRITE\SPRITE.H
  222.                                         //@HEADER OUTFILE EXT D:\MYINC\SPRITE.H
  223.  
  224.                     The INT line defines the file name of the "internal" use .H 
  225.                     file, while the EXT line defines the file name of the 
  226.                     "external" use .H file. 
  227.  
  228. SPRITE.H            Generated by the command "HEADER -tINT SPRITE.HPP" 
  229.  
  230. SPRITE.OBJ          Object file 
  231.  
  232. SPRITE.LIB          Library file 
  233.  
  234. HEADER.EXE          Header file preprocessor.  I think I have placed this on 
  235.                     hobbes, possibly under the name HPREP.  If not, this is an 
  236.                     older version, but it will do. (I keep forgetting to bring 
  237.                     the newer version in to work.) 
  238.  
  239. Before we can begin to understand the code, we must first understand the data 
  240. structures on which the code operates, so we first look at the playground: 
  241.  
  242. typedef struct _PLAYGROUND {
  243.    ULONG ulSig;
  244.    ULONG ulStatus;
  245.    HMTX hsmAccess;
  246.  
  247.    HAB habAnchor;
  248.    HDC hdcWork;
  249.    HPS hpsWork;
  250.    HBITMAP hbmWork;
  251.  
  252.    HBITMAP hbmBack;
  253.    BITMAPINFOHEADER2 bmihBack;
  254.    LONG lBackColor;
  255.  
  256.    BOOL bUpdate;
  257.  
  258.    HSPRITE ahsSprites[MAX_SPRITES];
  259.    ULONG ulNumMembers;
  260. } PLAYGROUND, *HPLAYGROUND;
  261. typedef HPLAYGROUND *PHPLAYGROUND;
  262.  
  263. ulSig               4-byte signature for the data structure, used for parameter 
  264.                     validation. 
  265.  
  266. ulStatus            32-bit status flags used for semaphore access at this time. 
  267.  
  268. hsmAccess           mutex (mutual exclusion) semaphore handle. 
  269.  
  270. habAnchor           anchor block handle of the calling thread. 
  271.  
  272. hdcWork             OD_MEMORY device context handle for the work area. 
  273.  
  274. hpsWork             presentation space handle associated with hdcWork. 
  275.  
  276. hbmWork             bitmap handle set into hpsWork. 
  277.  
  278. hbmBack             bitmap handle for the background bitmap.  If NULLHANDLE, 
  279.                     the playground has a background color instead (lBackColor). 
  280.  
  281. bmihBack            bitmap information header for hbmBack.  If hbmBack is 
  282.                     NULLHANDLE, the cx and cy fields indicate the size of the 
  283.                     playground; otherwise the size of the playground is 
  284.                     specified by the size of the background bitmap. 
  285.  
  286. lBackColor          the background color of the playground, if hbmBack is 
  287.                     NULLHANDLE. 
  288.  
  289. bUpdate             update flag.  If FALSE, no drawing is actually performed. 
  290.                     This is useful for changing sprites in place. 
  291.  
  292. ahsSprites          array of sprite handles comprising the membership list. 
  293.  
  294. ulNumMembers        current number of members. 
  295.  
  296. We will see how these fields are used when we look at the code.  But now, we 
  297. will look at the sprite structure: 
  298.  
  299. typedef struct _SPRITE {
  300.    ULONG ulSig;
  301.    ULONG ulStatus;
  302.    HMTX hsmAccess;
  303.  
  304.    HAB habAnchor;
  305.    HBITMAP hbmBitmap;
  306.    HBITMAP hbmMask;
  307.    BITMAPINFOHEADER2 bmihBitmap;
  308.    BITMAPINFOHEADER2 bmihMask;
  309.  
  310.    struct _PLAYGROUND *hpgPlay;
  311.    POINTL ptlPos;
  312.    BOOL bVisible;
  313. } SPRITE, *HSPRITE;
  314. typedef HSPRITE *PHSPRITE;
  315.  
  316. ulSig               4-byte signature for the data structure, used for parameter 
  317.                     validation. 
  318.  
  319. ulStatus            32-bit status flags used for semaphore access at this time. 
  320.  
  321. hsmAccess           mutex (mutual exclusion) semaphore handle. 
  322.  
  323. habAnchor           anchor block handle of the calling thread. 
  324.  
  325. hbmBitmap           bitmap handle which defines the sprite. 
  326.  
  327. hbmMask             bitmap handle which defines the mask. 
  328.  
  329. bmihBitmap          bitmap information header for hbmBitmap. 
  330.  
  331. bmihMask            bitmap information header for hbmMask. 
  332.  
  333. hpgPlay             playground handle of which the sprite is a member. 
  334.  
  335. ptlPos              current position. 
  336.  
  337. bVisible            current visibility state. 
  338.  
  339. A comment on the list of exposed functions below:  notice the symmetry of the 
  340. function names.  For each create, there is a destroy; querys have corresponding 
  341. sets when appropriate; the add has a remove.  While much is often said about 
  342. intuitiveness of the user-interface, the same concepts along with the 
  343. advantages gained can be applied to the "programmer-interface".  The 
  344. non-exposed (internal) functions, obviously, do not need to follow this 
  345. guideline, although it does help if more than one person is developing and/or 
  346. maintaining the code. 
  347.  
  348. Each function below is a hypertext link to its code and the explanation of the 
  349. code; feel free to explore the functions in any order. 
  350.  
  351. Internal Functions 
  352.  
  353. o accessSem 
  354. o clipBltPoints 
  355. o drawSpriteAt 
  356. o drawBackAt 
  357. o getMemHps 
  358. o queryHandleType 
  359.  
  360. External Functions 
  361.  
  362. o SprAddSprite 
  363. o SprCreatePlayground 
  364. o SprCreateSprite 
  365. o SprDestroyPlayground 
  366. o SprDestroySprite 
  367. o SprDrawPlayground 
  368. o SprDrawSprite 
  369. o SprQueryPlaygroundBack 
  370. o SprQueryPlaygroundColor 
  371. o SprQueryPlaygroundSize 
  372. o SprQuerySpritePosition 
  373. o SprQuerySpriteRect 
  374. o SprQuerySpriteSize 
  375. o SprQuerySpriteVisibility 
  376. o SprQueryUpdateFlag 
  377. o SprRemoveSprite 
  378. o SprSetPlaygroundBack 
  379. o SprSetPlaygroundColor 
  380. o SprSetPlaygroundSize 
  381. o SprSetSpritePosition 
  382. o SprSetSpriteVisibility 
  383. o SprSetUpdateFlag 
  384.  
  385. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  386.  
  387.  
  388. ΓòÉΓòÉΓòÉ 2.1.5. Summary ΓòÉΓòÉΓòÉ
  389.  
  390. Summary 
  391.  
  392. This month, we finished our discussion of the design of the sprite library by 
  393. describing the need for a master data structure called the playground, and the 
  394. code to implement the library routines was presented to illustrate the concepts 
  395. that we have already learned in our discussions up to this point.  Next month, 
  396. we will take these underpinings and will apply them to the i495.exe application 
  397. to see how they can be utililized to perform rudimentary animation. 
  398.  
  399. All comments, suggestions, bugs, etc. are welcome c/o the author. 
  400.  
  401. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  402.  
  403.  
  404. ΓòÉΓòÉΓòÉ <hidden> queryHandleType ΓòÉΓòÉΓòÉ
  405.  
  406. queryHandleType 
  407.  
  408. The purpose of this function is parameter validation, and uses the ulSig field 
  409. of both data structures.  Note that for non-accessible memory pointers, this 
  410. function will still cause the application to trap (although it is possible to 
  411. check for NULL). 
  412.  
  413. static ULONG queryHandleType(PVOID pvHandle)
  414. //-------------------------------------------------------------------------
  415. // This function returns a QH_* constant specifying the handle type.  It
  416. // will be replaced by CmnQueryHandle() when this subsystem is integrated
  417. // into Common/2.
  418. //
  419. // Input:  pvHandle - points the the handle to query
  420. // Returns:   QH_ERROR if error, QH_* constant otherwise
  421. //-------------------------------------------------------------------------
  422. {
  423.    if (pvHandle==NULL) {
  424.       return QH_ERROR;
  425.    } /* endif */
  426.  
  427.    switch (((PHEADER)pvHandle)->ulSig) {
  428.    case SIG_HSPRITE:
  429.       return QH_HSPRITE;
  430.    case SIG_HPLAYGROUND:
  431.       return QH_HPLAYGROUND;
  432.    default:
  433.       return QH_ERROR;
  434.    } /* endswitch */
  435. }
  436.  
  437. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  438.  
  439.  
  440. ΓòÉΓòÉΓòÉ <hidden> accessSem ΓòÉΓòÉΓòÉ
  441.  
  442. accessSem 
  443.  
  444. The purpose of this function is to provide mutually exclusive access to the 
  445. data structures used by the library.  By requiring that all data structures 
  446. have a common set of fields defined first (semaphore handle, etc.), we can cast 
  447. the data structures to the type PHANDLE to allow us access to the common 
  448. fields. 
  449.  
  450. static USHORT accessSem(PHEADER phHandle,USHORT usAction)
  451. //-------------------------------------------------------------------------
  452. // This function provides semaphore access for mutual exclusion of private
  453. // data access.
  454. //
  455. // Input:  phHandle - points to the handle header
  456. //         usAction - specifies the action to perform:
  457. //            ACCSEM_SET - requests access to the handle
  458. //            ACCSEM_CLEAR - relinquishes access to the handle
  459. //            ACCSEM_ALREADYSET - not used
  460. //            ACCSEM_NOTSET - not used
  461. // Returns:  ACCSEM_ERROR if an error occurred, else the action to take
  462. //           on the next call to this function
  463. //-------------------------------------------------------------------------
  464. {
  465.    switch (usAction) {
  466.    case ACCSEM_SET:
  467.       if ((phHandle->ulStatus & HSTATUS_INLIBRARY)!=0) {
  468.          return ACCSEM_ALREADYSET;
  469.       } /* endif */
  470.  
  471.       DosRequestMutexSem(phHandle->hsmAccess,SEM_INDEFINITE_WAIT);
  472.       phHandle->ulStatus|=HSTATUS_INLIBRARY;
  473.       return ACCSEM_CLEAR;
  474.    case ACCSEM_CLEAR:
  475.       if ((phHandle->ulStatus & HSTATUS_INLIBRARY)==0) {
  476.          return ACCSEM_NOTSET;
  477.       } /* endif */
  478.  
  479.       DosReleaseMutexSem(phHandle->hsmAccess);
  480.       phHandle->ulStatus&=~HSTATUS_INLIBRARY;
  481.       return ACCSEM_SET;
  482.    case ACCSEM_ALREADYSET:
  483.       return ACCSEM_NOTSET;
  484.    case ACCSEM_NOTSET:
  485.       return ACCSEM_ALREADYSET;
  486.    default:
  487.       return ACCSEM_ERROR;
  488.    } /* endswitch */
  489. }
  490.  
  491. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  492.  
  493.  
  494. ΓòÉΓòÉΓòÉ <hidden> getMemHps ΓòÉΓòÉΓòÉ
  495.  
  496. getMemHps 
  497.  
  498. There is nothing special about this function that needs to be noted. 
  499.  
  500. static HPS getMemHps(HAB habAnchor)
  501. //-------------------------------------------------------------------------
  502. // This function creates an HPS associated with a memory HDC.  The
  503. // HDC handle can be retrieved using the GpiQueryDevice() function.
  504. //
  505. // Input:  habAnchor - anchor block of the calling thread.
  506. // Returns:  HPS handle if successful, NULLHANDLE otherwise
  507. //-------------------------------------------------------------------------
  508. {
  509.    HDC hdcMem;
  510.    SIZEL szlHps;
  511.    HPS hpsMem;
  512.  
  513.    hdcMem=DevOpenDC(habAnchor,OD_MEMORY,"*",0,NULL,NULLHANDLE);
  514.    if (hdcMem==NULLHANDLE) {
  515.       return NULLHANDLE;
  516.    } /* endif */
  517.  
  518.    szlHps.cx=0;
  519.    szlHps.cy=0;
  520.  
  521.    hpsMem=GpiCreatePS(habAnchor,
  522.                       hdcMem,
  523.                       &szlHps,
  524.                       PU_PELS|GPIT_MICRO|GPIA_ASSOC);
  525.    if (hpsMem==NULLHANDLE) {
  526.       DevCloseDC(hdcMem);
  527.    } /* endif */
  528.  
  529.    return hpsMem;
  530. }
  531.  
  532. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  533.  
  534.  
  535. ΓòÉΓòÉΓòÉ <hidden> clipBltPoints ΓòÉΓòÉΓòÉ
  536.  
  537. clipBltPoints 
  538.  
  539. The library clips all drawing to the playground size.  (A future enhancement to 
  540. the library would be to allow the application to specify where in a window the 
  541. lower-left corner of the playground should be.)  This function clips a pair of 
  542. rectangles (which are defined by a pair of points, meaning that we have four 
  543. points total) to a rectangle defined to be (0,0)-(pszlPlay->cx,pszlPlay->cy). 
  544.  
  545. You can see the clipping effect by enlarging the size of the i495 window. 
  546.  
  547. static BOOL clipBltPoints(HAB habAnchor,PPOINTL pptlArray,PSIZEL pszlPlay)
  548. //-------------------------------------------------------------------------
  549. // This function clips the first two points in pptlArray to a rectangle
  550. // of size pszlPlay.  The last two points in pptlArray are then adjusted
  551. // by the amount clipped.
  552. //
  553. // It is assumed that the first two points refer to a coordinate space
  554. // of size pszlPlay and that the two rectangles formed by the first and
  555. // last pair of points in pptlArray are of the same size.
  556. //
  557. // Input:  habAnchor - anchor block of the calling thread.
  558. //         pptlArray - points to array of 4 points for GpiBitBlt()
  559. //         pszlPlay - points to the size of the playground to clip to
  560. // Output:  pptlArray - points to adjusted array
  561. // Returns:  TRUE if at least one pel was *not* clipped, FALSE if all
  562. //           points fell outside of the clipping region.
  563. //-------------------------------------------------------------------------
  564. {
  565.    RECTL rclPlay;
  566.    RECTL rclDest;
  567.    RECTL rclInter;
  568.    RECTL rclDelta;
  569.  
  570.    rclPlay.xLeft=0;
  571.    rclPlay.yBottom=0;
  572.    rclPlay.xRight=pszlPlay->cx-1;
  573.    rclPlay.yTop=pszlPlay->cy-1;
  574.  
  575.    rclDest.xLeft=pptlArray[0].x;
  576.    rclDest.yBottom=pptlArray[0].y;
  577.    rclDest.xRight=pptlArray[1].x;
  578.    rclDest.yTop=pptlArray[1].y;
  579.  
  580.    WinIntersectRect(habAnchor,&rclInter,&rclPlay,&rclDest);
  581.  
  582.    //----------------------------------------------------------------------
  583.    // If the result is an empty rectangle, return FALSE to indicate so.
  584.    //----------------------------------------------------------------------
  585.    if (WinIsRectEmpty(habAnchor,&rclInter)) {
  586.       return FALSE;
  587.    } /* endif */
  588.  
  589.    rclDelta.xLeft=rclDest.xLeft-rclInter.xLeft;
  590.    rclDelta.yBottom=rclDest.yBottom-rclInter.yBottom;
  591.    rclDelta.xRight=rclDest.xRight-rclInter.xRight;
  592.    rclDelta.yTop=rclDest.yTop-rclInter.yTop;
  593.  
  594.    pptlArray[0].x-=rclDelta.xLeft;
  595.    pptlArray[0].y-=rclDelta.yBottom;
  596.    pptlArray[1].x-=rclDelta.xRight;
  597.    pptlArray[1].y-=rclDelta.yTop;
  598.    pptlArray[2].x-=rclDelta.xLeft;
  599.    pptlArray[2].y-=rclDelta.yBottom;
  600.    pptlArray[3].x-=rclDelta.xRight;
  601.    pptlArray[3].y-=rclDelta.yTop;
  602.    return TRUE;
  603. }
  604.  
  605. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  606.  
  607.  
  608. ΓòÉΓòÉΓòÉ <hidden> drawSpriteAt ΓòÉΓòÉΓòÉ
  609.  
  610. drawSpriteAt 
  611.  
  612. This function draws a sprite at the specified position; it calls 
  613. clipBltPoints() to insure that all necessary clipping is performed. An 
  614. advantage of having this as a function is that the transition to z-order 
  615. implementation is eased somewhat.  It is because of this that the background is 
  616. not drawn in this function, but is removed to its own function - drawBackAt(). 
  617.  
  618. static BOOL drawSpriteAt(HPS hpsDraw,
  619.                          HSPRITE hsSprite,
  620.                          PSIZEL pszlSize,
  621.                          PPOINTL pptlPos)
  622. //-------------------------------------------------------------------------
  623. // This function draws the sprite at the specified position.  It is assumed
  624. // that the background has already been drawn into hpsDraw before this
  625. // function is called.
  626. //
  627. // Input:  hpsDraw - handle of the presentation space to draw in
  628. //         hsSprite - handle of the sprite to draw
  629. //         pszlSize - points to the size of hpsDraw.  If NULL, the size
  630. //                    of the playground is used.
  631. //         pptlPos - points to the point specifying the position.  If
  632. //                   NULL, the sprite's current position is used.
  633. // Returns:  TRUE if successful, FALSE otherwise
  634. //-------------------------------------------------------------------------
  635. {
  636.    POINTL ptlUse;
  637.    SIZEL szlUse;
  638.    POINTL aptlPoints[4];
  639.  
  640.    if (!hsSprite->hpgPlay->bUpdate) {
  641.       return TRUE;
  642.    } /* endif */
  643.  
  644.    //----------------------------------------------------------------------
  645.    // Initialize the local variables with either what was passed in or
  646.    // the defaults as noted above in the function prologue
  647.    //----------------------------------------------------------------------
  648.    if (pptlPos==NULL) {
  649.       ptlUse=hsSprite->ptlPos;
  650.    } else {
  651.       ptlUse=*pptlPos;
  652.    } /* endif */
  653.  
  654.    if (pszlSize==NULL) {
  655.       SprQueryPlaygroundSize(hsSprite->hpgPlay,&szlUse);
  656.    } else {
  657.       szlUse=*pszlSize;
  658.    } /* endif */
  659.  
  660.    aptlPoints[0].x=ptlUse.x;
  661.    aptlPoints[0].y=ptlUse.y;
  662.    aptlPoints[1].x=aptlPoints[0].x+hsSprite->bmihMask.cx-1;
  663.    aptlPoints[1].y=aptlPoints[0].y+hsSprite->bmihMask.cy-1;
  664.    aptlPoints[2].x=0;
  665.    aptlPoints[2].y=0;
  666.    aptlPoints[3].x=aptlPoints[2].x+hsSprite->bmihMask.cx;
  667.    aptlPoints[3].y=aptlPoints[2].y+hsSprite->bmihMask.cy;
  668.  
  669.    if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlUse)) {
  670.       //-------------------------------------------------------------------
  671.       // Blit the mask and then the bitmap
  672.       //-------------------------------------------------------------------
  673.       GpiWCBitBlt(hpsDraw,
  674.                   hsSprite->hbmMask,
  675.                   4,
  676.                   aptlPoints,
  677.                   ROP_SRCAND,
  678.                   BBO_IGNORE);
  679.  
  680.       GpiWCBitBlt(hpsDraw,
  681.                   hsSprite->hbmBitmap,
  682.                   4,
  683.                   aptlPoints,
  684.                   ROP_SRCPAINT,
  685.                   BBO_IGNORE);
  686.    } /* endif */
  687.  
  688.    return TRUE;
  689. }
  690.  
  691. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  692.  
  693.  
  694. ΓòÉΓòÉΓòÉ <hidden> drawBackAt ΓòÉΓòÉΓòÉ
  695.  
  696. drawBackAt 
  697.  
  698. This function draws the background at the specified position with the specified 
  699. size.  This is used to copy the background onto the display as well as into the 
  700. work area as needed.  Notice that this is where background coloring is done if 
  701. a background bitmap was not specified. 
  702.  
  703. static BOOL drawBackAt(HPS hpsDraw,
  704.                        HPLAYGROUND hpgPlay,
  705.                        PRECTL prclDest,
  706.                        PSIZEL pszlDest,
  707.                        PRECTL prclSrc)
  708. //-------------------------------------------------------------------------
  709. // This function draws the background in the specified presentation space.
  710. //
  711. // Input:  hpsDraw - handle of the presentation space to draw in
  712. //         hpgPlay - handle of the playground containing the background
  713. //         prclDest - points to the destination rectangle.  If NULL, the
  714. //                    value of prclSrc is used.
  715. //         pszlDest - points to the size of hpsDraw.  If NULL, the size of
  716. //                    the playground is used.
  717. //         prclSrc - points to the source rectangle.  If NULL, the entire
  718. //                   background is painted.
  719. // Returns:  TRUE if successful, FALSE otherwise
  720. //-------------------------------------------------------------------------
  721. {
  722.    RECTL rclUseSrc;
  723.    RECTL rclUseDest;
  724.    SIZEL szlUse;
  725.    POINTL aptlPoints[4];
  726.  
  727.    if (!hpgPlay->bUpdate) {
  728.       return TRUE;
  729.    } /* endif */
  730.  
  731.    if (prclSrc==NULL) {
  732.       rclUseSrc.xLeft=0;
  733.       rclUseSrc.yBottom=0;
  734.       rclUseSrc.xRight=hpgPlay->bmihBack.cx;
  735.       rclUseSrc.yTop=hpgPlay->bmihBack.cy;
  736.    } else {
  737.       rclUseSrc=*prclSrc;
  738.    } /* endif */
  739.  
  740.    if (prclDest==NULL) {
  741.       rclUseDest=rclUseSrc;
  742.       rclUseDest.xRight--;
  743.       rclUseDest.yTop--;
  744.    } else {
  745.       rclUseDest=*prclDest;
  746.    } /* endif */
  747.  
  748.    if (pszlDest==NULL) {
  749.       szlUse.cx=hpgPlay->bmihBack.cx;
  750.       szlUse.cy=hpgPlay->bmihBack.cy;
  751.    } else {
  752.       szlUse=*pszlDest;
  753.    } /* endif */
  754.  
  755.    aptlPoints[0].x=rclUseDest.xLeft;
  756.    aptlPoints[0].y=rclUseDest.yBottom;
  757.    aptlPoints[1].x=rclUseDest.xRight;
  758.    aptlPoints[1].y=rclUseDest.yTop;
  759.    aptlPoints[2].x=rclUseSrc.xLeft;
  760.    aptlPoints[2].y=rclUseSrc.yBottom;
  761.    aptlPoints[3].x=rclUseSrc.xRight;
  762.    aptlPoints[3].y=rclUseSrc.yTop;
  763.  
  764.    if (clipBltPoints(hpgPlay->habAnchor,aptlPoints,&szlUse)) {
  765.       //-------------------------------------------------------------------
  766.       // If there is a background bitmap, blit it, otherwise black out the
  767.       // area.
  768.       //-------------------------------------------------------------------
  769.       if (hpgPlay->hbmBack!=NULLHANDLE) {
  770.          GpiWCBitBlt(hpsDraw,
  771.                      hpgPlay->hbmBack,
  772.                      4,
  773.                      aptlPoints,
  774.                      ROP_SRCCOPY,
  775.                      BBO_IGNORE);
  776.       } else {
  777.          //----------------------------------------------------------------
  778.          // WinFillRect() excludes the top and right of the rectangle
  779.          //----------------------------------------------------------------
  780.          rclUseDest.xRight++;
  781.          rclUseDest.yTop++;
  782.          WinFillRect(hpsDraw,&rclUseDest,hpgPlay->lBackColor);
  783.       } /* endif */
  784.    } /* endif */
  785.  
  786.    return TRUE;
  787. }
  788.  
  789. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  790.  
  791.  
  792. ΓòÉΓòÉΓòÉ <hidden> SprAddSprite ΓòÉΓòÉΓòÉ
  793.  
  794. SprAddSprite 
  795.  
  796. This function adds a sprite handle to the end of the ahsSprites array within 
  797. the HPLAYGROUND structure.  By insuring - in SprRemoveSprite() - that the array 
  798. is always compact, we save a test for NULL in the SprDrawPlayground() loop. 
  799. Note that there are no functions for modifying the order of the sprite within 
  800. the array, because as of now there is no need.  However, once z-ordering is 
  801. added to the library, another function - SprSetLayer() - will be added to set 
  802. the sprite's position to the top, bottom, previous, or next position in the 
  803. z-order stack. 
  804.  
  805. SPRERROR EXPENTRY SprAddSprite(HPLAYGROUND hpgPlay,HSPRITE hsSprite)
  806. //-------------------------------------------------------------------------
  807. // This function labels a sprite as a "member" of the specified playground.
  808. // Doing so allows the application to control the sprite's position,
  809. // visibility, etc. on a drawing surface.
  810. //
  811. // Input:  hpgPlay - handle to the playground
  812. //         hsSprite - handle to the sprite to add
  813. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  814. //-------------------------------------------------------------------------
  815. {
  816.    USHORT usAction;
  817.  
  818.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  819.       return SPR_ERR_BADHANDLE;
  820.    } else
  821.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  822.       return SPR_ERR_BADHANDLE;
  823.    } /* endif */
  824.  
  825.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  826.  
  827.    if (hsSprite->hpgPlay!=NULL) {
  828.       accessSem((PHEADER)hpgPlay,usAction);
  829.       return SPR_ERR_HASPLAYGROUND;
  830.    } else
  831.    if (hpgPlay->ulNumMembers==MAX_SPRITES) {
  832.       accessSem((PHEADER)hpgPlay,usAction);
  833.       return SPR_ERR_PLAYGROUNDFULL;
  834.    } /* endif */
  835.  
  836.    hpgPlay->ahsSprites[hpgPlay->ulNumMembers]=hsSprite;
  837.    hpgPlay->ulNumMembers++;
  838.  
  839.    hsSprite->hpgPlay=hpgPlay;
  840.  
  841.    accessSem((PHEADER)hpgPlay,usAction);
  842.    return SPR_ERR_NOERROR;
  843. }
  844.  
  845. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  846.  
  847.  
  848. ΓòÉΓòÉΓòÉ <hidden> SprCreatePlayground ΓòÉΓòÉΓòÉ
  849.  
  850. SprCreatePlayground 
  851.  
  852. Note the use of calloc().  Using any of the C runtime is not a good thing 
  853. because it is implemented (usually) using suballocation, meaning an application 
  854. can accidentally increment hpgPlay by 2 bytes (for example) and would not get a 
  855. trap notification by OS/2; instead unpredictable behavior would occur, which 
  856. misleads the developer into thinking a stack error is occuring.  It would be 
  857. better to use DosAllocMem() instead. 
  858.  
  859. SPRERROR EXPENTRY SprCreatePlayground(HAB habAnchor,PHPLAYGROUND phpgPlay)
  860. //-------------------------------------------------------------------------
  861. // This function creates a playground to which sprites can be added.
  862. //
  863. // Input:  habAnchor - anchor block of the calling thread.
  864. // Output:  phpgPlay - points to the variable with the HPLAYGROUND handle
  865. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  866. //-------------------------------------------------------------------------
  867. {
  868.    BITMAPINFOHEADER2 bmihInfo;
  869.    LONG lValue;
  870.  
  871.    *phpgPlay=calloc(1,sizeof(PLAYGROUND));
  872.    if (*phpgPlay==NULL) {
  873.       *phpgPlay=NULL;
  874.       return SPR_ERR_NOMEMORY;
  875.    } /* endif */
  876.  
  877.    (*phpgPlay)->ulSig=SIG_HPLAYGROUND;
  878.    (*phpgPlay)->ulStatus=0;
  879.  
  880.    if (DosCreateMutexSem(NULL,&(*phpgPlay)->hsmAccess,0,FALSE)) {
  881.       free(*phpgPlay);
  882.       return SPR_ERR_RESOURCE;
  883.    } /* endif */
  884.  
  885.    (*phpgPlay)->habAnchor=habAnchor;
  886.  
  887.    (*phpgPlay)->hpsWork=getMemHps(habAnchor);
  888.    if ((*phpgPlay)->hpsWork==NULLHANDLE) {
  889.       free(*phpgPlay);
  890.       *phpgPlay=NULL;
  891.       return SPR_ERR_RESOURCE;
  892.    } /* endif */
  893.  
  894.    (*phpgPlay)->hdcWork=GpiQueryDevice((*phpgPlay)->hpsWork);
  895.  
  896. Since the workarea is used for moving sprites with position overlap, the size 
  897. of the bitmap to be set in the HPS is (MAX_SPRITE_CX*2,MAX_SPRITE_CY*2). 
  898.  
  899.    bmihInfo.cbFix=16;
  900.    bmihInfo.cx=MAX_SPRITE_CX*2;
  901.    bmihInfo.cy=MAX_SPRITE_CY*2;
  902.    bmihInfo.cPlanes=1;
  903.  
  904.    DevQueryCaps((*phpgPlay)->hdcWork,CAPS_COLOR_BITCOUNT,1,&lValue);
  905.    bmihInfo.cBitCount=lValue;
  906.  
  907.    (*phpgPlay)->hbmWork=GpiCreateBitmap((*phpgPlay)->hpsWork,
  908.                                         &bmihInfo,
  909.                                         0,
  910.                                         NULL,
  911.                                         NULL);
  912.    if ((*phpgPlay)->hbmWork==NULLHANDLE) {
  913.       GpiDestroyPS((*phpgPlay)->hpsWork);
  914.       DevCloseDC((*phpgPlay)->hdcWork);
  915.       free(*phpgPlay);
  916.       *phpgPlay=NULL;
  917.       return SPR_ERR_RESOURCE;
  918.    } /* endif */
  919.  
  920.    GpiSetBitmap((*phpgPlay)->hpsWork,(*phpgPlay)->hbmWork);
  921.  
  922.    (*phpgPlay)->lBackColor=CLR_BLACK;
  923.    (*phpgPlay)->bUpdate=TRUE;
  924.  
  925.    (*phpgPlay)->hbmBack=NULLHANDLE;
  926.    (*phpgPlay)->ulNumMembers=0;
  927.    return SPR_ERR_NOERROR;
  928. }
  929.  
  930. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  931.  
  932.  
  933. ΓòÉΓòÉΓòÉ <hidden> SprCreateSprite ΓòÉΓòÉΓòÉ
  934.  
  935. SprCreateSprite 
  936.  
  937. See SprCreatePlayground() for notes on using calloc(). 
  938.  
  939. SPRERROR EXPENTRY SprCreateSprite(HAB habAnchor,
  940.                                   HBITMAP hbmBitmap,
  941.                                   PHSPRITE phsSprite)
  942. //-------------------------------------------------------------------------
  943. // This function creates a sprite from the specified bitmap.  The sprite
  944. // cannot be moved, shown, etc., however, until it is associated with a
  945. // playground.
  946. //
  947. // The color black is used as the transparency color.  If you need to use
  948. // black in the bitmap without it becoming transparent, use the next
  949. // closest color.  <grin>
  950. //
  951. // New sprites are initialized as being at position (0,0) and hidden.
  952. //
  953. // Note that, once this function is called, the bitmap is managed by
  954. // the sprite subsystem.  The bitmap should *NOT* be deleted by the
  955. // application or else unpredictable results will occur.
  956. //
  957. // Input:  habAnchor - anchor block of the calling thread.
  958. //         hbmBitmap - handle to the bitmap
  959. // Output:  phsSprite - points to the sprite handle
  960. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  961. //-------------------------------------------------------------------------
  962. {
  963.    HPS hpsMem;
  964.    HDC hdcMem;
  965.    POINTL aptlPoints[4];
  966.  
  967.    *phsSprite=calloc(1,sizeof(SPRITE));
  968.    if (*phsSprite==NULL) {
  969.       *phsSprite=NULL;
  970.       return SPR_ERR_NOMEMORY;
  971.    } /* endif */
  972.  
  973.    (*phsSprite)->ulSig=SIG_HSPRITE;
  974.    (*phsSprite)->ulStatus=0;
  975.  
  976.    if (DosCreateMutexSem(NULL,&(*phsSprite)->hsmAccess,0,FALSE)) {
  977.       free(*phsSprite);
  978.       return SPR_ERR_RESOURCE;
  979.    } /* endif */
  980.  
  981.    (*phsSprite)->habAnchor=habAnchor;
  982.  
  983.    (*phsSprite)->hbmBitmap=hbmBitmap;
  984.  
  985.    (*phsSprite)->ptlPos.x=0;
  986.    (*phsSprite)->ptlPos.y=0;
  987.    (*phsSprite)->bVisible=FALSE;
  988.  
  989.    (*phsSprite)->bmihBitmap.cbFix=16;
  990.    GpiQueryBitmapInfoHeader((*phsSprite)->hbmBitmap,&(*phsSprite)->bmihBitmap);
  991.  
  992.    //----------------------------------------------------------------------
  993.    // Get an OD_MEMORY HDC and HPS to create the mask in.  Since we will
  994.    // save the bitmap handle, but don't give a $%#@ about the HDC/HPS, they
  995.    // can be local variables.
  996.    //----------------------------------------------------------------------
  997.    hpsMem=getMemHps(habAnchor);
  998.    if (hpsMem==NULLHANDLE) {
  999.       free(*phsSprite);
  1000.       *phsSprite=NULL;
  1001.       return SPR_ERR_RESOURCE;
  1002.    } /* endif */
  1003.  
  1004.    hdcMem=GpiQueryDevice(hpsMem);
  1005.  
  1006.    (*phsSprite)->bmihMask=(*phsSprite)->bmihBitmap;
  1007.    (*phsSprite)->bmihMask.cPlanes=1;
  1008.    (*phsSprite)->bmihMask.cBitCount=1;
  1009.  
  1010.    (*phsSprite)->hbmMask=GpiCreateBitmap(hpsMem,
  1011.                                          &(*phsSprite)->bmihMask,
  1012.                                          0,
  1013.                                          NULL,
  1014.                                          NULL);
  1015.    if ((*phsSprite)->hbmMask==NULLHANDLE) {
  1016.       GpiDestroyPS(hpsMem);
  1017.       DevCloseDC(hdcMem);
  1018.       free(*phsSprite);
  1019.       *phsSprite=NULL;
  1020.       return SPR_ERR_RESOURCE;
  1021.    } /* endif */
  1022.  
  1023.    GpiSetBitmap(hpsMem,(*phsSprite)->hbmMask);
  1024.  
  1025.    aptlPoints[0].x=0;
  1026.    aptlPoints[0].y=0;
  1027.    aptlPoints[1].x=aptlPoints[0].x+(*phsSprite)->bmihMask.cx-1;
  1028.    aptlPoints[1].y=aptlPoints[0].y+(*phsSprite)->bmihMask.cy-1;
  1029.    aptlPoints[2].x=0;
  1030.    aptlPoints[2].y=0;
  1031.    aptlPoints[3].x=aptlPoints[2].x+(*phsSprite)->bmihBitmap.cx;
  1032.    aptlPoints[3].y=aptlPoints[2].y+(*phsSprite)->bmihBitmap.cy;
  1033.  
  1034.    //----------------------------------------------------------------------
  1035.    // Set the foreground to white and the background to black so that this
  1036.    // works.  The resulting behavior in the GpiWCBitBlt() call is
  1037.    // inconsistent with the docs, so I don't know what to think.
  1038.    //----------------------------------------------------------------------
  1039.    GpiSetColor(hpsMem,CLR_WHITE);
  1040.    GpiSetBackColor(hpsMem,CLR_BLACK);
  1041.  
  1042.    GpiWCBitBlt(hpsMem,
  1043.                (*phsSprite)->hbmBitmap,
  1044.                4,
  1045.                aptlPoints,
  1046.                ROP_SRCCOPY,
  1047.                BBO_IGNORE);
  1048.    GpiSetBitmap(hpsMem,NULLHANDLE);
  1049.    GpiDestroyPS(hpsMem);
  1050.    DevCloseDC(hdcMem);
  1051.    return SPR_ERR_NOERROR;
  1052. }
  1053.  
  1054. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1055.  
  1056.  
  1057. ΓòÉΓòÉΓòÉ <hidden> SprDestroyPlayground ΓòÉΓòÉΓòÉ
  1058.  
  1059. SprDestroyPlayground 
  1060.  
  1061. This function destroys the sprites in the playground before destroying the 
  1062. playground itself.  However, if you look in SprDestroySprite() you'll see a 
  1063. check to see if the sprite is still a member of a playground (and fails if it 
  1064. is); thus, we have to call SprRemoveSprite() first. 
  1065.  
  1066. SPRERROR EXPENTRY SprDestroyPlayground(HPLAYGROUND hpgPlay)
  1067. //-------------------------------------------------------------------------
  1068. // This function destroys the playground including any sprites that are
  1069. // still members of it.  All resources consumed by the playground,
  1070. // including the back bitmap, are returned to the system.
  1071. //
  1072. // Input:  hpgPlay - handle to the playground
  1073. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1074. //-------------------------------------------------------------------------
  1075. {
  1076.    USHORT usAction;
  1077.    ULONG ulIndex;
  1078.    HSPRITE hsSprite;
  1079.  
  1080.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1081.       return SPR_ERR_BADHANDLE;
  1082.    } /* endif */
  1083.  
  1084.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1085.  
  1086.    if (hpgPlay->hbmBack!=NULLHANDLE) {
  1087.       GpiDeleteBitmap(hpgPlay->hbmBack);
  1088.    } /* endif */
  1089.  
  1090.    for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
  1091.       hsSprite=hpgPlay->ahsSprites[ulIndex];
  1092.       SprRemoveSprite(hpgPlay,hsSprite);
  1093.       SprDestroySprite(hsSprite);
  1094.    } /* endfor */
  1095.  
  1096.    GpiSetBitmap(hpgPlay->hpsWork,NULLHANDLE);
  1097.  
  1098.    if (hpgPlay->hbmBack!=NULLHANDLE) {
  1099.       GpiDeleteBitmap(hpgPlay->hbmBack);
  1100.    } /* endif */
  1101.  
  1102.    GpiDestroyPS(hpgPlay->hpsWork);
  1103.    DevCloseDC(hpgPlay->hdcWork);
  1104.    accessSem((PHEADER)hpgPlay,usAction);
  1105.    free(hpgPlay);
  1106.    return SPR_ERR_NOERROR;
  1107. }
  1108.  
  1109. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1110.  
  1111.  
  1112. ΓòÉΓòÉΓòÉ <hidden> SprDestroySprite ΓòÉΓòÉΓòÉ
  1113.  
  1114. SprDestroySprite 
  1115.  
  1116. There is nothing special about this function that needs to be noted. 
  1117.  
  1118. SPRERROR EXPENTRY SprDestroySprite(HSPRITE hsSprite)
  1119. //-------------------------------------------------------------------------
  1120. // This function destroys the sprite and returns all resources to the
  1121. // system.
  1122. //
  1123. // Input:  hsSprite - handle to the sprite
  1124. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1125. //-------------------------------------------------------------------------
  1126. {
  1127.    USHORT usAction;
  1128.  
  1129.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1130.       return SPR_ERR_BADHANDLE;
  1131.    } /* endif */
  1132.  
  1133.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1134.  
  1135.    if (hsSprite->hpgPlay!=NULL) {
  1136.       accessSem((PHEADER)hsSprite,usAction);
  1137.       return SPR_ERR_HASPLAYGROUND;
  1138.    } /* endif */
  1139.  
  1140.    GpiDeleteBitmap(hsSprite->hbmBitmap);
  1141.    GpiDeleteBitmap(hsSprite->hbmMask);
  1142.    accessSem((PHEADER)hsSprite,usAction);
  1143.    free(hsSprite);
  1144.    return SPR_ERR_NOERROR;
  1145. }
  1146.  
  1147. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1148.  
  1149.  
  1150. ΓòÉΓòÉΓòÉ <hidden> SprDrawPlayground ΓòÉΓòÉΓòÉ
  1151.  
  1152. SprDrawPlayground 
  1153.  
  1154. See SprAddSprite() for notes about ahsSprites being a compact array for 
  1155. performance reasons. 
  1156.  
  1157. SPRERROR EXPENTRY SprDrawPlayground(HPS hpsDraw,HPLAYGROUND hpgPlay)
  1158. //-------------------------------------------------------------------------
  1159. // This function redraws the playground and all sprites belonging to the
  1160. // playground.
  1161. //
  1162. // Input:  hpsDraw - handle to the HPS to draw the playground in
  1163. //         hpgPlay - handle to the playground
  1164. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1165. //-------------------------------------------------------------------------
  1166. {
  1167.    USHORT usAction;
  1168.    ULONG ulIndex;
  1169.  
  1170.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1171.       return SPR_ERR_BADHANDLE;
  1172.    } /* endif */
  1173.  
  1174.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1175.  
  1176.    if (hpgPlay->bUpdate) {
  1177.       drawBackAt(hpsDraw,hpgPlay,NULL,NULL,NULL);
  1178.  
  1179.       for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
  1180.          SprDrawSprite(hpsDraw,hpgPlay->ahsSprites[ulIndex]);
  1181.       } /* endfor */
  1182.    } /* endif */
  1183.  
  1184.    accessSem((PHEADER)hpgPlay,usAction);
  1185.    return SPR_ERR_NOERROR;
  1186. }
  1187.  
  1188. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1189.  
  1190.  
  1191. ΓòÉΓòÉΓòÉ <hidden> SprDrawSprite ΓòÉΓòÉΓòÉ
  1192.  
  1193. SprDrawSprite 
  1194.  
  1195. Given the drawSpriteAt() and drawBackAt() functions, the implementation of this 
  1196. function is fairly trivial. 
  1197.  
  1198. SPRERROR EXPENTRY SprDrawSprite(HPS hpsDraw,HSPRITE hsSprite)
  1199. //-------------------------------------------------------------------------
  1200. // This function draws a sprite
  1201. //
  1202. // Input:  hpsDraw - handle to the HPS to draw the sprite in
  1203. //         hsSprite - handle to the sprite
  1204. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1205. //-------------------------------------------------------------------------
  1206. {
  1207.    USHORT usAction;
  1208.    RECTL rclSprite;
  1209.  
  1210.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1211.       return SPR_ERR_BADHANDLE;
  1212.    } /* endif */
  1213.  
  1214.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1215.  
  1216.    if (hsSprite->hpgPlay==NULL) {
  1217.       accessSem((PHEADER)hsSprite,usAction);
  1218.       return SPR_ERR_HASNOPLAYGROUND;
  1219.    } /* endif */
  1220.  
  1221.    if ((!hsSprite->bVisible) || (!hsSprite->hpgPlay->bUpdate)) {
  1222.       accessSem((PHEADER)hsSprite,usAction);
  1223.       return SPR_ERR_NOERROR;
  1224.    } /* endif */
  1225.  
  1226.    rclSprite.xLeft=hsSprite->ptlPos.x;
  1227.    rclSprite.yBottom=hsSprite->ptlPos.y;
  1228.    rclSprite.xRight=rclSprite.xLeft+hsSprite->bmihMask.cx;
  1229.    rclSprite.yTop=rclSprite.yBottom+hsSprite->bmihMask.cy;
  1230.  
  1231.    drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSprite);
  1232.    drawSpriteAt(hpsDraw,hsSprite,NULL,NULL);
  1233.  
  1234.    accessSem((PHEADER)hsSprite,usAction);
  1235.    return SPR_ERR_NOERROR;
  1236. }
  1237.  
  1238. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1239.  
  1240.  
  1241. ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundBack ΓòÉΓòÉΓòÉ
  1242.  
  1243. SprQueryPlaygroundBack 
  1244.  
  1245. There is nothing special about this function that needs to be noted. 
  1246.  
  1247. SPRERROR EXPENTRY SprQueryPlaygroundBack(HPLAYGROUND hpgPlay,
  1248.                                          HBITMAP *phbmBack)
  1249. //-------------------------------------------------------------------------
  1250. // This function returns the handle of the background bitmap currently in
  1251. // use.
  1252. //
  1253. // Input:  hpgPlay - handle to the playground
  1254. // Output:  phbmBack - points to the handle to the background bitmap.
  1255. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1256. //-------------------------------------------------------------------------
  1257. {
  1258.    USHORT usAction;
  1259.  
  1260.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1261.       return SPR_ERR_BADHANDLE;
  1262.    } /* endif */
  1263.  
  1264.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1265.    *phbmBack=hpgPlay->hbmBack;
  1266.    accessSem((PHEADER)hpgPlay,usAction);
  1267.    return SPR_ERR_NOERROR;
  1268. }
  1269.  
  1270. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1271.  
  1272.  
  1273. ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundColor ΓòÉΓòÉΓòÉ
  1274.  
  1275. SprQueryPlaygroundColor 
  1276.  
  1277. There is nothing special about this function that needs to be noted. 
  1278.  
  1279. SPRERROR EXPENTRY SprQueryPlaygroundColor(HPLAYGROUND hpgPlay,
  1280.                                           PLONG plBackColor)
  1281. //-------------------------------------------------------------------------
  1282. // This function returns the background color of the playground and is
  1283. // only valid if the playground doesn't have a bitmap.
  1284. //
  1285. // Input:  hpgPlay - handle to the playground
  1286. //         plBackColor - points to the variable to receive the background
  1287. //                       color
  1288. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1289. //-------------------------------------------------------------------------
  1290. {
  1291.    USHORT usAction;
  1292.  
  1293.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1294.       return SPR_ERR_BADHANDLE;
  1295.    } /* endif */
  1296.  
  1297.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1298.  
  1299.    if (hpgPlay->hbmBack!=NULLHANDLE) {
  1300.       accessSem((PHEADER)hpgPlay,usAction);
  1301.       return SPR_ERR_HASBACKGROUND;
  1302.    } /* endif */
  1303.  
  1304.    *plBackColor=hpgPlay->lBackColor;
  1305.    accessSem((PHEADER)hpgPlay,usAction);
  1306.    return SPR_ERR_NOERROR;
  1307. }
  1308.  
  1309. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1310.  
  1311.  
  1312. ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundSize ΓòÉΓòÉΓòÉ
  1313.  
  1314. SprQueryPlaygroundSize 
  1315.  
  1316. There is nothing special about this function that needs to be noted. 
  1317.  
  1318. SPRERROR EXPENTRY SprQueryPlaygroundSize(HPLAYGROUND hpgPlay,PSIZEL pszlSize)
  1319. //-------------------------------------------------------------------------
  1320. // This function returns the size of the playground.  For playgrounds with
  1321. // bitmaps set as the background, the returned value is the size of the
  1322. // bitmap.  Otherwise, the returned value is that which was specified on
  1323. // the last call to SprSetPlaygroundSize().
  1324. //
  1325. // Input:  hpgPlay - handle to the playground
  1326. //         pszlSize - points to the variable to receive the size of the
  1327. //                    playground
  1328. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1329. //-------------------------------------------------------------------------
  1330. {
  1331.    USHORT usAction;
  1332.  
  1333.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1334.       return SPR_ERR_BADHANDLE;
  1335.    } /* endif */
  1336.  
  1337.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1338.    pszlSize->cx=hpgPlay->bmihBack.cx;
  1339.    pszlSize->cy=hpgPlay->bmihBack.cy;
  1340.    accessSem((PHEADER)hpgPlay,usAction);
  1341.    return SPR_ERR_NOERROR;
  1342. }
  1343.  
  1344. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1345.  
  1346.  
  1347. ΓòÉΓòÉΓòÉ <hidden> SprQuerySpritePosition ΓòÉΓòÉΓòÉ
  1348.  
  1349. SprQuerySpritePosition 
  1350.  
  1351. There is nothing special about this function that needs to be noted. 
  1352.  
  1353. SPRERROR EXPENTRY SprQuerySpritePosition(HSPRITE hsSprite,PPOINTL pptlPos)
  1354. //-------------------------------------------------------------------------
  1355. // This function returns the current position of the sprite.  Note that
  1356. // a sprite has a current position even if it is hidden.
  1357. //
  1358. // Input:  hsSprite - handle to the sprite
  1359. // Output:  pptlPos - points to the current position
  1360. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1361. //-------------------------------------------------------------------------
  1362. {
  1363.    USHORT usAction;
  1364.  
  1365.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1366.       return SPR_ERR_BADHANDLE;
  1367.    } /* endif */
  1368.  
  1369.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1370.  
  1371.    if (hsSprite->hpgPlay==NULL) {
  1372.       accessSem((PHEADER)hsSprite,usAction);
  1373.       return SPR_ERR_HASNOPLAYGROUND;
  1374.    } /* endif */
  1375.  
  1376.    *pptlPos=hsSprite->ptlPos;
  1377.    accessSem((PHEADER)hsSprite,usAction);
  1378.    return SPR_ERR_NOERROR;
  1379. }
  1380.  
  1381. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1382.  
  1383.  
  1384. ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteRect ΓòÉΓòÉΓòÉ
  1385.  
  1386. SprQuerySpriteRect 
  1387.  
  1388. Since the bounding rectangle of a sprite varies with its position, and since a 
  1389. sprite cannot have a position until it is a member of a playground, this 
  1390. function checks for membership and fails if there is none.  Note that the 
  1391. rectangle returned is all-inclusive, i.e. the upper and right edge of the 
  1392. rectangle is part of the sprite. 
  1393.  
  1394. SPRERROR EXPENTRY SprQuerySpriteRect(HSPRITE hsSprite,PRECTL prclRect)
  1395. //-------------------------------------------------------------------------
  1396. // This function returns the bounding rectangle of the sprite at its
  1397. // current position.
  1398. //
  1399. // Input:  hsSprite - handle to the sprite
  1400. // Output:  prclRect - points to the current bounding rectangle
  1401. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1402. //-------------------------------------------------------------------------
  1403. {
  1404.    USHORT usAction;
  1405.  
  1406.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1407.       return SPR_ERR_BADHANDLE;
  1408.    } /* endif */
  1409.  
  1410.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1411.  
  1412.    if (hsSprite->hpgPlay==NULL) {
  1413.       accessSem((PHEADER)hsSprite,usAction);
  1414.       return SPR_ERR_HASNOPLAYGROUND;
  1415.    } /* endif */
  1416.  
  1417.    prclRect->xLeft=hsSprite->ptlPos.x;
  1418.    prclRect->yBottom=hsSprite->ptlPos.y;
  1419.    prclRect->xRight=prclRect->xLeft+hsSprite->bmihBitmap.cx-1;
  1420.    prclRect->yTop=prclRect->yBottom+hsSprite->bmihBitmap.cy-1;
  1421.    accessSem((PHEADER)hsSprite,usAction);
  1422.    return SPR_ERR_NOERROR;
  1423. }
  1424.  
  1425. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1426.  
  1427.  
  1428. ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteSize ΓòÉΓòÉΓòÉ
  1429.  
  1430. SprQuerySpriteSize 
  1431.  
  1432. Unlike SprQuerySpritePosition() and SprQuerySpriteRect(), SprQuerySpriteSize() 
  1433. is not variant, but is fixed at the time of creation, so we do not need to 
  1434. check for membership in a playground. 
  1435.  
  1436. SPRERROR EXPENTRY SprQuerySpriteSize(HSPRITE hsSprite,PSIZEL pszlSize)
  1437. //-------------------------------------------------------------------------
  1438. // This function returns the current size of the sprite.
  1439. //
  1440. // Input:  hsSprite - handle to the sprite
  1441. // Output:  pszlSize - points to the current size
  1442. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1443. //-------------------------------------------------------------------------
  1444. {
  1445.    USHORT usAction;
  1446.  
  1447.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1448.       return SPR_ERR_BADHANDLE;
  1449.    } /* endif */
  1450.  
  1451.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1452.    pszlSize->cx=hsSprite->bmihBitmap.cx;
  1453.    pszlSize->cy=hsSprite->bmihBitmap.cy;
  1454.    accessSem((PHEADER)hsSprite,usAction);
  1455.    return SPR_ERR_NOERROR;
  1456. }
  1457.  
  1458. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1459.  
  1460.  
  1461. ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteVisibility ΓòÉΓòÉΓòÉ
  1462.  
  1463. SprQuerySpriteVisibility 
  1464.  
  1465. There is nothing special about this function that needs to be noted. 
  1466.  
  1467. SPRERROR EXPENTRY SprQuerySpriteVisibility(HSPRITE hsSprite,PBOOL pbVisible)
  1468. //-------------------------------------------------------------------------
  1469. // This function returns the visibility state of the sprite
  1470. //
  1471. // Input:  hsSprite - handle to the sprite
  1472. // Output:  pbVisible - points to the visibility state
  1473. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1474. //-------------------------------------------------------------------------
  1475. {
  1476.    USHORT usAction;
  1477.  
  1478.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1479.       return SPR_ERR_BADHANDLE;
  1480.    } /* endif */
  1481.  
  1482.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1483.  
  1484.    if (hsSprite->hpgPlay==NULL) {
  1485.       accessSem((PHEADER)hsSprite,usAction);
  1486.       return SPR_ERR_HASNOPLAYGROUND;
  1487.    } /* endif */
  1488.  
  1489.    *pbVisible=hsSprite->bVisible;
  1490.    accessSem((PHEADER)hsSprite,usAction);
  1491.    return SPR_ERR_NOERROR;
  1492. }
  1493.  
  1494. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1495.  
  1496.  
  1497. ΓòÉΓòÉΓòÉ <hidden> SprQueryUpdateFlag ΓòÉΓòÉΓòÉ
  1498.  
  1499. SprQueryUpdateFlag 
  1500.  
  1501. There is nothing special about this function that needs to be noted. 
  1502.  
  1503. SPRERROR EXPENTRY SprQueryUpdateFlag(HPLAYGROUND hpgPlay,PBOOL pbUpdate)
  1504. //-------------------------------------------------------------------------
  1505. // This function returns the setting of the update flag.  See the notes
  1506. // for SprSetUpdateFlag() for more information about this setting.
  1507. //
  1508. // Input:  hpgPlay - handle to the playground
  1509. //         pbUpdate - points to the variable to receive the update flag
  1510. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1511. //-------------------------------------------------------------------------
  1512. {
  1513.    USHORT usAction;
  1514.  
  1515.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1516.       return SPR_ERR_BADHANDLE;
  1517.    } /* endif */
  1518.  
  1519.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1520.    *pbUpdate=hpgPlay->bUpdate;
  1521.    accessSem((PHEADER)hpgPlay,usAction);
  1522.    return SPR_ERR_NOERROR;
  1523. }
  1524.  
  1525. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1526.  
  1527.  
  1528. ΓòÉΓòÉΓòÉ <hidden> SprRemoveSprite ΓòÉΓòÉΓòÉ
  1529.  
  1530. SprRemoveSprite 
  1531.  
  1532. This function removes a sprite from the ahsSprites field of the HPLAYGROUND 
  1533. structure and moves all members after the sprite down one slot in the array. 
  1534.  
  1535. SPRERROR EXPENTRY SprRemoveSprite(HPLAYGROUND hpgPlay,HSPRITE hsSprite)
  1536. //-------------------------------------------------------------------------
  1537. // This function removes the sprite from the membership list of the
  1538. // specified playground.  The sprite can then be added to another
  1539. // playground, or this one at a later time.
  1540. //
  1541. // Since there is a limited number of sprites that can be members of
  1542. // a playground, this function can be used to temporarily remove unused
  1543. // sprites from a playground so that others can be used.
  1544. //
  1545. // Input:  hpgPlay - handle to the playground
  1546. //         hsSprite - handle to the sprite to remove
  1547. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1548. //-------------------------------------------------------------------------
  1549. {
  1550.    USHORT usAction;
  1551.    ULONG ulIndex;
  1552.  
  1553.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1554.       return SPR_ERR_BADHANDLE;
  1555.    } else
  1556.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1557.       return SPR_ERR_BADHANDLE;
  1558.    } /* endif */
  1559.  
  1560.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1561.  
  1562.    for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
  1563.       if (hpgPlay->ahsSprites[ulIndex]==hsSprite) {
  1564.          break;
  1565.       } /* endif */
  1566.    } /* endfor */
  1567.  
  1568.    if (ulIndex==hpgPlay->ulNumMembers) {
  1569.       accessSem((PHEADER)hpgPlay,usAction);
  1570.       return SPR_ERR_HASNOPLAYGROUND;
  1571.    } /* endif */
  1572.  
  1573.    //----------------------------------------------------------------------
  1574.    // Adjust the member array by moving all of the sprites after the one
  1575.    // being removed to the slot just before there current position.  Then,
  1576.    // decrement the number of members and we're done.
  1577.    //----------------------------------------------------------------------
  1578.    hpgPlay->ulNumMembers--;
  1579.  
  1580.    while (ulIndex<hpgPlay->ulNumMembers) {
  1581.       hpgPlay->ahsSprites[ulIndex]=hpgPlay->ahsSprites[ulIndex+1];
  1582.       ulIndex++;
  1583.    } /* endwhile */
  1584.  
  1585.    hpgPlay->ahsSprites[ulIndex]=NULL;
  1586.    hsSprite->hpgPlay=NULL;
  1587.    accessSem((PHEADER)hpgPlay,usAction);
  1588.    return SPR_ERR_NOERROR;
  1589. }
  1590.  
  1591. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1592.  
  1593.  
  1594. ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundBack ΓòÉΓòÉΓòÉ
  1595.  
  1596. SprSetPlaygroundBack 
  1597.  
  1598. There is nothing special about this function that needs to be noted. 
  1599.  
  1600. SPRERROR EXPENTRY SprSetPlaygroundBack(HPLAYGROUND hpgPlay,
  1601.                                        HBITMAP hbmNew,
  1602.                                        HBITMAP *phbmOld)
  1603. //-------------------------------------------------------------------------
  1604. // This function sets the background bitmap of the playground.
  1605. //
  1606. // Note that, once this function is called, the bitmap is managed by
  1607. // the sprite subsystem.  The bitmap should *NOT* be deleted by the
  1608. // application unless the bitmap is "unset" from the playground (by
  1609. // calling this function again with a different handle).
  1610. //
  1611. // Input:  hpgPlay - handle to the playground
  1612. //         hbmNew - handle to the new bitmap to used as the background
  1613. // Output:  phbmOld - points to the handle to the old background bitmap.
  1614. //          This can be NULL, meaning that the application isn't interested
  1615. //          in receiving this value.
  1616. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1617. //-------------------------------------------------------------------------
  1618. {
  1619.    USHORT usAction;
  1620.  
  1621.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1622.       return SPR_ERR_BADHANDLE;
  1623.    } /* endif */
  1624.  
  1625.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1626.  
  1627.    if (phbmOld!=NULL) {
  1628.       *phbmOld=hpgPlay->hbmBack;
  1629.    } /* endif */
  1630.  
  1631.    hpgPlay->hbmBack=hbmNew;
  1632.  
  1633.    //----------------------------------------------------------------------
  1634.    // We're only interested in the cx and cy fields
  1635.    //----------------------------------------------------------------------
  1636.    hpgPlay->bmihBack.cbFix=16;
  1637.    GpiQueryBitmapInfoHeader(hpgPlay->hbmBack,&hpgPlay->bmihBack);
  1638.  
  1639.    accessSem((PHEADER)hpgPlay,usAction);
  1640.    return SPR_ERR_NOERROR;
  1641. }
  1642.  
  1643. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1644.  
  1645.  
  1646. ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundColor ΓòÉΓòÉΓòÉ
  1647.  
  1648. SprSetPlaygroundColor 
  1649.  
  1650. Note that we do not force a repaint, since I didn't want to deal with passing 
  1651. in an HPS on too many functions.  It is conceivable that the background color 
  1652. can be set immediately after creation of the playground and let it get 
  1653. displayed the next time WM_PAINT is processed. 
  1654.  
  1655. SPRERROR EXPENTRY SprSetPlaygroundColor(HPLAYGROUND hpgPlay,LONG lBackColor)
  1656. //-------------------------------------------------------------------------
  1657. // This function sets the new background color of the playground and is
  1658. // only valid if the playground doesn't have a bitmap.
  1659. //
  1660. // Input:  hpgPlay - handle to the playground
  1661. //         lBackColor - specifies the new background color
  1662. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1663. //-------------------------------------------------------------------------
  1664. {
  1665.    USHORT usAction;
  1666.  
  1667.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1668.       return SPR_ERR_BADHANDLE;
  1669.    } /* endif */
  1670.  
  1671.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1672.  
  1673.    if (hpgPlay->hbmBack!=NULLHANDLE) {
  1674.       accessSem((PHEADER)hpgPlay,usAction);
  1675.       return SPR_ERR_HASBACKGROUND;
  1676.    } /* endif */
  1677.  
  1678.    hpgPlay->lBackColor=lBackColor;
  1679.    accessSem((PHEADER)hpgPlay,usAction);
  1680.    return SPR_ERR_NOERROR;
  1681. }
  1682.  
  1683. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1684.  
  1685.  
  1686. ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundSize ΓòÉΓòÉΓòÉ
  1687.  
  1688. SprSetPlaygroundSize 
  1689.  
  1690. This function is allowed only if there is no background bitmap. 
  1691.  
  1692. SPRERROR EXPENTRY SprSetPlaygroundSize(HPLAYGROUND hpgPlay,PSIZEL pszlSize)
  1693. //-------------------------------------------------------------------------
  1694. // This function sets the playground size for playgrounds that do not have
  1695. // a bitmap set as the background.
  1696. //
  1697. // Input:  hpgPlay - handle to the playground
  1698. //         pszlSize - points to the size of the playground
  1699. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1700. //-------------------------------------------------------------------------
  1701. {
  1702.    USHORT usAction;
  1703.  
  1704.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1705.       return SPR_ERR_BADHANDLE;
  1706.    } /* endif */
  1707.  
  1708.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1709.  
  1710.    if (hpgPlay->hbmBack!=NULLHANDLE) {
  1711.       accessSem((PHEADER)hpgPlay,usAction);
  1712.       return SPR_ERR_HASBACKGROUND;
  1713.    } /* endif */
  1714.  
  1715.    hpgPlay->bmihBack.cx=pszlSize->cx;
  1716.    hpgPlay->bmihBack.cy=pszlSize->cy;
  1717.  
  1718.    accessSem((PHEADER)hpgPlay,usAction);
  1719.    return SPR_ERR_NOERROR;
  1720. }
  1721.  
  1722. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1723.  
  1724.  
  1725. ΓòÉΓòÉΓòÉ <hidden> SprSetSpritePosition ΓòÉΓòÉΓòÉ
  1726.  
  1727. SprSetSpritePosition 
  1728.  
  1729. SPRERROR EXPENTRY SprSetSpritePosition(HPS hpsDraw,
  1730.                                        HSPRITE hsSprite,
  1731.                                        PPOINTL pptlNew)
  1732. //-------------------------------------------------------------------------
  1733. // This function changes the position of the sprite.  This function is
  1734. // optimized so that, if the rectangle bounding the sprite at the new
  1735. // position overlaps the old, only one "bit blit" to the specified HPS
  1736. // is done, eliminating flicker.
  1737. //
  1738. // Input:  hpsDraw - handle to the HPS to draw the sprite in once it is
  1739. //                   moved
  1740. //         hsSprite - handle to the sprite
  1741. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1742. //-------------------------------------------------------------------------
  1743. {
  1744.    USHORT usAction;
  1745.    SIZEL szlPlay;
  1746.    SIZEL szlWork;
  1747.    RECTL rclOld;
  1748.    RECTL rclNew;
  1749.    RECTL rclUnion;
  1750.    RECTL rclSrc;
  1751.    RECTL rclDest;
  1752.    POINTL ptlWork;
  1753.    POINTL aptlPoints[4];
  1754.  
  1755.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1756.       return SPR_ERR_BADHANDLE;
  1757.    } /* endif */
  1758.  
  1759.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1760.  
  1761.    if (hsSprite->hpgPlay==NULL) {
  1762.       accessSem((PHEADER)hsSprite,usAction);
  1763.       return SPR_ERR_HASNOPLAYGROUND;
  1764.    } /* endif */
  1765.  
  1766.    if ((hsSprite->bVisible) && (hsSprite->hpgPlay->bUpdate)) {
  1767.       szlWork.cx=MAX_SPRITE_CX*2;
  1768.       szlWork.cy=MAX_SPRITE_CY*2;
  1769.  
  1770.       SprQueryPlaygroundSize(hsSprite->hpgPlay,&szlPlay);
  1771.  
  1772. Note how we query the sprite rectangle before and after the position changes 
  1773. and then call WinUnionRect() to check for overlap.  This determines our course 
  1774. of action.  If there is no overlap, call drawBackAt() and SprDrawSprite() to 
  1775. erase the sprite at its old position and redraw at its new position. 
  1776. Otherwise, perform the delta processing (see below). 
  1777.  
  1778.       SprQuerySpriteRect(hsSprite,&rclOld);
  1779.       hsSprite->ptlPos=*pptlNew;
  1780.       SprQuerySpriteRect(hsSprite,&rclNew);
  1781.  
  1782.       WinUnionRect(hsSprite->habAnchor,&rclUnion,&rclOld,&rclNew);
  1783.  
  1784.       if ((rclUnion.xRight-rclUnion.xLeft>MAX_SPRITE_CX*2) ||
  1785.           (rclUnion.yTop-rclUnion.yBottom>MAX_SPRITE_CY*2)) {
  1786.  
  1787.          rclSrc.xLeft=rclOld.xLeft;
  1788.          rclSrc.yBottom=rclOld.yBottom;
  1789.          rclSrc.xRight=rclSrc.xLeft+hsSprite->bmihBitmap.cx;
  1790.          rclSrc.yTop=rclSrc.yBottom+hsSprite->bmihBitmap.cy;
  1791.  
  1792.          drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSrc);
  1793.  
  1794.          SprDrawSprite(hpsDraw,hsSprite);
  1795.       } else {
  1796.  
  1797. rclUnion contains the bounding rectangle of the old and new positions, so first 
  1798. transfer this rectangle from the background to the workarea (offset by 
  1799. (-rclUnion.xLeft,-rclUnion.yBottom)). 
  1800.  
  1801.          rclSrc=rclUnion;
  1802.          rclSrc.xRight++;
  1803.          rclSrc.yTop++;
  1804.  
  1805.          rclDest.xLeft=0;
  1806.          rclDest.yBottom=0;
  1807.          rclDest.xRight=rclUnion.xRight-rclUnion.xLeft;
  1808.          rclDest.yTop=rclUnion.yTop-rclUnion.yBottom;
  1809.  
  1810.          drawBackAt(hsSprite->hpgPlay->hpsWork,
  1811.                     hsSprite->hpgPlay,
  1812.                     &rclDest,
  1813.                     &szlWork,
  1814.                     &rclSrc);
  1815.  
  1816. Once the background has been drawn, call drawSpriteAt() with a position also 
  1817. offset by (-rclUnion.xLeft,-rclUnion.yBottom).  This completes our drawing in 
  1818. the workarea; now we simply need to remove the offset, clip to the playground, 
  1819. and call GpiBitBlt() to transfer the entire rclUnion-sized rectangle from the 
  1820. workarea to the screen. 
  1821.  
  1822.          ptlWork.x=hsSprite->ptlPos.x-rclUnion.xLeft;
  1823.          ptlWork.y=hsSprite->ptlPos.y-rclUnion.yBottom;
  1824.  
  1825.          drawSpriteAt(hsSprite->hpgPlay->hpsWork,hsSprite,&szlWork,&ptlWork);
  1826.  
  1827.          //----------------------------------------------------------------
  1828.          // GpiBitBlt is non-inclusive on source AND target
  1829.          //----------------------------------------------------------------
  1830.          aptlPoints[0].x=rclUnion.xLeft;
  1831.          aptlPoints[0].y=rclUnion.yBottom;
  1832.          aptlPoints[1].x=rclUnion.xRight+1;
  1833.          aptlPoints[1].y=rclUnion.yTop+1;
  1834.          aptlPoints[2].x=0;
  1835.          aptlPoints[2].y=0;
  1836.          aptlPoints[3].x=rclUnion.xRight-rclUnion.xLeft+1;
  1837.          aptlPoints[3].y=rclUnion.yTop-rclUnion.yBottom+1;
  1838.  
  1839.          if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlPlay)) {
  1840.             GpiBitBlt(hpsDraw,
  1841.                       hsSprite->hpgPlay->hpsWork,
  1842.                       4,
  1843.                       aptlPoints,
  1844.                       ROP_SRCCOPY,
  1845.                       BBO_IGNORE);
  1846.          } /* endif */
  1847.       } /* endif */
  1848.    } else {
  1849.       hsSprite->ptlPos=*pptlNew;
  1850.    } /* endif */
  1851.  
  1852.    accessSem((PHEADER)hsSprite,usAction);
  1853.    return SPR_ERR_NOERROR;
  1854. }
  1855.  
  1856. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1857.  
  1858.  
  1859. ΓòÉΓòÉΓòÉ <hidden> SprSetSpriteVisibility ΓòÉΓòÉΓòÉ
  1860.  
  1861. SprSetSpriteVisibility 
  1862.  
  1863. There is nothing special about this function that needs to be noted. 
  1864.  
  1865. SPRERROR EXPENTRY SprSetSpriteVisibility(HPS hpsDraw,
  1866.                                          HSPRITE hsSprite,
  1867.                                          BOOL bVisible)
  1868. //-------------------------------------------------------------------------
  1869. // This function shows or hides a sprite.
  1870. //
  1871. // Input:  hpsDraw - handle to the HPS to draw in once the sprite is
  1872. //                   shown or hidden
  1873. //         hsSprite - handle to the sprite
  1874. //         bVisible - new visibility state
  1875. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1876. //-------------------------------------------------------------------------
  1877. {
  1878.    USHORT usAction;
  1879.    RECTL rclSprite;
  1880.  
  1881.    if (queryHandleType(hsSprite)!=QH_HSPRITE) {
  1882.       return SPR_ERR_BADHANDLE;
  1883.    } /* endif */
  1884.  
  1885.    usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
  1886.  
  1887.    if (hsSprite->hpgPlay==NULL) {
  1888.       accessSem((PHEADER)hsSprite,usAction);
  1889.       return SPR_ERR_HASNOPLAYGROUND;
  1890.    } /* endif */
  1891.  
  1892.    if (hsSprite->bVisible!=bVisible) {
  1893.       hsSprite->bVisible=bVisible;
  1894.  
  1895.       if (hsSprite->hpgPlay->bUpdate) {
  1896.          if (hsSprite->bVisible) {
  1897.             SprDrawSprite(hpsDraw,hsSprite);
  1898.          } else {
  1899.             rclSprite.xLeft=hsSprite->ptlPos.x;
  1900.             rclSprite.yBottom=hsSprite->ptlPos.y;
  1901.             rclSprite.xRight=rclSprite.xLeft+hsSprite->bmihMask.cx;
  1902.             rclSprite.yTop=rclSprite.yBottom+hsSprite->bmihMask.cy;
  1903.  
  1904.             drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSprite);
  1905.          } /* endif */
  1906.       } /* endif */
  1907.    } /* endif */
  1908.  
  1909.    accessSem((PHEADER)hsSprite,usAction);
  1910.    return SPR_ERR_NOERROR;
  1911. }
  1912.  
  1913. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1914.  
  1915.  
  1916. ΓòÉΓòÉΓòÉ <hidden> SprSetUpdateFlag ΓòÉΓòÉΓòÉ
  1917.  
  1918. SprSetUpdateFlag 
  1919.  
  1920. There is nothing special about this function that needs to be noted. 
  1921.  
  1922. SPRERROR EXPENTRY SprSetUpdateFlag(HPLAYGROUND hpgPlay,BOOL bUpdate)
  1923. //-------------------------------------------------------------------------
  1924. // This function sets the update flag for the playground.  If FALSE, no
  1925. // drawing actually takes place in any of the functions requiring an HPS,
  1926. // and the value of the HPS handle may be NULLHANDLE.  If TRUE, updating
  1927. // is reenabled, but you should still call SprDrawPlayground() to refresh
  1928. // the screen with the current contents.
  1929. //
  1930. // Input:  hpgPlay - handle to the playground
  1931. //         bUpdate - specifies the new update flag
  1932. // Returns:  SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
  1933. //-------------------------------------------------------------------------
  1934. {
  1935.    USHORT usAction;
  1936.  
  1937.    if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
  1938.       return SPR_ERR_BADHANDLE;
  1939.    } /* endif */
  1940.  
  1941.    usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
  1942.    hpgPlay->bUpdate=bUpdate;
  1943.    accessSem((PHEADER)hpgPlay,usAction);
  1944.    return SPR_ERR_NOERROR;
  1945. }
  1946.  
  1947. Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6 
  1948.  
  1949.  
  1950. ΓòÉΓòÉΓòÉ 2.2. Resources and Decompiling Them ΓòÉΓòÉΓòÉ
  1951.  
  1952.  
  1953. ΓòÉΓòÉΓòÉ 2.2.1. Introduction ΓòÉΓòÉΓòÉ
  1954.  
  1955. Resources and Decompiling Them 
  1956.  
  1957. Written by Martin Lafaix 
  1958.  
  1959. Introduction 
  1960.  
  1961. What's that? 
  1962.  
  1963. OS/2 comes with a resource compiler, RC, which allows us to put resources in an 
  1964. executable file; but, it would sometimes be useful to do just the opposite, 
  1965. namely, extracting resources from an executable (or from a DLL). 
  1966.  
  1967. Why? 
  1968.  
  1969. If we were able to extract resources, it would help us adapting this lovely 
  1970. little tool, which unfortunately has all its messages and menus in, say, 
  1971. Chinese... :-) and which is no longer supported by its author.  Or, it would 
  1972. allow us to correct those lovely typographical errors in the base OS/2 system, 
  1973. too. (At least, the French version includes some boring typos, in menu items 
  1974. and shortcuts :-( )  Or, it would even allow us to grab some lovely dialog box 
  1975. and include it in our wonderful projects. 
  1976.  
  1977. Contents 
  1978.  
  1979. This article contains four parts.  The first one describes the general 
  1980. executable file structure, the second one describes the 16-bit EXE structure, 
  1981. the third describes the 32-bit EXE structure, and the fourth describes the RES 
  1982. to RC translation.  Sample code will be given in REXX, which will use many 
  1983. user-defined functions, such as readw() or readl(). 
  1984.  
  1985. A (short) bibliography can be found at the end of this document. 
  1986.  
  1987. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  1988.  
  1989.  
  1990. ΓòÉΓòÉΓòÉ 2.2.2. A Voyage to OMF ΓòÉΓòÉΓòÉ
  1991.  
  1992. A Voyage to OMF 
  1993.  
  1994. In the following sections, "EXE" will be used as a generic term for .EXE or 
  1995. .DLL files. 
  1996.  
  1997. The Old DOS Header 
  1998.  
  1999. Each EXE starts with an old DOS header.  Two fields interest us, namely e_magic 
  2000. and e_lfanew.  The first one contains "MZ" and allowed us to recognize the EXE 
  2001. header, and the second one contains the offset of the new EXE header, which is 
  2002. where the fun begins.  The remaining fields are used for a DOS 'stub', that is, 
  2003. a program which displays a message like: 
  2004.  
  2005. This program cannot be run in a DOS session.
  2006.  
  2007. This message is displayed whenever the program is run from vanilla DOS. 
  2008.  
  2009. struct exe_hdr                          /* DOS 1, 2, 3 .EXE header */
  2010.   {
  2011.     unsigned short      e_magic;        /* Magic number */
  2012.     unsigned short      e_cblp;         /* Bytes on last page of file */
  2013.     unsigned short      e_cp;           /* Pages in file */
  2014.     unsigned short      e_crlc;         /* Relocations */
  2015.     unsigned short      e_cparhdr;      /* Size of header in paragraphs */
  2016.     unsigned short      e_minalloc;     /* Minimum extra paragraphs needed */
  2017.     unsigned short      e_maxalloc;     /* Maximum extra paragraphs needed */
  2018.     unsigned short      e_ss;           /* Initial (relative) SS value */
  2019.     unsigned short      e_sp;           /* Initial SP value */
  2020.     unsigned short      e_csum;         /* Checksum */
  2021.     unsigned short      e_ip;           /* Initial IP value */
  2022.     unsigned short      e_cs;           /* Initial (relative) CS value */
  2023.     unsigned short      e_lfarlc;       /* File address of relocation table */
  2024.     unsigned short      e_ovno;         /* Overlay number */
  2025.     unsigned short      e_res[ERES1WDS];/* Reserved words */
  2026.     unsigned short      e_oemid;        /* OEM identifier (for e_oeminfo) */
  2027.     unsigned short      e_oeminfo;      /* OEM information; e_oemid specific */
  2028.     unsigned short      e_res2[ERES2WDS];/* Reserved words */
  2029.     long                e_lfanew;       /* File address of new exe header */
  2030.   };
  2031.  
  2032. Figure 1.  The DOS 1, 2, 3 .EXE header. 
  2033.  
  2034. Recognizing it from REXX 
  2035.  
  2036. In the following code, infile contains the EXE filename. base will then contain 
  2037. the new header offset. 
  2038.  
  2039.    if charin(infile,,2) = 'MZ' then base = 1+l2d(charin(infile,61,4))
  2040.  
  2041. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2042.  
  2043.  
  2044. ΓòÉΓòÉΓòÉ 2.2.3. Exploring 16-Bit Headers ΓòÉΓòÉΓòÉ
  2045.  
  2046. Exploring 16-Bit Headers 
  2047.  
  2048. Recognizing a 16-bit EXE header 
  2049.  
  2050. A 16-bit EXE header starts with the 'NE' magic number; a 16-bit EXE structure 
  2051. starts with this magic number: 
  2052.  
  2053. struct new_exe                          /* New .EXE header */
  2054.   {
  2055.     unsigned short      ne_magic;       /* Magic number NE_MAGIC */
  2056.     unsigned char       ne_ver;         /* Version number */
  2057.     unsigned char       ne_rev;         /* Revision number */
  2058.     unsigned short      ne_enttab;      /* Offset of Entry Table */
  2059.     unsigned short      ne_cbenttab;    /* Number of bytes in Entry Table */
  2060.     long                ne_crc;         /* Checksum of whole file */
  2061.     unsigned short      ne_flags;       /* Flag word */
  2062.     unsigned short      ne_autodata;    /* Automatic data segment number */
  2063.     unsigned short      ne_heap;        /* Initial heap allocation */
  2064.     unsigned short      ne_stack;       /* Initial stack allocation */
  2065.     long                ne_csip;        /* Initial CS:IP setting */
  2066.     long                ne_sssp;        /* Initial SS:SP setting */
  2067.     unsigned short      ne_cseg;        /* Count of file segments */
  2068.     unsigned short      ne_cmod;        /* Entries in Module Reference Table */
  2069.     unsigned short      ne_cbnrestab;   /* Size of non-resident name table */
  2070.     unsigned short      ne_segtab;      /* Offset of Segment Table */
  2071.     unsigned short      ne_rsrctab;     /* Offset of Resource Table */
  2072.     unsigned short      ne_restab;      /* Offset of resident name table */
  2073.     unsigned short      ne_modtab;      /* Offset of Module Reference Table */
  2074.     unsigned short      ne_imptab;      /* Offset of Imported Names Table */
  2075.     long                ne_nrestab;     /* Offset of Non-resident Names Table */
  2076.     unsigned short      ne_cmovent;     /* Count of movable entries */
  2077.     unsigned short      ne_align;       /* Segment alignment shift count */
  2078.     unsigned short      ne_cres;        /* Count of resource entries */
  2079.     unsigned char       ne_exetyp;      /* Target operating system */
  2080.     unsigned char       ne_flagsothers; /* Other .EXE flags */
  2081.     char                ne_res[NERESBYTES];
  2082.                                         /* Pad structure to 64 bytes */
  2083.   };
  2084.  
  2085. Figure 2.  The OS/2 286 .EXE header. 
  2086.  
  2087. The following fields interest us: 
  2088.  
  2089. Field               Contents 
  2090.  
  2091. ne_cseg             is the number of segments in the EXE.  Segments containing 
  2092.                     resources are at the end of the segment table. 
  2093.  
  2094. ne_segtab           is the offset of the segment table.  Each entry in this 
  2095.                     table contains the following: 
  2096.  
  2097.    ssector (WORD)      is the segment's beginning sector, from the beginning of 
  2098.                        the EXE. See ne_align below for more explanations on how 
  2099.                        to compute the segment's effective position in EXE. 
  2100.    cb (WORD)           is the segment's size in bytes. 
  2101.    sflags (WORD)       is the segment's flags.  Interesting bits are: 
  2102.  
  2103.       NSMOVE              0x0010  Moveable segment flag 
  2104.       NSSHARED            0x0020  Shared segment flag 
  2105.       NSPRELOAD           0x0040  Preload segment flag 
  2106.       NSDISCARD           0x1000  Segment is discardable 
  2107.    smin (WORD)         is the minimum allocation in bytes.  This field's value 
  2108.                        is not used with segments containing resources. 
  2109.  
  2110.                     Note:  The segment table offset is from the beginning of 
  2111.                     the 286 EXE header, not from the beginning of the EXE. 
  2112.  
  2113. ne_rsrctab          is the offset of the resource table.  Each entry in this 
  2114.                     table contains two fields: 
  2115.  
  2116.    etype (WORD)        is the resource type. 
  2117.    ename (WORD)        is the resource name (well, for OS/2, it's a number). 
  2118.  
  2119.                     Note:  The resource table offset is from the beginning of 
  2120.                     the 286 EXE header, not from the beginning of the EXE. 
  2121.  
  2122. ne_align            is the segment alignment shift count.  It's the number of 
  2123.                     bits we should shift the segment's beginning sector value 
  2124.                     to find the segment's position in EXE. 
  2125.  
  2126.                     For example, if ne_align is 4, segments will be aligned on 
  2127.                     16-byte boundaries (that is, the EXE will be composed of 
  2128.                     16-byte 'sectors'). 
  2129.  
  2130. ne_cres             is the number of resources in the EXE.  Each resource uses 
  2131.                     a segment. 
  2132.  
  2133. More information on the 16-bit EXE header can be found in NEWEXE.H, which comes 
  2134. with the Developer's toolkit. Unfortunately, it isn't very informative. 
  2135.  
  2136. Extracting a Resource From The EXE 
  2137.  
  2138. The process of extracting resources from an EXE to a RES file is quite simple. 
  2139. We walk through the resource table (rsrctab), and, for each entry, we find and 
  2140. emit the corresponding segment.  (We have to twiddle the segment flag and 
  2141. create a small header for the resource, but that's not a big deal.) 
  2142.  
  2143. o First, we have to find the corresponding resource table entry (resource 
  2144.   number cnt): 
  2145.  
  2146.        call charin infile,base+rsrctab+cnt*4,0
  2147.  
  2148. o Then, we have to read the entry's content: 
  2149.  
  2150.        etype = readw()
  2151.        ename = readw()
  2152.  
  2153. o Then, we have to find and read the corresponding segment table entry: 
  2154.  
  2155.        call segin cseg-rsrccnt+1+cnt
  2156.  
  2157. o Then we...(I'm using a procedure here for readability.) 
  2158.  
  2159.     segin:
  2160.        call charin infile,base+segtab+(arg(1)-1)*8,0
  2161.        ssector = readw()
  2162.        cb = readw()
  2163.        sflags = readw()
  2164.        smin = readw()
  2165.  
  2166. o We then calculate the resource offset: 
  2167.  
  2168.        pos = 1+(2**segshift)*ssector
  2169.  
  2170. o And we translate the segment flag (from NSMMOVE, etc. to MOVEABLE, etc.): 
  2171.  
  2172.        flags = 0
  2173.        if bit(sflags,10) then flags = flags+64
  2174.        if bit(sflags,12) then flags = flags+16
  2175.        if bit(sflags,4) then flags = flags+4096
  2176.        if \ bit(sflags,11) then flags = flags+32
  2177.  
  2178. o We are now ready to write the resource header to a RES file: 
  2179.  
  2180.        call emit 'FF'x||d2w(etype)'FF'x||d2w(ename)d2w(flags)d2l(cb)
  2181.  
  2182. o And, last but not least, we have to write the resource data, too: 
  2183.  
  2184.        call emit charin(infile,pos,cb)
  2185.  
  2186. Note:  The RES format is explained in the section The RES File Format 
  2187.  
  2188. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2189.  
  2190.  
  2191. ΓòÉΓòÉΓòÉ 2.2.4. Exploring 32-Bit Headers ΓòÉΓòÉΓòÉ
  2192.  
  2193. Exploring 32-Bit Headers 
  2194.  
  2195. Recognizing a 32-bit EXE header 
  2196.  
  2197. A 32-bit EXE header starts with the 'LX' magic number; a 32-bit structure 
  2198. starts with this magic number: 
  2199.  
  2200. struct e32_exe                          /* New 32-bit .EXE header */
  2201. {
  2202.     unsigned char       e32_magic[2];   /* Magic number E32_MAGIC */
  2203.     unsigned char       e32_border;     /* The byte ordering for the .EXE */
  2204.     unsigned char       e32_worder;     /* The word ordering for the .EXE */
  2205.     unsigned long       e32_level;      /* The EXE format level for now = 0 */
  2206.     unsigned short      e32_cpu;        /* The CPU type */
  2207.     unsigned short      e32_os;         /* The OS type */
  2208.     unsigned long       e32_ver;        /* Module version */
  2209.     unsigned long       e32_mflags;     /* Module flags */
  2210.     unsigned long       e32_mpages;     /* Module # pages */
  2211.     unsigned long       e32_startobj;   /* Object # for instruction pointer */
  2212.     unsigned long       e32_eip;        /* Extended instruction pointer */
  2213.     unsigned long       e32_stackobj;   /* Object # for stack pointer */
  2214.     unsigned long       e32_esp;        /* Extended stack pointer */
  2215.     unsigned long       e32_pagesize;   /* .EXE page size */
  2216.     unsigned long       e32_pageshift;  /* Page alignment shift in .EXE */
  2217.     unsigned long       e32_fixupsize;  /* Fixup section size */
  2218.     unsigned long       e32_fixupsum;   /* Fixup section checksum */
  2219.     unsigned long       e32_ldrsize;    /* Loader section size */
  2220.     unsigned long       e32_ldrsum;     /* Loader section checksum */
  2221.     unsigned long       e32_objtab;     /* Object table offset */
  2222.     unsigned long       e32_objcnt;     /* Number of objects in module */
  2223.     unsigned long       e32_objmap;     /* Object page map offset */
  2224.     unsigned long       e32_itermap;    /* Object iterated data map offset */
  2225.     unsigned long       e32_rsrctab;    /* Offset of Resource Table */
  2226.     unsigned long       e32_rsrccnt;    /* Number of resource entries */
  2227.     unsigned long       e32_restab;     /* Offset of resident name table */
  2228.     unsigned long       e32_enttab;     /* Offset of Entry Table */
  2229.     unsigned long       e32_dirtab;     /* Offset of Module Directive Table */
  2230.     unsigned long       e32_dircnt;     /* Number of module directives */
  2231.     unsigned long       e32_fpagetab;   /* Offset of Fixup Page Table */
  2232.     unsigned long       e32_frectab;    /* Offset of Fixup Record Table */
  2233.     unsigned long       e32_impmod;     /* Offset of Import Module Name Table */
  2234.     unsigned long       e32_impmodcnt;  /* Number of entries in Import Module Name Table */
  2235.     unsigned long       e32_impproc;    /* Offset of Import Procedure Name Table
  2236.     unsigned long       e32_pagesum;    /* Offset of Per-Page Checksum Table */
  2237.     unsigned long       e32_datapage;   /* Offset of Enumerated Data Pages */
  2238.     unsigned long       e32_preload;    /* Number of preload pages */
  2239.     unsigned long       e32_nrestab;    /* Offset of Non-resident Names Table */
  2240.     unsigned long       e32_cbnrestab;  /* Size of Non-resident Name Table */
  2241.     unsigned long       e32_nressum;    /* Non-resident Name Table Checksum */
  2242.     unsigned long       e32_autodata;   /* Object # for automatic data object */
  2243.     unsigned long       e32_debuginfo;  /* Offset of the debugging information */
  2244.     unsigned long       e32_debuglen;   /* The length of the debugging info. in bytes */
  2245.     unsigned long       e32_instpreload;/* Number of instance pages in preload section of .EXE file */
  2246.     unsigned long       e32_instdemand; /* Number of instance pages in demand load section of .EXE file */
  2247.     unsigned long       e32_heapsize;   /* Size of heap - for 16-bit apps */
  2248.     unsigned long       e32_stacksize;  /* Size of stack */
  2249.     unsigned char       e32_res3[E32RESBYTES3];
  2250.                                         /* Pad structure to 196 bytes */
  2251.   };
  2252.  
  2253. Figure 3.  The OS/2 386 .EXE header. 
  2254.  
  2255. The following fields interest us: 
  2256.  
  2257. Field               Contents 
  2258.  
  2259. e32_pageshift       is the page alignment shift in the EXE.  It's the number of 
  2260.                     bits we should shift the page offset value to find the 
  2261.                     page's position in EXE. 
  2262.  
  2263.                     For example, if e32_pageshift is 4, pages will be aligned 
  2264.                     on 16-byte boundaries. 
  2265.  
  2266. e32_objtab          is the object table offset. Each entry contains the 
  2267.                     following fields: 
  2268.  
  2269.                                          32                    1 32                    1
  2270.                                         ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2271.                                         Γöé        size           Γöé        base           Γöé
  2272.                                         Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2273.                                         Γöé        flags          Γöé       pagemap         Γöé
  2274.                                         Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2275.                                         Γöé       mapsize         Γöé      reserved         Γöé
  2276.                                         ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2277.  
  2278.    o size is the object virtual size. 
  2279.  
  2280.    o base is the object base virtual address. 
  2281.  
  2282.    o flags is the object attribute flags. 
  2283.  
  2284.    o pagemap is the object page map index. 
  2285.  
  2286.    o mapsize is the number of entry in the object's page map. 
  2287.  
  2288.    o reserved is, well, reserved :-) 
  2289.  
  2290.                     We're only interested by flags and pagemap. That is, flags 
  2291.                     contains the resource flags (MOVEABLE, LOADONCALL, and so 
  2292.                     on), while pagemap allows us to find the object's pages 
  2293.                     within the EXE.  (See the "Tables and Maps Relations" 
  2294.                     section below, for more explanations on pagemap, the object 
  2295.                     table, and other tables.) 
  2296.  
  2297.                     flags' interesting bits are: 
  2298.  
  2299.    OBJWRITE            0x0002L  Writeable Object 
  2300.    OBJDISCARD          0x0010L  Object is Discardable 
  2301.    OBJSHARED           0x0020L  Object is Shared 
  2302.    OBJPRELOAD          0x0040L  Object has preload pages 
  2303.  
  2304.                     Note:  The object table offset is from the beginning of the 
  2305.                     386 EXE header, not from the beginning of the EXE. 
  2306.  
  2307. e32_objmap          is the object page map offset.  Each entry contains the 
  2308.                     following fields: 
  2309.  
  2310.                                          32                    1 16         1 16        1
  2311.                                         ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2312.                                         Γöé    pagedataoffset     Γöé  pagesize  Γöé pageflags Γöé
  2313.                                         ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2314.  
  2315.    o pagedataoffset is the file offset of page. 
  2316.  
  2317.    o pagesize is the number of bytes of page data. 
  2318.  
  2319.    o pageflags is per-page attributes. 
  2320.  
  2321.                     Note:  The object page map offset is from the beginning of 
  2322.                     the 386 EXE header, not from the beginning of the EXE. 
  2323.  
  2324. e32_rsrctab         is the offset of the resource table. Each entry contains 
  2325.                     the following fields: 
  2326.  
  2327.                                          16        1 16        1 32                     1
  2328.                                         ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2329.                                         Γöé    type   Γöé    name   Γöé          cb            Γöé
  2330.                                         Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2331.                                         Γöé    obj    Γöé        offset          Γöé
  2332.                                         ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2333.                                          16        1 32                     1
  2334.  
  2335.    o type is the resource type. 
  2336.  
  2337.    o name is the resource name. 
  2338.  
  2339.    o cb is the resource size, in bytes. 
  2340.  
  2341.    o obj is the number of the object containing the resource. 
  2342.  
  2343.    o offset is the resource's offset within object.  Resource will be in object 
  2344.      obj, starting at the specified offset: 
  2345.  
  2346.                                             0                  offset         offset+cb
  2347.                                            ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2348.                                         objΓöé                     Γöé<-  resource  ->Γöé       ...
  2349.                                            ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2350.  
  2351.                     Note:  The resource table offset is from the beginning of 
  2352.                     the 386 EXE header, not from the beginning of the EXE. 
  2353.  
  2354. e32_rsrccnt         is the number of resources in the EXE. 
  2355.  
  2356. e32_datapage        is the offset of Enumerated data page.  It's the position 
  2357.                     of the first data page in the EXE. 
  2358.  
  2359.                     Warning: This offset is from the beginning of the EXE, not 
  2360.                     from the beginning of the 386 EXE header.  It's THE 
  2361.                     exception :-/ 
  2362.  
  2363. More information on the 32-bit EXE header can be found on exe386.h, which comes 
  2364. with the Developer's toolkit.  It's not that informative, though, and OMF.INF 
  2365. is much better.  I highly recommend it. 
  2366.  
  2367. Tables and Maps Relations 
  2368.  
  2369. In this section, we will view the various relations between tables and maps. 
  2370.  
  2371.      ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2372. file Γöé                               Γöé  Γöé         Γöé  Γöé         ...
  2373.      ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2374.                                                  
  2375.                       object's page 1Γöé            Γöé object's page 2
  2376.                                      ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé
  2377.                                                 Γöé Γöé
  2378.                                                 Γöé Γöé
  2379.   :                                             Γöé Γöé
  2380.     Γöé    Γöé            Γöé    Γöé          : Γöé    Γöé  Γöé Γöé
  2381.  r-1Γöé    Γöé            Γöé    Γöé      ΓöîΓöÇΓöÇΓöÇΓöÇΓö£ΓöÇΓöÇΓöÇΓöÇΓöñ  Γöé Γöé
  2382.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ          : Γöé    Γöé      Γöé   p Γöé    Γöé ΓöÇΓöÿ Γöé
  2383.   r Γöé    Γöé ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ     Γöé    Γöé      Γöé     Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ    Γöé
  2384.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ      Γöé  o-1Γöé    Γöé      Γöé  p+1Γöé    Γöé ΓöÇΓöÇΓöÇΓöÿ
  2385.  r+1Γöé    Γöé      ΓööΓöÇΓöÇΓöÇΓöÇΓö£ΓöÇΓöÇΓöÇΓöÇΓöñ      Γöé     Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ
  2386.     Γöé    Γöé          o Γöé    Γöé ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ   : Γöé    Γöé
  2387.   : Γöé    Γöé            Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ            Γöé    Γöé
  2388.     Γöé    Γöé         o+1Γöé    Γöé            Γöé    Γöé
  2389.  
  2390.    resource           object           page map
  2391.     table             table
  2392.  
  2393. Figure 4.  Tables and maps relations. 
  2394.  
  2395. To find the data of a resource r, we first have to read the corresponding entry 
  2396. in the resource table.  The obj field of this entry allows us to find the 
  2397. object which contains the data.  The pagemap field of the object table entry 
  2398. then allows us to locate the object's pages in the EXE, via the page map.  To 
  2399. find the resource data, we then just have to read cb bytes from object, 
  2400. starting at offset. 
  2401.  
  2402. Extracting a Resource From The EXE 
  2403.  
  2404. The process of extracting resources from a 32-bit EXE to a RES file is similar 
  2405. to the 16-bit EXE to RES conversion.  We walk through the resource table 
  2406. (rsrctab), and, for each entry, we find and emit the corresponding resource. 
  2407. (We have to twiddle the object flag and create a small header for the resource, 
  2408. but that's not a big deal.) 
  2409.  
  2410. Note:  In the following code, we'll assume that objects span over consecutive 
  2411. pages.  That is, we will not handle the case where the object's pages are 
  2412. arranged discontinuously in the EXE. 
  2413.  
  2414. o First, we have to find the corresponding resource table entry (resource 
  2415.   number cnt): 
  2416.  
  2417.        call charin infile,base+rsrctab+cnt*14,0
  2418.  
  2419. o Then, we have to read the entry's content: 
  2420.  
  2421.        etype = readw()                   /* resource type              */
  2422.        ename = readw()                   /* resource name              */
  2423.        cb = readl()                      /* resource size              */
  2424.        eobj = readw()                    /* object containing resource */
  2425.        eoffset = readl()                 /* resource's offset in eobj  */
  2426.        call objin eobj
  2427.  
  2428.   (I'm using a procedure here for readability.) 
  2429.  
  2430.     objin:
  2431.        call charin infile,base+objtab+(arg(1)-1)*24,8
  2432.        oflags = readl()                  /* object attributes          */
  2433.        opagemap = readl()                /* object page map index      */
  2434.        omapsize = readl()                /* -- not used --             */
  2435.        opagedataoffset = l2d(charin(infile,base+objmap+(opagemap-1)*8,4))
  2436.  
  2437. o We then calculate the resource offset: 
  2438.  
  2439.        pos = 1+datapage+eoffset+(2**pageshift)*opagedataoffset
  2440.  
  2441. o And we translate the object flag (from OBJPRELOAD, ... to LOADONCALL, ...): 
  2442.  
  2443.        flags = 0
  2444.        if bit(oflags,10) then flags = flags+64
  2445.        if bit(oflags,11) then flags = flags+16
  2446.        if bit(oflags,12) then flags = flags+4096
  2447.        if \ bit(oflags,15) then flags = flags+32
  2448.  
  2449. o We are now ready to write the resource header to a RES file: 
  2450.  
  2451.        call emit 'FF'x||d2w(etype)'FF'x||d2w(ename)d2w(flags)d2l(cb)
  2452.  
  2453. o And, last but not least, we have to write the resource data, too: 
  2454.  
  2455.        call emit charin(infile,pos,cb)
  2456.  
  2457. Note:  The RES format is explained in the next section (The RES file format). 
  2458.  
  2459. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2460.  
  2461.  
  2462. ΓòÉΓòÉΓòÉ 2.2.5. The RES to RC Translation ΓòÉΓòÉΓòÉ
  2463.  
  2464. The RES to RC Translation 
  2465.  
  2466. And now the last part.  First, we will describe the RES format, and we will 
  2467. then describe some resources data.  We will focus our interest on the 
  2468. human-readable resources, such as menus, stringtables and so on. 
  2469.  
  2470. Note:  An important exception will be the dialog templates, for the following 
  2471. two reasons: 
  2472.  
  2473. o The Dialog editor already does this. 
  2474. o It's not that different from the others resources, and it would necessitated 
  2475.   an even more fastidious enumeration. 
  2476.  
  2477. For these reasons, our resource decompiler will not extract dialog templates 
  2478. from RES to RC. 
  2479.  
  2480. And we will finally describe briefly the included resource decompiler, rdc. 
  2481.  
  2482. The RES format 
  2483.  
  2484. The RES file is an aggregate of resources.  Each resource is composed of a 
  2485. header, followed by the resource data. 
  2486.  
  2487.  8  1 16          1 8  1 16         1 16        1
  2488. ΓöîΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2489. Γöé0xFFΓöé     Type    Γöé0xFFΓöé     Id     Γöé   Flags   Γöé
  2490. Γö£ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2491. Γöé          cb           Γöé
  2492. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2493.  32                    1
  2494.  
  2495. Figure 5.  The resource header. 
  2496.  
  2497. Type is the resource type (see below). 
  2498.  
  2499. Id is the resource name/identifier. 
  2500.  
  2501. Flags is the resource attributes (MOVEABLE, LOADONCALL, ...). 
  2502.  
  2503. cb is the resource size. 
  2504.  
  2505. The following types may appear: 
  2506.  
  2507. RT_POINTER               1  /* mouse pointer shape */ 
  2508. RT_BITMAP                2  /* bitmap */ 
  2509. RT_MENU                  3  /* menu template */ 
  2510. RT_DIALOG                4  /* dialog template */ 
  2511. RT_STRING                5  /* string tables */ 
  2512. RT_FONTDIR               6  /* font directory */ 
  2513. RT_FONT                  7  /* font */ 
  2514. RT_ACCELTABLE            8  /* accelerator tables */ 
  2515. RT_RCDATA                9  /* binary data */ 
  2516. RT_MESSAGE               10  /* error msg tables */ 
  2517. RT_DLGINCLUDE            11  /* dialog include file name */ 
  2518. RT_VKEYTBL               12  /* key to vkey tables */ 
  2519. RT_KEYTBL                13  /* key to UGL tables */ 
  2520. RT_CHARTBL               14  /* glyph to character tables */ 
  2521. RT_DISPLAYINFO           15  /* screen display information */ 
  2522. RT_FKASHORT              16  /* function key area short form */ 
  2523. RT_FKALONG               17  /* function key area long form */ 
  2524. RT_HELPTABLE             18  /* Help table for Cary Help manager */ 
  2525. RT_HELPSUBTABLE          19  /* Help subtable for Cary Help manager */ 
  2526. RT_FDDIR                 20  /* DBCS uniq/font driver directory */ 
  2527. RT_FD                    21  /* DBCS uniq/font driver */ 
  2528.  
  2529. Other values for type denote user-defined resources. 
  2530.  
  2531. Resource data format 
  2532.  
  2533. We first have to read the resource header: 
  2534.  
  2535. res2rc:  /* convert .RES format to .RC */
  2536.    call skip 1                       /* skipping the 'FF'x     */
  2537.    rt = readw()                      /* the resource type      */
  2538.    call skip 1                       /* skipping the 'FF'x     */
  2539.    id = readw()                      /* the resource ID/name   */
  2540.    opt = readw()                     /* the resource flag      */
  2541.    cb = readl()                      /* the resource data size */
  2542.  
  2543. Then, according to the resource type, we'll have to do specific operations: 
  2544.  
  2545.    select
  2546.       when rt = 1  then call emit 'POINTER 'id' 'option()' 'file('ptr')nl
  2547.       when rt = 2  then call emit 'BITMAP 'id' 'option()' 'file('bmp')nl
  2548.       when rt = 7  then call emit 'FONT 'id' 'option()' 'file('fon')nl
  2549.  
  2550. If the resource is a pointer, a bitmap, a font or an icon, the resource data is 
  2551. the corresponding pointer, bitmap, font or icon.  We then just have to recreate 
  2552. a file containing this data. 
  2553.  
  2554.       when rt = 3  then do; call emit 'MENU 'id' 'option()nl'BEGIN'nl; call emit menuout('  ')nl'END'nl; end
  2555.  
  2556. If the resource is a menu, it's not that simple :-)  The resource data is the 
  2557. corresponding menu structure: 
  2558.  
  2559.  16   1 16   1 16   1 16   1 16   1
  2560. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2561. Γöé  cb  Γöé type Γöé  cp  Γöé offs Γöé countΓöé                    ...
  2562. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2563.  
  2564. cb is the size of the menu data. 
  2565.  
  2566. type is the menu type (Only 0 and 1 are valid). 
  2567.  
  2568. cp is the menu code page (850 by default). 
  2569.  
  2570. offs is the starting offset of the menu data, from the start of the structure. 
  2571.  
  2572. count is the number of item composing the menu. 
  2573.  
  2574. If the menu type is 1, count is followed by another 16-bit field, ppoffs 
  2575. (presentation parameter offset, from the start of the structure).  But we won't 
  2576. handle type 1 menus, so... 
  2577.  
  2578. Every item has the following format: 
  2579.  
  2580.  16   1 16   1 16   1
  2581. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2582. Γöéstyle ΓöéattribΓöé  Id  Γöé [Optional Data]
  2583. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2584.  
  2585. style is the item style (MIS_*). 
  2586.  
  2587. attrib is the item attributes (MIA_*). 
  2588.  
  2589. Id is the item identifier. 
  2590.  
  2591. If the item contains data (that is, if item is a submenu, or has the 
  2592. MIS_BITMAP, MIS_STRING or ... style), then the previous structure is followed 
  2593. by the corresponding data: 
  2594.  
  2595. MIS_SUBMENU         Data is a menu structure, as previously defined. 
  2596. MIS_STRING          Data is a null-terminated string. 
  2597. MIS_BITMAP          Data can be any of the following: 
  2598.  
  2599.              'FF'x, followed by a 16-bit word, representing the resource 
  2600.              identifier. 
  2601.              '00'x.  No resource identifier provided. 
  2602.              "#", and subsequent characters make up the decimal representation 
  2603.              of the resource identifier. 
  2604.  
  2605. So, if the resource is a menu, we will have to emit each item, recursively (as 
  2606. a menu can contain a submenu, ...). 
  2607.  
  2608.       when rt = 5  then call emit 'STRINGTABLE 'option()nl'BEGIN'strout()'END'nl
  2609.       when rt = 10 then call emit 'MESSAGETABLE 'option()nl'BEGIN'strout()'END'nl
  2610.  
  2611. If the resource is a stringtable or a messagetable, then we have to emit the 
  2612. corresponding table.  Each string/messagetable contains up to 16 strings. (In a 
  2613. RC file, you can have more than one stringtable, with more than 16 strings, but 
  2614. rc does not preserve your ordering -- string IDs are maintained, though.) 
  2615.  
  2616. In the RES file, STRINGTABLE data looks like the following: 
  2617.  
  2618.  16   1 8 1 1               len+1 8 1
  2619. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2620. Γöé dummyΓöélenΓöéstring1             0ΓöélenΓöéstring2           ...
  2621. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2622.  
  2623. Each string is zero-terminated.  If len is zero, the string does not exists. 
  2624.  
  2625.       when rt = 8  then do; call emit 'ACCELTABLE 'id' 'option()nl'BEGIN'nl||keyout()'END'nl; end
  2626.  
  2627. If the resource is an acceltable, then we have to emit the corresponding table. 
  2628. ACCELTABLE resource data looks like the following: 
  2629.  
  2630.  16  1 16  1 16  1 16  1 16  1
  2631. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2632. ΓöécountΓöé  cp Γöétype1Γöékey1 Γöécmd1 Γöétype2Γöé...                ...
  2633. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2634.  
  2635. count is the number of keys in the acceltable. 
  2636.  
  2637. cp is the acceltable codepage. 
  2638.  
  2639. And the type/key/cmd triplets describe the accel-keys : 
  2640.  
  2641. type is the key's type (VIRTUALKEY, shifted, ...). 
  2642.  
  2643. key is the key's value (VK_F1, "a", ...). 
  2644.  
  2645. cmd is the accel command. 
  2646.  
  2647.       when rt = 11 then do; call emit 'DLGINCLUDE 'id' 'charin(infile,,cb)nl; cb = 0; end
  2648.  
  2649. If the resource is a dlginclude statement, then the resource data will contain 
  2650. the included file name. 
  2651.  
  2652. Note:  This information is of little value if you don't have the included 
  2653. file... 
  2654.  
  2655.       when rt = 18 then call emit 'HELPTABLE 'id||nl'BEGIN'htout()'END'nl
  2656.  
  2657. If the resource is a helptable, then the resource data will contain the 
  2658. following: 
  2659.  
  2660.  16  1 16  1 16  1 16  1
  2661. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2662. Γöéwnd 1Γöésub 1Γöé-----Γöéext 1Γöéwnd 2Γöésub 2Γöé-----Γöéext 2Γöé       ...
  2663. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2664.  <     helpitem  1     > <     helpitem  2     >
  2665.  
  2666. wnd n is the application window ID. 
  2667.  
  2668. sub n is the help subtable ID. 
  2669.  
  2670. ext n is the extended help panel ID. 
  2671.  
  2672.       when rt = 19 then call emit 'HELPSUBTABLE 'id||hstout()nl
  2673.  
  2674. If the resource is a HELPSUBTABLE, then the resource data will contain the 
  2675. following: 
  2676.  
  2677.  16  1 16  1 16  1
  2678. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2679. Γöésize Γöéwnd 1Γöéhelp1Γöéwnd 2Γöéhelp2Γöé                         ...
  2680. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  2681.        <subitem 1> <subitem 2>
  2682.  
  2683. Each subitem contains size items (the default size value is 2): 
  2684.  
  2685. wnd n is the child window ID. 
  2686.  
  2687. help n is the help panel ID. 
  2688.  
  2689. And, if size is more than 2, the remaining integers have an application-defined 
  2690. meaning. 
  2691.  
  2692.    otherwise
  2693.       call emit 'RESOURCE 'rt' 'id' 'option()' 'file('dat')
  2694.  
  2695. If the resource is of any other type, then we emit the 'RESOURCE' generic 
  2696. statement, and we put the resource data in a .DAT file.  The rc compiler will 
  2697. handle that gracefully.  :-) 
  2698.  
  2699.    end  /* select */
  2700.  
  2701. The Resource decompiler 
  2702.  
  2703. The interesting part, at last!  A resource decompiler (named rdc.cmd)  is 
  2704. provided in rdc.zip.  It's usage is as follow: 
  2705.  
  2706. Usage:  rdc [<options>] <.EXE input file> [<.RC output file>]
  2707.         -r              - Extract .res file
  2708.         -h              - Access Help
  2709.  
  2710. Figure 6.  The resource decompiler usage. 
  2711.  
  2712. Note:  Please note the following: 
  2713.  
  2714. o It's not highly polished. 
  2715. o The RES to RC translation part is known to be buggy. 
  2716. o You can't directly obtain a RC file from an EXE.  You have to take a two-step 
  2717.   process (first, rdc -r xxx.exe, and then rdc xxx.res xxx.rc). 
  2718. o If files named res_*.* are present in the current directory, you'll get a 
  2719.   strange result.  (And it may trash these files.) 
  2720. o The default RC file extension is '.RC2'.  It'll protect you from bad 
  2721.   surprises. 
  2722. o And, as stated earlier, it does not extract dialog templates from RES to RC 
  2723.   files (but it does extract them from EXE to RES). 
  2724.  
  2725. But, to be optimistic, it works just fine most of the time :-) 
  2726.  
  2727. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2728.  
  2729.  
  2730. ΓòÉΓòÉΓòÉ 2.2.6. Summary ΓòÉΓòÉΓòÉ
  2731.  
  2732. Summary 
  2733.  
  2734. In the previous parts, we have seen how to extract resources from an executable 
  2735. (a .EXE or a .DLL), and how to extract some resources from a .RES file, as we 
  2736. have focused our interest on the 'human-readable' resources. 
  2737.  
  2738. While I realize there are still many obscure points, I hope you will find the 
  2739. included information useful.  And I'll try my best to answer all questions on 
  2740. it. 
  2741.  
  2742. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2743.  
  2744.  
  2745. ΓòÉΓòÉΓòÉ 2.2.7. Bibliography ΓòÉΓòÉΓòÉ
  2746.  
  2747. Bibliography 
  2748.  
  2749. On EXE format 
  2750.  
  2751. OMF.INF             describes the new 32-bit file format.  It's a good 
  2752.                     discussion on OMF (Object Module Format) and the 386 EXE 
  2753.                     header.  It's available on ftp-os2.cdrom.com. 
  2754. EXE.H, EXE386.H and NEWEXE.H These C header files contain the various EXE 
  2755.                     header structures.  But it's not really a good place to 
  2756.                     start with. 
  2757.  
  2758. On RC/RES format 
  2759.  
  2760. Control Program Guide and Reference This on-line manual describes the 
  2761.                     DosGetResource/DosFreeResource APIs. It's part of the 
  2762.                     Developer's toolkit. 
  2763. PM Reference        This on-line manual contains much useful information on the 
  2764.                     resource data format (In Related Information/Resource 
  2765.                     File).  It's part of the Developer's toolkit. 
  2766. Tools Reference     This on-line manual contains the Resource Compiler 
  2767.                     reference.  It describes all RC statements/directives. 
  2768.                     It's part of the Developer's toolkit. 
  2769.  
  2770. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2771.  
  2772.  
  2773. ΓòÉΓòÉΓòÉ <hidden> outname ΓòÉΓòÉΓòÉ
  2774.  
  2775. outname 
  2776.  
  2777. This function, which requires two parameters, returns an output filename (if 
  2778. one does not already exists). 
  2779.  
  2780. outname: /* return name made from infile and extension */
  2781.    if outfile = '' then
  2782.       if lastpos('.',arg(1)) > lastpos('\',arg(1)) then
  2783.          outfile = left(arg(1),lastpos('.',arg(1)))arg(2)
  2784.       else
  2785.          outfile = arg(1)'.'arg(2)
  2786.    return outfile
  2787.  
  2788. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2789.  
  2790.  
  2791. ΓòÉΓòÉΓòÉ <hidden> readw ΓòÉΓòÉΓòÉ
  2792.  
  2793. readw 
  2794.  
  2795. This function reads one word (two bytes) from current file position.  The 
  2796. file's position is updated. 
  2797.  
  2798. readw:   /* read one word from infile */
  2799.    return w2d(charin(infile,,2))
  2800.  
  2801. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2802.  
  2803.  
  2804. ΓòÉΓòÉΓòÉ <hidden> readl ΓòÉΓòÉΓòÉ
  2805.  
  2806. readl 
  2807.  
  2808. This function reads one long word (four bytes) from current file position. The 
  2809. file's position is updated. 
  2810.  
  2811. readl:   /* read one long from infile */
  2812.    return l2d(charin(infile,,4))
  2813.  
  2814. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2815.  
  2816.  
  2817. ΓòÉΓòÉΓòÉ <hidden> skip ΓòÉΓòÉΓòÉ
  2818.  
  2819. skip 
  2820.  
  2821. This function skips arg(1) chars in current file.  The file's position is 
  2822. updated. 
  2823.  
  2824. skip:    /* skip arg(1) chars */
  2825.    return charin(infile,,arg(1))
  2826.  
  2827. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2828.  
  2829.  
  2830. ΓòÉΓòÉΓòÉ <hidden> bit ΓòÉΓòÉΓòÉ
  2831.  
  2832. bit 
  2833.  
  2834. This function returns bit arg(2) of arg(1).  arg(1) can contain up to 32 bits. 
  2835.  
  2836. Note:  bits are numbered from left to right. 
  2837.  
  2838. bit:     /* return bit arg(2) of arg(1) */
  2839.    return substr(x2b(d2x(arg(1),4)), arg(2),1)
  2840.  
  2841. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2842.  
  2843.  
  2844. ΓòÉΓòÉΓòÉ <hidden> w2d ΓòÉΓòÉΓòÉ
  2845.  
  2846. w2d 
  2847.  
  2848. This function translates a little-endian word to a REXX integer. 
  2849.  
  2850. w2d:     /* little-endian word to decimal */
  2851.    w = c2x(arg(1))
  2852.    return x2d(substr(w,3,2)substr(w,1,2))
  2853.  
  2854. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2855.  
  2856.  
  2857. ΓòÉΓòÉΓòÉ <hidden> d2w ΓòÉΓòÉΓòÉ
  2858.  
  2859. d2w 
  2860.  
  2861. This function translates a REXX integer to a little-endian word. 
  2862.  
  2863. d2w:     /* decimal to little-endian word */
  2864.    w = d2x(arg(1),4)
  2865.    return x2c(substr(w,3,2)substr(w,1,2))
  2866.  
  2867. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2868.  
  2869.  
  2870. ΓòÉΓòÉΓòÉ <hidden> l2d ΓòÉΓòÉΓòÉ
  2871.  
  2872. l2d 
  2873.  
  2874. This function translates a little-endian long word to a REXX integer. 
  2875.  
  2876. l2d:     /* little-endian long to decimal */
  2877.    l = c2x(arg(1))
  2878.    return x2d(substr(l,7,2)substr(l,5,2)substr(l,3,2)substr(l,1,2))
  2879.  
  2880. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2881.  
  2882.  
  2883. ΓòÉΓòÉΓòÉ <hidden> d2l ΓòÉΓòÉΓòÉ
  2884.  
  2885. d2l 
  2886.  
  2887. This function translates a REXX integer to a little-endian long word. 
  2888.  
  2889. d2l:     /* decimal to little-endian long */
  2890.    l = d2x(arg(1),8)
  2891.    return x2c(substr(l,7,2)substr(l,5,2)substr(l,3,2)substr(l,1,2))
  2892.  
  2893. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2894.  
  2895.  
  2896. ΓòÉΓòÉΓòÉ <hidden> emit ΓòÉΓòÉΓòÉ
  2897.  
  2898. emit 
  2899.  
  2900. This function writes arg(1) to output file. 
  2901.  
  2902. emit:    /* write data to output file */
  2903.    return charout(outfile,arg(1))
  2904.  
  2905. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2906.  
  2907.  
  2908. ΓòÉΓòÉΓòÉ <hidden> option ΓòÉΓòÉΓòÉ
  2909.  
  2910. option 
  2911.  
  2912. This function translates the option's attributes into a RC string. 
  2913.  
  2914. option:  /* convert flags to option string */
  2915.    if bit(opt,10) then r = 'PRELOAD'; else r = 'LOADONCALL'
  2916.    if bit(opt,12) then r = r' MOVEABLE'
  2917.    if bit(opt, 4) then r = r' DISCARDABLE'
  2918.    if \ (bit(opt,4) | bit(opt,12)) then r = r' FIXED'
  2919.    if r = 'LOADONCALL MOVEABLE DISCARDABLE' then r = ''
  2920.    return r
  2921.  
  2922. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2923.  
  2924.  
  2925. ΓòÉΓòÉΓòÉ <hidden> file ΓòÉΓòÉΓòÉ
  2926.  
  2927. file 
  2928.  
  2929. This function creates a new file, with extension arg(1), and fill it with cb 
  2930. bytes of infile. 
  2931.  
  2932. file:    /* write cb bytes to res_xxx.arg(1) */
  2933.    r = 'res_'right(fnum,4,'0')'.'arg(1)
  2934.    call charout r,charin(infile,,cb)
  2935.    fnum = fnum+1; cb = 0
  2936.    call stream r,'c','close'
  2937.    return r
  2938.  
  2939. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2940.  
  2941.  
  2942. ΓòÉΓòÉΓòÉ <hidden> strout ΓòÉΓòÉΓòÉ
  2943.  
  2944. strout 
  2945.  
  2946. This function extracts a string/messagetable definitions, and returns a string 
  2947. containing the table. 
  2948.  
  2949. strout:  /* extract strings definitions */
  2950.    call skip 2
  2951.    id = (id-1)*16; cb = cb-2; r = nl
  2952.    do while cb > 0
  2953.       len = x2d(c2x(charin(infile,,1)))
  2954.       if len > 1 then r = r'  'left(id,8)'"'charin(infile,,len-1)'"'nl
  2955.       call skip 1
  2956.       id = id+1; cb = cb-len-1
  2957.    end /* do */
  2958.    return r
  2959.  
  2960. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2961.  
  2962.  
  2963. ΓòÉΓòÉΓòÉ <hidden> keyout ΓòÉΓòÉΓòÉ
  2964.  
  2965. keyout 
  2966.  
  2967. This functions extracts an acceltable definition, and returns a string 
  2968. containing the acceltable. 
  2969.  
  2970. keyout:  /* extract acceltable definitions */
  2971.    procedure expose nl cb infile outfile
  2972.    cnt = readw()
  2973.    cp = readw()
  2974.    cb = cb-4
  2975.    if cp \= 850 then call emit arg(1)'CODEPAGE 'cp||nl
  2976.    do cnt
  2977.       typ = readw()
  2978.       key = readw()
  2979.       if \ bit(typ,15) & key >= 32 & key <= 255 then key = '"'d2c(key)'"'; else key = '0x'd2x(key)
  2980.       cmd = readw()
  2981.       cb = cb-6; t = ''
  2982.       if bit(typ,16) then t = t', CHAR'
  2983.       if bit(typ,15) then t = t', VIRTUALKEY'
  2984.       if bit(typ,14) then t = t', SCANCODE'
  2985.       if bit(typ,13) then t = t', SHIFT'
  2986.       if bit(typ,12) then t = t', CONTROL'
  2987.       if bit(typ,11) then t = t', ALT'
  2988.       if bit(typ,10) then t = t', LONEKEY'
  2989.       if bit(typ, 8) then t = t', SYSCOMMAND'
  2990.       if bit(typ, 7) then t = t', HELP'
  2991.       call emit '  'left(key',',8)left(cmd',',8)substr(t,3)nl
  2992.    end /* do */
  2993.    return ''
  2994.  
  2995. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  2996.  
  2997.  
  2998. ΓòÉΓòÉΓòÉ <hidden> htout ΓòÉΓòÉΓòÉ
  2999.  
  3000. htout 
  3001.  
  3002. This function returns a string containing the HELPTABLE definition. 
  3003.  
  3004. htout:   /* extract helptable definitions */
  3005.    r = nl
  3006.    i = readw()
  3007.    do while i \= 0
  3008.       r = r'  HELPITEM 'i', 'readw()
  3009.       call skip 2
  3010.       r = r', 'readw()nl; cb = cb-8
  3011.       i = readw()
  3012.    end /* do */
  3013.    cb = cb-2
  3014.    return r
  3015.  
  3016. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  3017.  
  3018.  
  3019. ΓòÉΓòÉΓòÉ <hidden> hstout ΓòÉΓòÉΓòÉ
  3020.  
  3021. hstout 
  3022.  
  3023. This function returns a string containing the HELPSUBTABLE definition. 
  3024.  
  3025. hstout:  /* extract helpsubtable definitions */
  3026.    sis = readw()
  3027.    if sis \= 2 then r = nl'SUBITEMSIZE 'sis; else r = ''
  3028.    r = r||nl'BEGIN'nl; cb = cb-2
  3029.    i = readw()
  3030.    do while i \= 0
  3031.       r = r||'  HELPSUBITEM 'i
  3032.       do sis-1; r = r', 'readw(); end
  3033.       cb = cb-2*sis; r = r||nl
  3034.       i = readw();
  3035.    end /* do */
  3036.    cb = cb-2
  3037.    return r'END'
  3038.  
  3039. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  3040.  
  3041.  
  3042. ΓòÉΓòÉΓòÉ <hidden> itemout ΓòÉΓòÉΓòÉ
  3043.  
  3044. itemout 
  3045.  
  3046. This functions emits the current menu item. 
  3047.  
  3048. itemout: /* extract menu item definition */
  3049.    procedure expose nl cb infile outfile
  3050.    cb = cb-6; s = ''; a = ''; r = arg(1)'MENUITEM "'; x = '| MIS_'; y = '| MIA_'
  3051.    sty = readw()
  3052.    att = readw()
  3053.    iid = readw()
  3054.    if \ (bit(sty,13) | bit(sty,14)) then
  3055.       do
  3056.          c = charin(infile); cb = cb-1
  3057.          if c = 'FF'x & bit(sty,15) then do; r = r'#'readw(); cb = cb-2; end
  3058.          else do while c \= '00'x; r = r||c; c = charin(infile); cb = cb-1; end
  3059.       end
  3060.    if bit(sty,15) then s = s x'BITMAP'
  3061.    if bit(sty,14) then s = s x'SEPARATOR'
  3062.    if bit(sty,13) then s = s x'OWNERDRAW'
  3063.    if bit(sty,12) then s = s x'SUBMENU'
  3064.    if bit(sty,11) then s = s x'MULTMENU'
  3065.    if bit(sty,10) then s = s x'SYSCOMMAND'
  3066.    if bit(sty, 9) then s = s x'HELP'
  3067.    if bit(sty, 8) then s = s x'STATIC'
  3068.    if bit(sty, 7) then s = s x'BUTTONSEPARATOR'
  3069.    if bit(sty, 6) then s = s x'BREAK'
  3070.    if bit(sty, 5) then s = s x'BREAKSEPARATOR'
  3071.    if bit(sty, 4) then s = s x'GROUP'
  3072.    if bit(sty, 3) then s = s x'SINGLE'
  3073.    if bit(att,11) then a = a y'NODISMISS'
  3074.    if bit(att, 4) then a = a y'FRAMED'
  3075.    if bit(att, 3) then a = a y'CHECKED'
  3076.    if bit(att, 2) then a = a y'DISABLED'
  3077.    if bit(att, 1) then a = a y'HILITED'
  3078.    if a \= '' then a = ','substr(a,3)
  3079.    if s \= '' then s = ','substr(s,3); else if a \= '' then s = ','
  3080.    call emit r'", 'iid||s||a||nl
  3081.    if bit(sty,12) then do; call emit arg(1)'BEGIN'nl; call emit menuout(arg(1)'  ','')arg(1)'END'nl; end
  3082.    return
  3083.  
  3084. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  3085.  
  3086.  
  3087. ΓòÉΓòÉΓòÉ <hidden> menuout ΓòÉΓòÉΓòÉ
  3088.  
  3089. menuout 
  3090.  
  3091. This functions emit the current menu or submenu. 
  3092.  
  3093. menuout: /* extract menus definitions */
  3094.    procedure expose nl cb infile outfile
  3095.    cb = cb-10;
  3096.    cbs = readw()
  3097.    typ = readw()
  3098.    cp = readw()
  3099.    off = readw()
  3100.    cnt = readw()
  3101.    if arg(2) \= '' then
  3102.       do
  3103.          if cp \= 850 then call emit 'CODEPAGE 'cp||nl
  3104.          call emit arg(2)
  3105.       end /* do */
  3106.    do cnt; call itemout arg(1); end
  3107.    return ''
  3108.  
  3109. Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6 
  3110.  
  3111.  
  3112. ΓòÉΓòÉΓòÉ 2.3. Visual REXX Faceoff ΓòÉΓòÉΓòÉ
  3113.  
  3114.  
  3115. ΓòÉΓòÉΓòÉ 2.3.1. Introduction ΓòÉΓòÉΓòÉ
  3116.  
  3117. Visual Rexx Faceoff 
  3118.  
  3119. Written by Gordon Zeglinski 
  3120.  
  3121. Introduction 
  3122.  
  3123. This issue sees the first part of the Visual Rexx Faceoff.  We start by looking 
  3124. at VX-REXX. 
  3125.  
  3126. The Watcom VX-REXX package includes two 3.5" HD floppies and a 700+ page 
  3127. manual.  The manual is nicely written, but the reference section is slightly 
  3128. hard to use.  (Fortunately, one doesn't have to use it!)  The first few 
  3129. chapters are instructions on how to do things, the rest of the manual is all 
  3130. reference.  There are plenty of sample programs included. 
  3131.  
  3132. Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6 
  3133.  
  3134.  
  3135. ΓòÉΓòÉΓòÉ 2.3.2. Installation ΓòÉΓòÉΓòÉ
  3136.  
  3137. To install VX-REXX, you need about 5-6 megs of free disk space.  The install 
  3138. program is pretty simple and non-intrusive.  It fits in nicely with the OS/2 
  3139. environment.  There's nothing I hate more than these "ego-maniac" install 
  3140. programs that go out of their way to make you sit and watch them install. 
  3141. Fortunately, this package doesn't have one of those.  After answering a few 
  3142. questions, popping in the two disks, and rebooting, we have the following 
  3143. folder on our desktop. 
  3144.  
  3145. Figure 1.  Installation Folder 
  3146.  
  3147. Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6 
  3148.  
  3149.  
  3150. ΓòÉΓòÉΓòÉ 2.3.3. Look and Feel ΓòÉΓòÉΓòÉ
  3151.  
  3152. The interface is neat and easy to use.  It consists of the window you are 
  3153. designing and a tool palette, as shown in figure 2. 
  3154.  
  3155. Figure 2.  User Interface 
  3156.  
  3157. VX-REXX uses SOM to implement its "tools".  Each of the objects in the Tools 
  3158. window (except for the pointer) is a SOM object.  Note, just because VX-REXX is 
  3159. based in SOM does not mean it's a WPS app, which is not a bad thing.  VX-REXX 
  3160. does mimic the feel of the WPS.  Each object has a pop-up menu that can be used 
  3161. to change the various properties of the object you have clicked on.  Figure 2 
  3162. shows the popup for the main window; other objects have similar menus.  Figure 
  3163. 3 shows the properties notebook for a static text object. 
  3164.  
  3165. Figure 3.  Properties Notebook 
  3166.  
  3167. Overall, if you are used to the WPS, you will quickly learn how to configure 
  3168. and create objects.  We now get to the best part of the interface. 
  3169.  
  3170. I found the reference section of the manual a bit difficult to use.  It's hard 
  3171. to find answers to questions like "How do I put text into the damn listbox?!". 
  3172. Fortunately, you don't have to look in the manual for this.  VX has a code 
  3173. insertion ability.  To use this ability, you bring up a context menu, select 
  3174. "Code Insert", then select the action you want the code to perform.  The 
  3175. inserted code will usually require some editing.  In addition to the popup menu 
  3176. method of code insertion, the user can drag a control from the window they are 
  3177. designing and drop it on the code window.  VX-REXX will then prompt the user 
  3178. for the action to perform, after which the code necessary to perform the action 
  3179. is inserted. 
  3180.  
  3181. Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6 
  3182.  
  3183.  
  3184. ΓòÉΓòÉΓòÉ 2.3.4. Wrapping Things Up ΓòÉΓòÉΓòÉ
  3185.  
  3186. I have found one annoying thing/bug in VX, but before I comment on it, I will 
  3187. wait for a response from Watcom tech support.  Next issue, we'll look at VisPro 
  3188. REXX (from HockWare) and see how VX-REXX compares to it. 
  3189.  
  3190. Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6 
  3191.  
  3192.  
  3193. ΓòÉΓòÉΓòÉ 3. Columns ΓòÉΓòÉΓòÉ
  3194.  
  3195. The following columns can be found in this issue: 
  3196.  
  3197. o /dev/EDM/BookReview 
  3198. o C++ Corner 
  3199. o Introduction to PM Programming 
  3200. o Scratch Patch 
  3201.  
  3202. Columns - EDM/2 - June 1994 - Volume 2, Issue 6 
  3203.  
  3204.  
  3205. ΓòÉΓòÉΓòÉ 3.1. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
  3206.  
  3207.  
  3208. ΓòÉΓòÉΓòÉ 3.1.1. Introduction ΓòÉΓòÉΓòÉ
  3209.  
  3210. /dev/EDM2/BookReview 
  3211.  
  3212. Written by Carsten Whimster 
  3213.  
  3214. Introduction 
  3215.  
  3216. /dev/EDM2/BookReview is a monthly column which focuses on development oriented 
  3217. books and materials.  The column is from a beginning PM programmer's eyes, 
  3218. because that's what I am.  Try to pick up whichever book strikes your fancy, 
  3219. and join the growing group of people following our introductory PM programming 
  3220. columns.  I will review books aimed at beginners for a while, and then move on 
  3221. from there. 
  3222.  
  3223. Please send me your comments and thoughts so that I can make this column as 
  3224. effective as possible.  After all, this is our magazine, and it will be most 
  3225. effective with reader feedback. 
  3226.  
  3227. This book is the last of my current collection, and even though it was written 
  3228. for OS/2 1.3, and thus only covers the 16-bit functions, it still manages to 
  3229. give decent coverage to concepts which are 16/32 bit insensitive. 
  3230.  
  3231. /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6 
  3232.  
  3233.  
  3234. ΓòÉΓòÉΓòÉ 3.1.2. Errata ΓòÉΓòÉΓòÉ
  3235.  
  3236. Errata 
  3237.  
  3238. There are three things on my agenda this month. 
  3239.  
  3240. First of all, I got mail from a couple of people who disagreed with my rosy 
  3241. evaluation of Writing OS/2 2.1 Device Drivers in C, 2nd Edition, Mastrianni.  I 
  3242. guess I should have made a couple of things a little clearer. If you are to use 
  3243. the book, you need Mastrianni's library, unless you write your own DevHlp 
  3244. functions, and the library costs around $150 US. Secondly, the reason I feel 
  3245. strongly about his book is that Mastrianni has done a lot of work abstracting 
  3246. device driver writing away from naked assembler, giving the opportunity to many 
  3247. more people to write device drivers than otherwise would have attempted it. 
  3248. This is the main accomplishment, I think.  In any case, you must judge for 
  3249. yourself whether it is worth it.  If you do decide to write a device driver, 
  3250. you'll most likely need the device driver kit from IBM, but from what I have 
  3251. heard, it is in dire need of cleaning up.  It is supposedly messy, expensive, 
  3252. and incomplete.  IBM would really do us all a huge favour by putting out a 
  3253. better kit, and in fact, they may be headed in that direction.  Supposedly 
  3254. Mastrianni has been hired by IBM, and I presume he'll be working on their kit 
  3255. development team.  If anyone has any factual information on this development, 
  3256. I'd love to hear it.  One can always hope.  In any case, the book will help you 
  3257. get off to a faster, surer start than if you were to try it on your own. 
  3258.  
  3259. Secondly, I have had a report of an inaccuracy in Real World Programming for 
  3260. OS/2 2.1, Blain, Delimon, and English.  Here is the deal, courtesy of Gordon 
  3261. Zeglinski:  on page 440, the following occurs: 
  3262.  
  3263. !DosSubSet(pHeap,DOSSUB_SPARSE_OBJ|DOSSUB_SERIALIZE))
  3264. If we look in the header file however, we find 
  3265.  
  3266. #define DosSubSet       DosSubSetMem
  3267. #define DOSSUBSET       DosSubSetMem
  3268. APIRET APIENTRY  DosSubSetMem(PVOID pbBase,
  3269.                               ULONG flag,
  3270.                               ULONG cb);
  3271.  
  3272. So the code fragment does not even have the correct number of arguments. It 
  3273. will not compile without a warning in C, and will not compile at all under C++. 
  3274. Look at Gordon's C++ Queue Object column for the proper way to use this API. 
  3275.  
  3276. Finally, from what I have heard, the new Watcom C/C++ 10.0 is imminent, and 
  3277. from reviews of the beta, it is something.  It will have an IDE, and an 
  3278. assembler (yes!), on top of the usual stuff, and of course will include the new 
  3279. 2.1 toolkit.  If you are about to buy a C/C++ compiler, wait until this comes 
  3280. out before you decide which one to spend your hard-earned money on. It looks 
  3281. like IBM may finally get a run for their money in the high-end 
  3282. compiler-department. 
  3283.  
  3284. As a foot-note, I am working (with a little help from my friends here at EDM/2) 
  3285. on a tabular content format for what each book covers, and what it does not 
  3286. cover.  Exiting stuff, and this may be just what you have been waiting for to 
  3287. be able to decide which book has what you need.  Thanks to Gordon (again) for 
  3288. the great idea. 
  3289.  
  3290. /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6 
  3291.  
  3292.  
  3293. ΓòÉΓòÉΓòÉ 3.1.3. OS/2 Presentation Manager GPI ΓòÉΓòÉΓòÉ
  3294.  
  3295. OS/2 Presentation Manager GPI 
  3296.  
  3297. Sample code fans will like the layout of this book.  In some ways, it is quite 
  3298. similar to Real World Programming for OS/2 2.1.  Each chapter starts out with a 
  3299. small motivating section, followed by detail on how to actually apply the 
  3300. concepts being presented.  The sample code follows at the end of the chapter, 
  3301. and consists of complete snippets of code, with some meaningful function, 
  3302. although whole programs are not included.  This is in keeping with the author's 
  3303. stated objective of assisting the intermediate to advanced PM programmer in 
  3304. becoming a proficient GPI programmer.  With its 318 pages, the book is fairly 
  3305. substantial, considering that it only covers one major topic. 
  3306.  
  3307. Here are the chapter headings: 
  3308.  
  3309.  1. Introduction: Simple Text and Graphics Output 
  3310.  2. Presentation Spaces and Device Contexts 
  3311.  3. Drawing Primitives and Attributes 
  3312.  4. Fonts 
  3313.  5. Bitmaps 
  3314.  6. Color Tables 
  3315.  7. Coordinate Spaces and Transformation 
  3316.  8. Clipping and Regions 
  3317.  9. Orders, Elements, and Segments 
  3318. 10. Correlation and Boundary Data Accumulation 
  3319. 11. MetaFiles 
  3320. 12. Printing 
  3321. 13. The OS/2 2.0 32-Bit Operating System 
  3322. 14. Appendix 1: DevOpenDC Parameters 
  3323. 15. Appendix 2: PMPRINT Queue Processor Parameters 
  3324. 16. Appendix 3: Introduction to Transforms and Matrices 
  3325. 17. Appendix 4: Sample MetaFile Internals 
  3326. 18. Appendix 5: Sample Orders 
  3327. 19. Appendix 6: GPI Functions Supported only by a Normal-PS 
  3328.  
  3329. Before using this book, you should already know how to set up a skeleton 
  3330. program, with message queue, window procedure, and all the rest of the 
  3331. trimmings.  This book ONLY talks about the GPI and a few Dev functions. 
  3332.  
  3333. The first chapter introduces the methodology and intent of the GPI APIs. Brief 
  3334. explanations of device contexts, presentation spaces, and so on are presented. 
  3335. Personally, I would have liked a section explaining the design choices made in 
  3336. the GPI APIs, but that doesn't hurt the coverage of the book. One thing I did 
  3337. miss, though, was a little humour.  Like so many programming books, humour is 
  3338. conspicuous by its absense.  I am not calling for a Monty Python-esque 
  3339. treatment of the material, just a little light-hearted jesting. This would make 
  3340. it more enjoyable, and less dry.  Oh well, it's not the first time I have 
  3341. missed that, and it won't be the last. 
  3342.  
  3343. The general feeling of the subsequent chapters is one of a programmer who knows 
  3344. his field very well, but has a lot to cover.  Each sentence has terse 
  3345. information to present, and it never lets up.  This is not a book you sit down 
  3346. and read in a couple of days!  Every sentence has to be thought through after 
  3347. reading it!  You probably have to try the code from each chapter in your own 
  3348. applications before really understanding what's going on. 
  3349.  
  3350. Chapter two lays the ground-work for all GPI programming.  Device contexts and 
  3351. presentation spaces are explained again in much greater detail than the first 
  3352. time.  There are limitations to each choice of PS, and the correct type of DC 
  3353. must be used.  This seems logical at first sight, but can be complicated when 
  3354. your requirements are not clearly delineated.  Unfortunately, the diagrams used 
  3355. in the book look like something the original word-processors might have 
  3356. produced, not very professional.  Not good for a book on presentation graphics 
  3357. and printing. 
  3358.  
  3359. The various drawing primitives and attribute groups, characters and text, lines 
  3360. and curves, filled areas or patterns, markers, and image and bitblt pixel 
  3361. operations are introduced in depth, and their relationship to each other are 
  3362. explained.  Non-bundle attributes are explained next.  Many functions and their 
  3363. related possibilities are explained. 
  3364.  
  3365. Each of chapters four to eleven introduces its own area, and finally in chapter 
  3366. twelve, the particular problems of printing are demonstrated.  I did feel that 
  3367. chapter five on bitmaps was short, given the disproportionate amount of 
  3368. interest this particular topic usually has. 
  3369.  
  3370. There are a lot of gotcha's in GPI programming, and a lot of little rules you 
  3371. have to be aware of.  Most people will not really use that much of the GPI, 
  3372. except to output a text-string here and there, and for these people, this book 
  3373. is overkill.  It is not intended as a reference book, there are other books for 
  3374. that purpose.  This book is intended, in the author's own words "...to provide 
  3375. answers (illustrated by programming examples) to any questions that Application 
  3376. Developers may have concerning the GPI and Dev functions. Rather than providing 
  3377. a tutorial description, I have concentrated on making the description of each 
  3378. topic as comprehensive as possible."  The end result is a book which is similar 
  3379. to a reference in coverage, but more like a tutorial in presentation. 
  3380.  
  3381. My final impression is a good one, even if the book is a little dry.  It 
  3382. concentrates on presenting OS/2's way of programming with graphics, not on 
  3383. teaching the un-initiated about graphics programming.  The one major 
  3384. short-coming is that it was written for 16-bit OS/2 1.3.  I find it strange 
  3385. that the book has not been re-written for OS/2 2.x, but perhaps the sales of 
  3386. this book were disappointing because of the slowness with which 1.3 caught on. 
  3387. Now is a different story, though.  With over 5 million copies of OS/2 sold at 
  3388. last count, we need an updated version of this book.  My final evaluation of 
  3389. this book reflects this. 
  3390.  
  3391. /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6 
  3392.  
  3393.  
  3394. ΓòÉΓòÉΓòÉ 3.1.4. Summary and Ratings ΓòÉΓòÉΓòÉ
  3395.  
  3396. Summary and Ratings 
  3397.  
  3398. This book ought to be updated.  There aren't many books on the market 
  3399. specifically about the GPI, and with the current boom going on with OS/2 2.1, 
  3400. 2.11, warp/personal OS/2, and so on, it would be perfect timing to have a new 
  3401. edition now.  The book is terse, well-written and accurate, but needs 
  3402. descriptions of the 32-bit functions, the new functions, and how to interface 
  3403. the two with 16-bit functions. 
  3404.  
  3405. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3406. ΓöéBOOK                                ΓöéAUDIENCE    ΓöéMARKΓöéCOMMENTS                                         Γöé
  3407. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3408. ΓöéReal World Programming for OS/2 2.1,ΓöéIntermediateΓöéB+  ΓöéLots of good code examples, but sometimes it is  Γöé
  3409. ΓöéBlain, Delimon, and English, SAMS   Γöéto Advanced Γöé    Γöétoo complex for novices. Accurate.  Well         Γöé
  3410. ΓöéPublishing. ISBN 0-672-30300-0.     ΓöéPM C        Γöé    Γöéorganized.  The index needs a little beefing up. Γöé
  3411. ΓöéUS$40, CAN$50.                      Γöéprogrammers Γöé    ΓöéGood, but not entirely complete how-to reference.Γöé
  3412. Γöé                                    Γöé            Γöé    ΓöéGood purchase.                                   Γöé
  3413. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3414. ΓöéLearning to Program OS/2 2.0        ΓöéBeginning PMΓöéB-  ΓöéThis book can be both frustrating and very       Γöé
  3415. ΓöéPresentation Manager by Example,    ΓöéC           Γöé    Γöérewarding.  It is not very large, and a bit      Γöé
  3416. ΓöéKnight, Van Nostrand Reinhold. ISBN ΓöéProgrammers Γöé    Γöépricey, but has some excellent chapters on       Γöé
  3417. Γöé0-442-01292-6. US$40, CAN$50.       Γöé            Γöé    Γöébeginning topics, such as messages, resources,   Γöé
  3418. Γöé                                    Γöé            Γöé    ΓöéIPF, and dialog boxes.  Strictly for beginners.  Γöé
  3419. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3420. ΓöéWriting OS/2 2.1 Device Drivers in  ΓöéAdvanced C  ΓöéA-  ΓöéThe only thing a device driver programmer would  Γöé
  3421. ΓöéC, 2nd Edition, Mastrianni, Van     ΓöéProgrammers,Γöé    Γöénot find in here is how to write SCSI, ADD, and  Γöé
  3422. ΓöéNostrand Reinhold. ISBN             Γöéfamiliar    Γöé    ΓöéIFS drivers.  Most everything else is in here,   Γöé
  3423. Γöé0-442-01729-4. US$35, CAN$45.       Γöéwith        Γöé    Γöéalong with skeleton examples.  An optional DevHlpΓöé
  3424. Γöé                                    Γöéhardware    Γöé    Γöélibrary of C-callable functions can be purchased Γöé
  3425. Γöé                                    Γöéprogramming Γöé    Γöéby those who don't have time to write their own. Γöé
  3426. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3427. ΓöéOS/2 Presentation Manager GPI, Winn,ΓöéIntermediateΓöéC+  ΓöéThis book needs updating for OS/2 2.x.  It is a  Γöé
  3428. ΓöéVan Nostrand Reinhold. ISBN         Γöéto advanced Γöé    Γöéwell-written in-depth coverage of the OS/2 way ofΓöé
  3429. Γöé0-442-00739-6. US$35, CAN$45.       ΓöéPM C        Γöé    Γöéprogramming for graphics.  It is not an          Γöé
  3430. Γöé                                    Γöéprogrammers Γöé    Γöéintroductory PM or graphics programming book.    Γöé
  3431. Γöé                                    Γöé            Γöé    ΓöéYou should know how to create windows etc.       Γöé
  3432. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3433.  
  3434. This table contains all books I have reviewed, so that you can find what you 
  3435. are looking for at a glance.  I will be careful to rate books fairly relative 
  3436. to each other.  If I feel a need to adjust ratings, I will adjust all of them 
  3437. at the same time, and write a note explaining why I felt this necessary. 
  3438. Please note that books aimed at different audiences should only be compared 
  3439. with great care, if at all.  I intend to concentrate on the strong points of 
  3440. the books I review, but I will point out any weaknesses in a constructive 
  3441. manner.  Read the reviews carefully. 
  3442.  
  3443. BOOK:  The name of the book, author(s), publishing company, ISBN, and 
  3444. approximate price. 
  3445.  
  3446. AUDIENCE:  This is a description of the audience I think the book targets best. 
  3447. This is not intended as gospel, just a guideline for people not familiar with 
  3448. the book. 
  3449.  
  3450. MARK:  My opinion of the success of the book's presentation, and how well it 
  3451. targets its audience.  Technical content, accuracy, organization, readability, 
  3452. and quality of index all weigh heavily here, but the single most important item 
  3453. is how well the book covers what it says it covers.  I don't expect to see any 
  3454. book score less than C, but the scale is there if necessary. 
  3455.  
  3456. ΓöîΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3457. ΓöéA+ ΓöéGround-breaking, all-around outstanding book                                 Γöé
  3458. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3459. ΓöéA  ΓöéExcellent book. This is what I want to see happen a lot                      Γöé
  3460. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3461. ΓöéA- ΓöéExcellent book with minor flaws                                              Γöé
  3462. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3463. ΓöéB+ ΓöéVery good book with minor flaws or omissions                                 Γöé
  3464. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3465. ΓöéB  ΓöéGood book with some flaws and omissions                                      Γöé
  3466. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3467. ΓöéB- ΓöéGood book, but in need of improvement                                        Γöé
  3468. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3469. ΓöéC+ ΓöéMediocre book with some potential, but in need of some updating              Γöé
  3470. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3471. ΓöéC  ΓöéMediocre book with some good sections, but badly in need of fixing           Γöé
  3472. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3473. ΓöéC- ΓöéMediocre book, little good material, desperately in need of an overhaul      Γöé
  3474. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3475. ΓöéD  ΓöéDon't buy this book unless you need it, and nothing else exists              Γöé
  3476. Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3477. ΓöéF  ΓöéDon't buy this book. Period                                                  Γöé
  3478. ΓööΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3479.  
  3480. COMMENTS: This is a summary of the review proper, although in a very brief 
  3481. format. 
  3482.  
  3483. /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6 
  3484.  
  3485.  
  3486. ΓòÉΓòÉΓòÉ 3.1.5. Coming Up ΓòÉΓòÉΓòÉ
  3487.  
  3488. Coming Up 
  3489.  
  3490. Next month I will be looking at The Art of OS/2 C Programming, Panov, Salomon 
  3491. and Panov, if it gets here in time (sounds very familiar :).  Otherwise I will 
  3492. review some REXX book.  The books I intend to review are (not necessarily in 
  3493. this order): 
  3494.  
  3495. o The Art of OS/2 C Programming, Panov, Salomon and Panov 
  3496. o OS/2 Presentation Manager Programming, Petzold - 1994 - not yet published :( 
  3497. o The Design of OS/2, 2nd Edititon, Kogan and Deitel - 1994 - not published 
  3498.   yet?  I will review the old version if someone sends me one, but if I have to 
  3499.   buy it I will wait for the new edition. 
  3500.  
  3501. This list is not set in stone, but they are books I am interested in.  I am 
  3502. considering reviewing the IBM OS/2 Redbooks, since they are readily and cheaply 
  3503. available, and look like good introductory reference.  I am also considering 
  3504. reviewing OS/2 Unleashed, but it is not strictly speaking a development book, 
  3505. so I'm going to wait until the list of real development books has diminished a 
  3506. bit.  By the way, does anyone know why the special edition of OS/2 Unleashed 
  3507. has completely different authors?  And what is different about the Special 
  3508. Edition?  Finally, I am considering reviewing Designing OS/2 Applications, 
  3509. Reich, mostly because it promises to present a different angle on OS/2 
  3510. programming, namely that of how to design  OS/2 applications, rather than how 
  3511. to program OS/2 applications. 
  3512.  
  3513. If anyone has a book they want to see reviewed, I will be happy to oblige as 
  3514. long as I can afford it.  Of course, requests can be satisfied quicker when 
  3515. accompanied by a book.  :)  Publishers can send me books at the address on my 
  3516. personal page at the end of the magazine, and I will review all OS/2 
  3517. development-related books I receive. 
  3518.  
  3519. /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6 
  3520.  
  3521.  
  3522. ΓòÉΓòÉΓòÉ 3.2. C++ Corner ΓòÉΓòÉΓòÉ
  3523.  
  3524.  
  3525. ΓòÉΓòÉΓòÉ 3.2.1. Introduction ΓòÉΓòÉΓòÉ
  3526.  
  3527. C++ Corner 
  3528.  
  3529. Written by Gordon Zeglinski 
  3530.  
  3531. Introduction 
  3532.  
  3533. This issue's C++ column is in response to a reader's email.  Things are 
  3534. extremely hectic, so sometimes email doesn't get answered as promptly as I 
  3535. would like it to be.  Keep the mail coming, but please be patient; I'll answer 
  3536. it as soon as I can. 
  3537.  
  3538. In this issue, we will look at multi-threading using the IThread class.  The 
  3539. IThread class is part of the ICLUI shipped with C-Set++ 2.0 and 2.1; however, 
  3540. we will be building upon the drag and drop example of last issue, which 
  3541. requires C-Set++ 2.1. 
  3542.  
  3543. C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6 
  3544.  
  3545.  
  3546. ΓòÉΓòÉΓòÉ 3.2.2. The IThread Class ΓòÉΓòÉΓòÉ
  3547.  
  3548. The IThread Class 
  3549.  
  3550. The IThread class is used to manipulate threads in the ICLUI. An instance of 
  3551. IThread and the thread it represents are not bound together.  If the thread 
  3552. terminates, the instance is not destroyed.  If the instance is destroyed, the 
  3553. thread continues executing. 
  3554.  
  3555. Starting a Thread with IThread 
  3556.  
  3557. There are two methods that can be used to start a thread.  The first, is to use 
  3558. the one of the constructors that take a function address or a reference to an 
  3559. instance of IThreadFn as an argument.  The second is to use the "start member" 
  3560. function.  We will look at both methods here. 
  3561.  
  3562. The following code snippet illustrates both methods of starting a thread. In 
  3563. this example, we use a member function of the class foo as the threads starting 
  3564. function. 
  3565.  
  3566. class foo{
  3567.  
  3568. public:
  3569.    foo();
  3570.  
  3571.    void fooThread();
  3572.  
  3573. };
  3574.  
  3575. void main(){
  3576.    //Create an instance of the foo class
  3577.    foo fooInst;
  3578.  
  3579.    // create the member thread dispatch object
  3580.    IThreadMemberFn<foo> ThreadFnc(fooInst,&foo::fooThread);
  3581.  
  3582.    // create a reference to the member thread dispatch object
  3583.    IReference<IThreadFn> ThreadFncRef(&ThreadFnc);
  3584.  
  3585.    // create a thread object and start the thread
  3586.    IThread ImmediateDispatch(ThreadFncRef);
  3587.  
  3588.    // create a thread object
  3589.    IThread DelayedDispatch;
  3590.  
  3591.    /*
  3592.    Do some work here
  3593.    */
  3594.  
  3595.    DelayedDispatch.start(ThreadFncRef);
  3596. }
  3597.  
  3598. The class IThreadMemberFn<class T> holds both an instance of a class and a 
  3599. pointer to a member function of that class.  These two pieces of information 
  3600. are need to start the thread using the correct member function and instance. 
  3601. Note, that since IThreadMemberFn is a template class, it can be used with any 
  3602. class. 
  3603.  
  3604. In this example, we only looked at starting threads on member functions. The 
  3605. method of starting threads on non-member functions is almost identical to the 
  3606. one outlined above.  Thus, it is left up to the reader to explore this further. 
  3607.  
  3608. C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6 
  3609.  
  3610.  
  3611. ΓòÉΓòÉΓòÉ 3.2.3. Building a Simple Test Application ΓòÉΓòÉΓòÉ
  3612.  
  3613. Building a Simple Test Application 
  3614.  
  3615. This section should look familiar to those who have read the last issue. We 
  3616. will take our application from last issue, and move the file loading routine 
  3617. into a separate thread.  In this section, we will look at only the 
  3618. modifications made to last issues code that are needed to accomplish our goal 
  3619. here. 
  3620.  
  3621. The class definition for MyFrame has been expanded to allow multi-threaded 
  3622. loading of files into the MLE. 
  3623.  
  3624. class MyFrame:public IFrameWindow{
  3625.  
  3626. public:
  3627.    MyFrame(const char *Title);
  3628.    void StartLoadThread();         //Added to start thread
  3629.  
  3630.    void SetFileName(IString &S){FileName=S;}  //Added to set the filename
  3631.  
  3632. protected:
  3633.    void LoadFile();        //Added: load thread start point
  3634.  
  3635.  
  3636.    // New members to support multi-threaded loading
  3637.    IReference<IThreadFn>    ThreadFncRef;
  3638.    IThreadMemberFn<MyFrame> *ExecuteThreadFnc;
  3639.    IThread                  ExecuteThread;
  3640.  
  3641.    IString FileName;
  3642.  
  3643.    IMultiLineEdit EditWin;
  3644.    AFileProvider FileProvider;
  3645. };
  3646.  
  3647. Added to the version of MyFrame shown above, are several several new member 
  3648. functions that handle the multi-threaded file loading.  The constructor is 
  3649. modified as follows to initialize the new data members. 
  3650.  
  3651. MyFrame::MyFrame(const char *Title):
  3652.    IFrameWindow(Title,IResourceId(1),  //-------------------
  3653.       IFrameWindow::titleBar|          //
  3654.       IFrameWindow::sizingBorder|      //
  3655.       IFrameWindow::minimizeButton|    // Create the Frame
  3656.       IFrameWindow::systemMenu|        //  Window
  3657.       IFrameWindow::shellPosition|     //
  3658.       IFrameWindow::minimizeButton|    //
  3659.       IFrameWindow::windowList|        //
  3660.       IFrameWindow::maximizeButton),   //--------------------
  3661.    EditWin(10,this,this){              // Create the Edit Window
  3662.                                        // ID=10, use this frame
  3663.                                        // window as the parent and
  3664.                                        //owner
  3665.                                        //---------------------
  3666.  
  3667.    setIcon(IResourceId(1));
  3668.    setClient(&EditWin);
  3669.  
  3670.    //enable default drag and drop handler
  3671.    IDMHandler::enableDragDropFor(&EditWin);
  3672.    //attach the provider
  3673.    EditWin.setItemProvider(&FileProvider);
  3674.  
  3675.    //Create the thread support members.
  3676.    ExecuteThreadFnc=new IThreadMemberFn<MyFrame>(*this,
  3677.                   &MyFrame::LoadFile);
  3678.  
  3679.    ThreadFncRef=IReference<IThreadFn>(ExecuteThreadFnc);
  3680.  
  3681.    show();
  3682. }
  3683.  
  3684. The targetDrop routine is modified so that it uses the member functions we 
  3685. added to MyFrame to set the file name and start the thread which will read in 
  3686. the file.  In the following code, we use the fact that the parent of the MLE is 
  3687. an instance of MyFrame to get the instance of the MyFrame window and call the 
  3688. thread creation function. 
  3689.  
  3690. Boolean AFileItem::targetDrop( IDMTargetDropEvent &Event){
  3691.    IMultiLineEdit *DropWin=(IMultiLineEdit *)this->targetOperation()->targetWindow();
  3692.  
  3693.    IString
  3694.     fname = this->containerName() + this->sourceName();
  3695.  
  3696.    MyFrame *FrameWin=(MyFrame*) DropWin->parent();
  3697.  
  3698.    FrameWin->SetFileName(fname);
  3699.    FrameWin->StartLoadThread();
  3700.  
  3701.    return true;
  3702. }
  3703.  
  3704. Now that we've seen how the old code was modified, we look at the two new 
  3705. member functions of MyFrame. These functions don't do anything that we haven't 
  3706. already seen. 
  3707.  
  3708. void MyFrame::StartLoadThread(){
  3709.    ExecuteThread.start(ThreadFncRef);
  3710. }
  3711.  
  3712. void MyFrame::LoadFile(){
  3713.    //erase the edit window
  3714.    EditWin.removeAll();
  3715.  
  3716.    //load the file into the edit window
  3717.    EditWin.importFromFile(FileName);
  3718. }
  3719.  
  3720. The source code to this issue is packaged the same way as the source code in 
  3721. the previous issue. 
  3722.  
  3723. C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6 
  3724.  
  3725.  
  3726. ΓòÉΓòÉΓòÉ 3.2.4. Summary ΓòÉΓòÉΓòÉ
  3727.  
  3728. Summary 
  3729.  
  3730. In this issue, we have seen how to use IThread and its supporting classes to 
  3731. create a multi-threaded PM application by building upon our drag and drop 
  3732. example from last issue. 
  3733.  
  3734. C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6 
  3735.  
  3736.  
  3737. ΓòÉΓòÉΓòÉ 3.3. Introduction to PM Programming ΓòÉΓòÉΓòÉ
  3738.  
  3739.  
  3740. ΓòÉΓòÉΓòÉ 3.3.1. Introduction ΓòÉΓòÉΓòÉ
  3741.  
  3742. Introduction to PM Programming 
  3743.  
  3744. Written by Larry Salomon, Jr. 
  3745.  
  3746. Introduction 
  3747.  
  3748. The purpose of this column is to provide the readers out there who are not 
  3749. familiar with PM application development the information necessary to satisfy 
  3750. their curiousity, educate themselves, and give them an advantage over the 
  3751. documentation supplied by IBM.  Of course, much of this stuff could probably be 
  3752. found in one of the many books out there, but the problem with books in general 
  3753. is that they don't answer the questions you have after you read the book the 
  3754. first time through. 
  3755.  
  3756. I will gladly entertain feedback from the readers about what was "glossed over" 
  3757. or what was detailed well, what tangential topics need to be covered and what 
  3758. superfluous crap should have been removed.  This feedback is essential in 
  3759. guaranteeing that you get what you pay for.  :) 
  3760.  
  3761. It should be said that you must not depend solely on this column to teach you 
  3762. how to develop PM applications; instead, this should be viewed as a supplement 
  3763. to your other information storehouses (books, the network conferences, etc.). 
  3764. Because this column must take a general approach, there will be some topics 
  3765. that you would like to see discussed that really do not belong here.  Specific 
  3766. questions can be directed to the Scratch Patch, where an attempt to answer them 
  3767. will be made. 
  3768.  
  3769. Last Month 
  3770.  
  3771. Last month, we explored more of the PM APIs and began looking into the 
  3772. WC_ENTRYFIELD window class.  This month, we will continue where we left off, 
  3773. and will continue in directions unknown; unknown, that is, unless you continue 
  3774. reading. 
  3775.  
  3776. Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6 
  3777.  
  3778.  
  3779. ΓòÉΓòÉΓòÉ 3.3.2. More Messages ΓòÉΓòÉΓòÉ
  3780.  
  3781. More Messages 
  3782.  
  3783. Let us first begin by looking at the remaining entryfield messages. 
  3784.  
  3785. EM_CLEAR 
  3786.  
  3787. This message is sent to delete the selected text in the entryfield. 
  3788.  
  3789. Parameters 
  3790.  
  3791.    param1 
  3792.  
  3793.       ulReserved (ULONG) 
  3794.  
  3795.          Reserved, 0. 
  3796.  
  3797.    param2 
  3798.  
  3799.       ulReserved (ULONG) 
  3800.  
  3801.          Reserved, 0. 
  3802.  
  3803. Returns 
  3804.  
  3805.    reply 
  3806.  
  3807.       bSuccess (BOOL) 
  3808.  
  3809.          TRUE      successful completion 
  3810.          FALSE     an error occurred. 
  3811.  
  3812. EM_COPY 
  3813.  
  3814. This message is sent to copy the selected text to the clipboard. 
  3815.  
  3816. Parameters 
  3817.  
  3818.    param1 
  3819.  
  3820.       ulReserved (ULONG) 
  3821.  
  3822.          Reserved, 0. 
  3823.  
  3824.    param2 
  3825.  
  3826.       ulReserved (ULONG) 
  3827.  
  3828.          Reserved, 0. 
  3829.  
  3830. Returns 
  3831.  
  3832.    reply 
  3833.  
  3834.       bSuccess (BOOL) 
  3835.  
  3836.          TRUE      successful completion 
  3837.          FALSE     an error occurred. 
  3838.  
  3839. EM_CUT 
  3840.  
  3841. This message is sent to copy the selected text to the clipboard and then delete 
  3842. it.  This is equivalent to sending an EM_COPY message followed by an EM_CLEAR 
  3843. message. 
  3844.  
  3845. Parameters 
  3846.  
  3847.    param1 
  3848.  
  3849.       ulReserved (ULONG) 
  3850.  
  3851.          Reserved, 0. 
  3852.  
  3853.    param2 
  3854.  
  3855.       ulReserved (ULONG) 
  3856.  
  3857.          Reserved, 0. 
  3858.  
  3859. Returns 
  3860.  
  3861.    reply 
  3862.  
  3863.       bSuccess (BOOL) 
  3864.  
  3865.          TRUE      successful completion 
  3866.          FALSE     an error occurred. 
  3867.  
  3868. EM_PASTE 
  3869.  
  3870. This message is sent to paste text from the clipboard into the entryfield. If 
  3871. there is selected text, it is replaced with the pasted contents; otherwise, the 
  3872. text is inserted at the current cursor position. 
  3873.  
  3874. Parameters 
  3875.  
  3876.    param1 
  3877.  
  3878.       ulReserved (ULONG) 
  3879.  
  3880.          Reserved, 0. 
  3881.  
  3882.    param2 
  3883.  
  3884.       ulReserved (ULONG) 
  3885.  
  3886.          Reserved, 0. 
  3887.  
  3888. Returns 
  3889.  
  3890.    reply 
  3891.  
  3892.       bSuccess (BOOL) 
  3893.  
  3894.          TRUE      successful completion 
  3895.          FALSE     an error occurred. 
  3896.  
  3897. EM_SETFIRSTCHAR 
  3898.  
  3899. This message is sent to set the zero-based index of the first character visible 
  3900. in the entryfield. 
  3901.  
  3902. Parameters 
  3903.  
  3904.    param1 
  3905.  
  3906.       sFirstChar (SHORT) 
  3907.  
  3908.          0-based index of the first visible character 
  3909.  
  3910.    param2 
  3911.  
  3912.       ulReserved (ULONG) 
  3913.  
  3914.          Reserved, 0. 
  3915.  
  3916. Returns 
  3917.  
  3918.    reply 
  3919.  
  3920.       bSuccess (BOOL) 
  3921.  
  3922.          TRUE      successful completion 
  3923.          FALSE     an error occurred. 
  3924.  
  3925. EM_SETINSERTMODE 
  3926.  
  3927. This message is sent to set the insert mode of the entryfield. 
  3928.  
  3929. Parameters 
  3930.  
  3931.    param1 
  3932.  
  3933.       bInsert (BOOL) 
  3934.  
  3935.          TRUE      insert mode 
  3936.          FALSE     overwrite mode 
  3937.  
  3938.    param2 
  3939.  
  3940.       ulReserved (ULONG) 
  3941.  
  3942.          Reserved, 0. 
  3943.  
  3944. Returns 
  3945.  
  3946.    reply 
  3947.  
  3948.       bOldState (BOOL) 
  3949.  
  3950.          TRUE      the entryfield was previously in insert mode 
  3951.          FALSE     the entryfield was previously in overwrite mode 
  3952.  
  3953. EM_SETREADONLY 
  3954.  
  3955. This message is sent to set the read-only state of the entryfield. 
  3956.  
  3957. Parameters 
  3958.  
  3959.    param1 
  3960.  
  3961.       bReadOnly (BOOL) 
  3962.  
  3963.          TRUE      the entryfield should be read-only 
  3964.          FALSE     the entryfield should be editable 
  3965.  
  3966.    param2 
  3967.  
  3968.       ulReserved (ULONG) 
  3969.  
  3970.          Reserved, 0. 
  3971.  
  3972. Returns 
  3973.  
  3974.    reply 
  3975.  
  3976.       bOldState (BOOL) 
  3977.  
  3978.          TRUE      the entryfield was previously read-only 
  3979.          FALSE     the entryfield was previously editable 
  3980.  
  3981. EM_SETSEL 
  3982.  
  3983. This message is sent to set the current selection of the entryfield. 
  3984.  
  3985. Parameters 
  3986.  
  3987.    param1 
  3988.  
  3989.       sMinSel (SHORT) 
  3990.  
  3991.          The first 0-based point of selection 
  3992.  
  3993.       sMaxSel (SHORT) 
  3994.  
  3995.          The last 0-based point of selection 
  3996.  
  3997.    param2 
  3998.  
  3999.       ulReserved (ULONG) 
  4000.  
  4001.          Reserved, 0. 
  4002.  
  4003. Returns 
  4004.  
  4005.    reply 
  4006.  
  4007.       bSuccess (BOOL) 
  4008.  
  4009.          TRUE      successful completion 
  4010.          FALSE     an error occurred. 
  4011.  
  4012. EM_SETTEXTLIMIT 
  4013.  
  4014. This message is sent to set the maximum number of characters the entryfield can 
  4015. contain. 
  4016.  
  4017. Parameters 
  4018.  
  4019.    param1 
  4020.  
  4021.       usLimit (USHORT) 
  4022.  
  4023.          maximum number of characters allowed 
  4024.  
  4025.    param2 
  4026.  
  4027.       ulReserved (ULONG) 
  4028.  
  4029.          Reserved, 0. 
  4030.  
  4031. Returns 
  4032.  
  4033.    reply 
  4034.  
  4035.       bSuccess (BOOL) 
  4036.  
  4037.          TRUE      successful completion 
  4038.          FALSE     an error occurred. 
  4039.  
  4040. Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6 
  4041.  
  4042.  
  4043. ΓòÉΓòÉΓòÉ 3.3.3. Conceptually Speaking ΓòÉΓòÉΓòÉ
  4044.  
  4045. Conceptually Speaking 
  4046.  
  4047. Of Selections, Anchor Points, and Cursor Points 
  4048.  
  4049. What is a selection?  A selection is an area that is defined by the user.  Any 
  4050. "objects" (defined by the context of the selection) that are contained within 
  4051. the selected area are defined to be selected.  Any selection consists of two 
  4052. things:  an anchor point, which is defined to be the point where the selection 
  4053. was started and is fixed, and a cursor point, which is defined to the be place 
  4054. where the cursor/pointer currently is and moves with the cursor/pointer.  A 
  4055. selection is performed, according to CUA guidelines, using either the mouse or 
  4056. the keyboard.  Using the mouse requires the user to press one of the buttons 
  4057. (usually the first) and hold the button while moving the mouse.  When the 
  4058. selection has been made, the button is released.  Using the keyboard, the user 
  4059. presses the Shift key while moving the cursor with the arrow keys.  When the 
  4060. Shift key is released, the selection is completed. 
  4061.  
  4062. There are other semantics associated with selections when using the mouse, but 
  4063. we will not discuss them here.  The point of these definitions is to allow you 
  4064. to understand the purpose of the EM_SETSEL message.  Its two parameters are 
  4065. slightly different that what was discussed above; if the anchor point is always 
  4066. before the cursor point ("before" is used, since the entryfield can be 
  4067. considered as being a one-dimensional stream of characters), then sMinSel is 
  4068. the anchor point and sMaxSel is the cursor point, otherwise the two are 
  4069. reversed. 
  4070.  
  4071. Clipboard 
  4072.  
  4073. For those of you who have no GUI experience, the clipboard is a temporary 
  4074. storage place for placing items to be used later in the same or other 
  4075. applications.  Items of predefined, or application-defined formats, may be 
  4076. placed on the clipboard. 
  4077.  
  4078. Its capabilities and interfaces are beyond the scope of this discussion, but it 
  4079. is important that you know what it is. 
  4080.  
  4081. Text Limits 
  4082.  
  4083. When you create an entryfield, by default it allows up to 32 characters maximum 
  4084. to be entered.  If, however, you need more (or less) than this amount, you must 
  4085. first send it an EM_SETTEXTLIMIT message, which tells the entryfield to 
  4086. allocate more or less memory for its use. 
  4087.  
  4088. Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6 
  4089.  
  4090.  
  4091. ΓòÉΓòÉΓòÉ 3.3.4. Notifications ΓòÉΓòÉΓòÉ
  4092.  
  4093. Notifications 
  4094.  
  4095. The entryfield also sends notifications to its owner.  These notifications are 
  4096. listed below. 
  4097.  
  4098. o EN_CHANGE - this is sent whenever the entryfield's contents have changed. 
  4099.  
  4100. o EN_KILLFOCUS - this is sent whenever the entryfield is losing the input 
  4101.   focus. 
  4102.  
  4103. o EN_MEMERROR - this is sent whenever the entryfield cannot allocate memory in 
  4104.   response to an EM_SETTEXTLIMIT message. 
  4105.  
  4106. o EN_OVERFLOW - this is sent whenever an attempt to insert or paste more text 
  4107.   than is allowed by the text limit is made. 
  4108.  
  4109. o EN_SCROLL - this is sent whenever the entryfield has scrolled from a call to 
  4110.   WinScrollWindow(), the cursor moving beyond the visible area, or when the 
  4111.   text has changed. 
  4112.  
  4113. o EN_SETFOCUS - this is sent whenever the entryfield is gaining the input 
  4114.   focus. 
  4115.  
  4116. The notifications you will use the most often are the EN_CHANGE, EN_SETFOCUS, 
  4117. and EN_KILLFOCUS ones, although the others have their uses. 
  4118.  
  4119. Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6 
  4120.  
  4121.  
  4122. ΓòÉΓòÉΓòÉ 3.3.5. Summary ΓòÉΓòÉΓòÉ
  4123.  
  4124. Summary 
  4125.  
  4126. This month, we finished looking at the entryfield messages, the notifications 
  4127. sent by the entryfield, and the concepts associated with the new messages. 
  4128. Next month, we will begin looking at the WC_LISTBOX class, and will continue 
  4129. with nameDlgProc(). 
  4130.  
  4131. Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6 
  4132.  
  4133.  
  4134. ΓòÉΓòÉΓòÉ 3.4. Scratch Patch ΓòÉΓòÉΓòÉ
  4135.  
  4136.  
  4137. ΓòÉΓòÉΓòÉ 3.4.1. Introduction ΓòÉΓòÉΓòÉ
  4138.  
  4139. Scratch Patch 
  4140.  
  4141. Written by Larry Salomon, Jr. 
  4142.  
  4143. Introduction 
  4144.  
  4145. Welcome to this month's "Scratch Patch"!  Each month, I collect various items 
  4146. that fit into this column sent to me via email. The ones that I feel contribute 
  4147. the most to developers, whether in terms of information or as a nifty trick to 
  4148. tuck into your cap, get published in this column. 
  4149.  
  4150. To submit an item, send it via email to my address - os2man@panix.com - and be 
  4151. sure to grant permission to publish it (those that forget will not be 
  4152. considered for publication). 
  4153.  
  4154. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4155.  
  4156.  
  4157. ΓòÉΓòÉΓòÉ 3.4.2. Corrections ΓòÉΓòÉΓòÉ
  4158.  
  4159. Corrections 
  4160.  
  4161. If you remember, last month I stated that APAR number PJ13781 was created 
  4162. against the Palette Manager; well, it has been closed.  The reason is, if 
  4163. you'll look in the source code (ugpm.zip), you'll see that a call to WinGetPS() 
  4164. is made without 1) creating a message queue first and 2) without releasing it 
  4165. later.  This is causing the instabilities that were reported. 
  4166.  
  4167. My apologies for not figuring this out before, but I never looked at the 
  4168. source. 
  4169.  
  4170. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4171.  
  4172.  
  4173. ΓòÉΓòÉΓòÉ 3.4.3. Gotcha Notes! ΓòÉΓòÉΓòÉ
  4174.  
  4175. Gotcha Notes! 
  4176.  
  4177. When using the IBM User Interface Class Libraries, if you use the new operator 
  4178. to create an instance of your main window in the main() function, you must use 
  4179. the delete operator after the IApplication::current().run() call or else the 
  4180. application will not close after the main window has been destroyed. 
  4181.  
  4182. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4183.  
  4184.  
  4185. ΓòÉΓòÉΓòÉ 3.4.4. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
  4186.  
  4187. Snippet(s) of the Month 
  4188.  
  4189. "When it rains, it pours." 
  4190.  
  4191. Eberhard Mattes (mattes@azu.informatik.uni-stuttgart.de) submitted the 
  4192. following item: 
  4193.  
  4194. This is the template for a dialog box that contains a system icon.  Note that 
  4195. DLGEDIT doesn't know how to handle SS_SYSICON. 
  4196.  
  4197. DLGTEMPLATE 3141
  4198. BEGIN
  4199.   DIALOG "A System Icon", 3141, 20, 20, 200, 64, , FCF_TITLEBAR | FCF_SYSMENU
  4200.   BEGIN
  4201.     CONTROL SPTR_ICONQUESTION, 0, 90, 28, 0, 0, WC_STATIC, WS_VISIBLE | SS_SYSICON
  4202.     DEFPUSHBUTTON "OK", 1, 8, 8, 32, 16
  4203.   END
  4204. END
  4205.  
  4206. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  4207.  
  4208. Jeff Garzik (jgarzik@pantera.atl.ga.us) submitted the following item: 
  4209.  
  4210. /*
  4211.  * DosStartSession() sample code for a DOS session
  4212.  * by Jeff Garzik (jgarzik@pantera.atl.ga.us)
  4213.  *
  4214.  * It has been tested under BC++ 1.0 and emx+gcc 0.8h.
  4215.  */
  4216.  
  4217. #define INCL_DOS                /* we're lazy */
  4218. #include <os2.h>
  4219. #include <stdio.h>
  4220. #include <string.h>
  4221. #include <stdlib.h>
  4222. #include <conio.h>
  4223.  
  4224. int main (int argc, char *argv[])
  4225. {
  4226.   STARTDATA sd;                 /* DosStartSession parm structure */
  4227.   PID pid = 0, pid2 = 0;        /* unused but necessary */
  4228.   ULONG SessID;                 /* "" */
  4229.   RESULTCODES rcResults;        /* "" */
  4230.   APIRET rc;                    /* OS/2 API return code */
  4231.  
  4232.                                 /* the program we want to run */
  4233.   char s[128] =  "c:\\os2\\mdos\\qbasic.exe",
  4234.  
  4235.                                 /* the parms of the program to be exec'd */
  4236.        s1[128] = "/EDITOR c:\\autoexec.bat",
  4237.  
  4238.                                 /* MS-DOS settings of program */
  4239.        DosSettings[200] = "DOS_BACKGROUND_EXECUTION=0\0"
  4240.                           "DPMI_MEMORY_LIMIT=0\0"
  4241.                           "EMS_MEMORY_LIMIT=0\0"
  4242.                           "HW_TIMER=1\0"
  4243.                           "IDLE_SECONDS=10\0"
  4244.                           "IDLE_SENSITIVITY=20\0"
  4245.                           "XMS_MEMORY_LIMIT=0\0"
  4246.                           "\0";
  4247.  
  4248.   /* fill in data for DosStartSession() */
  4249.   memset((void *)&sd, 0, sizeof(sd));
  4250.   sd.Length = sizeof(STARTDATA);
  4251.   sd.Related = SSF_RELATED_CHILD;
  4252.   sd.FgBg = SSF_FGBG_FORE;
  4253.   sd.TraceOpt = SSF_TRACEOPT_NONE;
  4254.   sd.PgmTitle = "My First DOS Sub-Process"; /* not really necessary */
  4255.   sd.PgmName = s;
  4256.   sd.PgmInputs = s1;
  4257.   sd.TermQ = NULL;
  4258.  
  4259.   /*
  4260.    * The two following settings are somewhat different for
  4261.    * DOS sessions.  You CANNOT set the environment of a
  4262.    * DOS session.  The Environment field in STARTDATA is
  4263.    * instead used for the DOS settings.  InheritOpt is really
  4264.    * irrelevant because DOS sessions get their environment
  4265.    * from the settings in DOS_AUTOEXEC (defaults to C:\AUTOEXEC.BAT)
  4266.    * exclusively
  4267.    */
  4268.   sd.Environment = DosSettings; /* or 0 for no settings */
  4269.   sd.InheritOpt = SSF_INHERTOPT_SHELL;
  4270.  
  4271.   /* set to SFF_TYPE_WINDOWEDVDM for windowed session */
  4272.   sd.SessionType = SSF_TYPE_VDM;
  4273.   sd.IconFile = 0;
  4274.   sd.PgmHandle = 0;
  4275.   sd.PgmControl = 0;
  4276.   sd.InitXPos = 0;              /* unused for fullscreen session */
  4277.   sd.InitYPos = 0;              /* unused for fullscreen session */
  4278.   sd.InitXSize = 0;             /* unused for fullscreen session */
  4279.   sd.InitYSize = 0;             /* unused for fullscreen session */
  4280.   sd.Reserved = 0;
  4281.   sd.ObjectBuffer = NULL;
  4282.   sd.ObjectBuffLen = 0;
  4283.  
  4284.   if ((rc = DosStartSession(&sd, &SessID, &pid)) != 0)
  4285.     printf("\nDosStartSession error %ld\n\n", rc);
  4286.   else
  4287.     printf("Successfully executed DOS Editor on AUTOEXEC.BAT.\n");
  4288.   DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &rcResults, &pid2, pid);
  4289.  
  4290.   printf("\nPress any key to continue...");
  4291.   getch();
  4292.   putchar('\n');
  4293.  
  4294.   return 0;
  4295. }
  4296.  
  4297. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  4298.  
  4299. Someone sent me the following in a uuencoded format, and I forgot to save their 
  4300. name and email address!  Sounds familiar?  :) 
  4301.  
  4302. #define INCL_DOS
  4303. #define INCL_DOSDEVIOCTL
  4304. #define INCL_ERRORS
  4305. #include <os2.h>
  4306. #include <stdio.h>
  4307.  
  4308. /*+-------------------------------------------------------------------+
  4309.   |Function QueryCommPorts                                            |
  4310.   |                                                                   |
  4311.   |Purpose :                                                          |
  4312.   |   Determine nr. of commports available on the PC.                 |
  4313.   |   Try to figure out which port is used by the mouse.              |
  4314.   |Inputparameters :                                                  |
  4315.   |   *cCommPorts : pointer to a byte to place the number of available|
  4316.   |                 comm ports                                        |
  4317.   |   bVerbose    : bool that indicates whether or not a status report|
  4318.   |                 must be displayed                                 |
  4319.   |Outputparameters :                                                 |
  4320.   |   cMousePort : byte that contains the nr of the comm port used by |
  4321.   |                the mouse                                          |
  4322.   +-------------------------------------------------------------------+*/
  4323.  
  4324. BYTE QueryNrCommPorts( BYTE *cCommPorts, BOOL bVerbose )
  4325. {
  4326.    BYTE   cMousePort = -1;
  4327.    BOOL   bMouse     = FALSE;
  4328.  
  4329.    HFILE  hfMouse;
  4330.    ULONG  ulAction;
  4331.  
  4332.    APIRET rc;
  4333.  
  4334.    struct
  4335.    {
  4336.       USHORT DeviceID;
  4337.       USHORT CommPort;
  4338.       USHORT SecDeviceID;
  4339.    } DataWords;
  4340.    ULONG  ulDataLength = sizeof( DataWords );
  4341.  
  4342.    CHAR szDeviceID[6][30] = { "Unknown",
  4343.                               "Bus mouse",
  4344.                               "Serial Mouse",
  4345.                               "Inport mouse",
  4346.                               "PS/2*-style pointing device",
  4347.                               "IBM* 8516 Touch Display"
  4348.                             };
  4349.  
  4350.    /*+----------------------------------------------+
  4351.      | Determine the number of comm ports on the PC |
  4352.      +----------------------------------------------+*/
  4353.  
  4354.    DosDevConfig( cCommPorts, DEVINFO_RS232 );
  4355.  
  4356.    /*+---------------------------------------------+
  4357.      | Determine nr of comm port used by the mouse |
  4358.      +---------------------------------------------+*/
  4359.  
  4360.    if ( DosOpen( "MOUSE$",
  4361.                  &hfMouse,
  4362.                  &ulAction,
  4363.                  0,
  4364.                  FILE_SYSTEM,
  4365.                  OPEN_ACTION_OPEN_IF_EXISTS,
  4366.                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  4367.                  0 ) == NO_ERROR )
  4368.    {
  4369.       rc = DosDevIOCtl( hfMouse,
  4370.                         IOCTL_POINTINGDEVICE,
  4371.                         0x6B,               /* Query Pointing Device ID */
  4372.                         NULL,
  4373.                         0L,
  4374.                         NULL,
  4375.                         (PVOID) &DataWords,
  4376.                         ulDataLength,
  4377.                         &ulDataLength );
  4378.       if ( rc != NO_ERROR )
  4379.       {
  4380.          printf( "\nError while querying mouse info.\n" );
  4381.          goto end;
  4382.       }
  4383.       else
  4384.       {
  4385.          bMouse = TRUE;
  4386.          cMousePort = DataWords.CommPort;
  4387.       }
  4388.    }
  4389.  
  4390.    /*+-------------------+
  4391.      |Print status report|
  4392.      +-------------------+*/
  4393.  
  4394.    if ( bVerbose )
  4395.    {
  4396.       printf( "\nSTATUS REPORT COMM PORTS\n\n" );
  4397.       printf( "Comm ports available : %d\n", *cCommPorts );
  4398.       if ( bMouse )
  4399.       {
  4400.          printf( "Mouse detected.\n" );
  4401.          printf( "\tType : %s\n", szDeviceID[ DataWords.DeviceID ] );
  4402.          printf( "\tComm port : %d\n", DataWords.CommPort );
  4403.       }
  4404.    }
  4405.  
  4406. end:
  4407.    return ( cMousePort );
  4408. }
  4409.  
  4410. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  4411.  
  4412. Finally, I came up with the following function. 
  4413.  
  4414. typedef VOID (* _Optlink PFNDRVENUM)(CHAR,PVOID);
  4415.  
  4416. VOID enumDrives(PFNDRVENUM pfnEnumFn,PVOID pvData)
  4417. //--------------------------------------------------
  4418. // This function enumerates all of the drives at the
  4419. // time the function is called, and for each local
  4420. // drive calls the callback specified.
  4421. //
  4422. // Input:  pfnEnumFn - callback function
  4423. //         pvData - pointer to user-defined data to
  4424. //                  pass to callback
  4425. //
  4426. // Callback has the following form:
  4427. //
  4428. // BOOL _Optlink callBack(CHAR chDrive,PVOID pvData)
  4429. //
  4430. // Input:  chDrive - uppercase drive letter
  4431. //         pvData - as was passed to enumDrives()
  4432. //--------------------------------------------------
  4433. {
  4434.    BYTE abBuffer[1024];
  4435.    ULONG ulCurrent;
  4436.    ULONG ulDriveMap;
  4437.    CHAR chDrive;
  4438.    CHAR achDrive[3];
  4439.    PFSQBUFFER2 pfsqbBuffer;
  4440.    ULONG ulSzBuf;
  4441.    APIRET arReturn;
  4442.  
  4443.    //-----------------------------------------------
  4444.    // Disable errors so that we don't get any "device
  4445.    // is locked" popups.
  4446.    //-----------------------------------------------
  4447.    DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
  4448.  
  4449.    DosQueryCurrentDisk(&ulCurrent,&ulDriveMap);
  4450.  
  4451.    ulDriveMap>>=2;
  4452.    chDrive='C';
  4453.    memset(achDrive,0,sizeof(achDrive));
  4454.    achDrive[1]=':';
  4455.    pfsqbBuffer=(PFSQBUFFER2)abBuffer;
  4456.  
  4457.    while (chDrive<='Z') {
  4458.       if ((ulDriveMap % 2)==1) {
  4459.          achDrive[0]=chDrive;
  4460.  
  4461.          ulSzBuf=sizeof(abBuffer);
  4462.          memset(pfsqbBuffer,0,ulSzBuf);
  4463.  
  4464.          arReturn=DosQueryFSAttach(achDrive,
  4465.                                    0,
  4466.                                    FSAIL_QUERYNAME,
  4467.                                    pfsqbBuffer,
  4468.                                    &ulSzBuf);
  4469.          if (arReturn==0) {
  4470.             switch (pfsqbBuffer->iType) {
  4471.             case FSAT_LOCALDRV:
  4472.                (*pfnEnumFn)(chDrive,pvData);
  4473.                break;
  4474.             default:
  4475.                break;
  4476.             } /* endswitch */
  4477.          } /* endif */
  4478.       } /* endif */
  4479.  
  4480.       ulDriveMap>>=1;
  4481.       chDrive++;
  4482.    } /* endwhile */
  4483.  
  4484.    DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
  4485. }
  4486.  
  4487. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4488.  
  4489.  
  4490. ΓòÉΓòÉΓòÉ 3.4.5. Documentation Chop Shop ΓòÉΓòÉΓòÉ
  4491.  
  4492. Documentation Chop Shop 
  4493.  
  4494. In the File Systems section of the Control Program Guide and Reference, there 
  4495. are a couple of problems. 
  4496.  
  4497.  1. The API DosQueryFileInfo() is referenced when DosQueryFSInfo() is intended. 
  4498.  
  4499.  2. The sample to retrieve file system information via DosQueryFSAttach() is 
  4500.     incorrect.  Declaring a variable of type FSQBUFFER2 and passing it to 
  4501.     DosQueryFSAttach() will return ERROR_BUFFER_OVERFLOW.  You must pass a 
  4502.     pointer to a buffer (stack-based or dynamically allocated) that has 
  4503.     sufficient space. 
  4504.  
  4505. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 
  4506.  
  4507. _wpPopulate is listed in the online reference as having a third parameter of 
  4508. WPFolder * and its value is the "real name of the folder to populate".  In 
  4509. actuality, it is a PSZ which is the path of the folder to populate. 
  4510.  
  4511. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4512.  
  4513.  
  4514. ΓòÉΓòÉΓòÉ 3.4.6. Want Ads ΓòÉΓòÉΓòÉ
  4515.  
  4516. Want Ads 
  4517.  
  4518. Below are the hot topics as of this issue's writing.  Feel free to write on any 
  4519. of these. 
  4520.  
  4521. Workplace Shell Programming (hot) - this is still quite the "black magic" 
  4522. topic, about which we have seen only one article.  There are many out there who 
  4523. do WPS programming for a living, but they have not been sufficiently 
  4524. enlightened about our need. :) 
  4525.  
  4526. Client/Server (hot) - using either named pipes (with or without a network) or 
  4527. sockets, client/server programming is all the rage these days.  On a related 
  4528. note, some people have also expressed an interest in learning about interfacing 
  4529. with the various protocol drivers (e.g.  NDIS, IPX/SPX, etc.).  Any articles in 
  4530. this area are most welcome. 
  4531.  
  4532. Multimedia (warm) - we recently had two articles on this topic.  However, they 
  4533. both dealt with sound, which we all know is not the only alternative media 
  4534. type.  Articles on anything else - MIDI, video, etc. - are needed. 
  4535.  
  4536. Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6 
  4537.  
  4538.  
  4539. ΓòÉΓòÉΓòÉ 4. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
  4540.  
  4541. How Do I Get EDM/2? 
  4542.  
  4543. EDM/2 can be obtained in any of the following ways: 
  4544.  
  4545. On the Internet 
  4546.  
  4547. o All back issues are available via anonymous FTP from the following sites: 
  4548.  
  4549.    - ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory. 
  4550.    - ftp.luth.se in the /pub/os2/programming/newsletter directory. 
  4551.    - generalhq.pc.cc.cmu.edu 
  4552.  
  4553. o The EDM/2 mailing list.  Send an empty message to edm2-info@knex.mind.org to 
  4554.   receive a file containing (among other things) instructions for subscribing 
  4555.   to EDM/2.  This is a UUCP connection, so be patient please. 
  4556. o IBM's external gopher/WWW server in Almaden. The address is 
  4557.   index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of the 
  4558.   "OS/2 Information" menu; the URL is 
  4559.   "gopher://index.almaden.ibm.com/1nonibm/os2nonib.70". 
  4560.  
  4561. On Compuserve 
  4562.  
  4563. All back issues are available in the OS/2 Developers Forum 2. 
  4564.  
  4565. IBM Internal 
  4566.  
  4567. o IBM's internal gopher/WWW server in Almaden. The address is 
  4568.   n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; the 
  4569.   URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70". 
  4570. o IBM's REQUEST command on all internal VM systems.  Enter the VM command 
  4571.   REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable packages 
  4572.   will be sent to you; in this list are the names of the packages containing 
  4573.   the EDM/2 issues. 
  4574.  
  4575. How do I Get EDM/2? - EDM/2 - June 1994 - Volume 2, Issue 6 
  4576.  
  4577.  
  4578. ΓòÉΓòÉΓòÉ 5. Contributors to this Issue ΓòÉΓòÉΓòÉ
  4579.  
  4580. Are You a Potential Author? 
  4581.  
  4582. We are always looking for (new) authors.  If you have a topic about which you 
  4583. would like to write, send a brief description of the topic electronically to 
  4584. any of the editors, whose addresses are listed below, by the 15th of the month 
  4585. before the month in which your article will appear.  This alerts us that you 
  4586. will be sending an article so that we can plan the issue layout accordingly. 
  4587. After you have done this, get the latest copy of the Article Submission 
  4588. Guidelines  from ftp.cdrom.com  in the /pub/os2/2_x/program/newsltr directory. 
  4589. (the file is artsub.zip)  The completed text of your article should be sent to 
  4590. us no later than five days prior to the last day of the month; any articles 
  4591. received after that time may be pushed to the next issue. 
  4592.  
  4593. The editors can be reached at the following email addresses: 
  4594.  
  4595. o Larry Salomon - os2man@panix.com (Internet). 
  4596. o Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet). 
  4597.  
  4598. The following people contributed to this issue in one form or another (in 
  4599. alphabetical order): 
  4600.  
  4601. o Martin Lafaix 
  4602. o Larry Salomon, Jr. 
  4603. o Carsten Whimster 
  4604. o Gordon Zeglinski 
  4605. o Network distributors 
  4606.  
  4607. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6 
  4608.  
  4609.  
  4610. ΓòÉΓòÉΓòÉ 5.1. Martin Lafaix ΓòÉΓòÉΓòÉ
  4611.  
  4612. Martin Lafaix 
  4613.  
  4614. Martin Lafaix is a computer science student at the Universit╨Æ de Nice-Sophia 
  4615. Antipolis.  He currently works on his PhD thesis (key areas: functional 
  4616. language, type as value, programming in the large, ...). 
  4617.  
  4618. He can be reached at the following address: lafaix@sophia.inria.fr 
  4619.  
  4620. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6 
  4621.  
  4622.  
  4623. ΓòÉΓòÉΓòÉ 5.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
  4624.  
  4625. Larry Salomon, Jr. 
  4626.  
  4627. Larry Salomon, Jr. wrote his first Presentation Manager application for OS/2 
  4628. version 1.1 in 1989.  Since that time, he has written numerous VIO and PM 
  4629. applications, including the Scramble applet included with OS/2 and the 
  4630. I-Brow/Magnify/Screen Capture trio being distributed by IBM with the 
  4631. Professional Developers Kit CD-ROM.  Currently, he works for Cheyenne Software 
  4632. in Roslyn, New York and resides in Bellerose, New York with his wife Lisa. 
  4633.  
  4634. Larry can be reached electronically via the Internet at os2man@panix.com. 
  4635.  
  4636. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6 
  4637.  
  4638.  
  4639. ΓòÉΓòÉΓòÉ 5.3. Carsten Whimster ΓòÉΓòÉΓòÉ
  4640.  
  4641. Carsten Whimster 
  4642.  
  4643. I am an undergraduate Computer Science student at the University of Waterloo, 
  4644. and an OS/2 enthusiast as of OS/2 2.0.  I am currently in my third year, taking 
  4645. mainly operating system, language, and compiler courses as much as possible. 
  4646. This is not too difficult obviously, since this covers most of what they try to 
  4647. teach us in any case :).  This summer and fall I am working at the University 
  4648. as a tutor in CS241, an introductory course to compilers.  I am a TEAM-OS/2 
  4649. member, and try to keep up with several OS/2 groups on the Internet. 
  4650.  
  4651. I am a beginning OS/2 PM programmer with a few projects on the go, and many 
  4652. more in my head.  I use EMX/GCC 2.5.8, Watcom C/C++ 9.5, and Watcom VX-REXX 
  4653. 2.0, and I am anxiously awaiting Watcom C/C++ 10.0's impending release. 
  4654.  
  4655. You may reach me... 
  4656.  
  4657. ...via email: 
  4658.  
  4659. bcrwhims@undergrad.math.uwaterloo.ca - Internet 
  4660.  
  4661. gopher://descartes.math.uwaterloo.ca:70/h0/mathSOC/.csc/.www/.bcrwhimster/homepage.html 
  4662. - Mosaic homepage 
  4663.  
  4664. ...via snail mail: 
  4665.  
  4666. Carsten Whimster
  4667. 319 Erb Street West, 3rd floor
  4668. Waterloo, Ontario
  4669. Canada
  4670. N2L 1W4
  4671.  
  4672. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6 
  4673.  
  4674.  
  4675. ΓòÉΓòÉΓòÉ 5.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
  4676.  
  4677. Gordon Zeglinski 
  4678.  
  4679. Gordon Zeglinski is a freelance programmer/consultant who received his Master's 
  4680. degree in Mechanical Engineering with a thesis on C++ sparse matrix objects. 
  4681. He has been programming in C++ for 6 years and also has a strong background in 
  4682. FORTRAN.  He started developing OS/2 applications with version 2.0 . 
  4683.  
  4684. His current projects include a client/server communications program that 
  4685. utilitizes OS/2's features which has entered beta testing.  Additionally, he is 
  4686. involved in the development of a "real-time" automated vehicle based on OS/2 
  4687. and using C++ in which he does device driver development and designs the 
  4688. applications that comprise the control logic and user interface. 
  4689.  
  4690. He can be reached via the Internet at zeglins@cc.umanitoba.ca. 
  4691.  
  4692. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6 
  4693.  
  4694.  
  4695. ΓòÉΓòÉΓòÉ 5.5. Network distributors ΓòÉΓòÉΓòÉ
  4696.  
  4697. Network Distributors 
  4698.  
  4699. These people are part of our distribution system to provide EDM/2 on networks 
  4700. other than the Internet.  Their help to provide access to this magazine for 
  4701. others is voluntary and we appreciate them a lot! 
  4702.  
  4703. o Paul Hethmon (hethmon@apac.ag.utk.edu) - Compuserve 
  4704. o Gess Shankar (gess@knex.mind.org) - Internet 
  4705. o David Singer (singer@almaden.ibm.com) - IBM Internal 
  4706. o Andre Asselin (ASSELIN AT RALVM12) - IBM Internal 
  4707.  
  4708. If you would like to become a "network distributor", be sure to contact the 
  4709. editors so that we can give you the credit you deserve! 
  4710.  
  4711. Contributors - EDM/2 - June 1994 - Volume 2, Issue 6