home *** CD-ROM | disk | FTP | other *** search
-
- ΓòÉΓòÉΓòÉ 1. June 1994 Title Page ΓòÉΓòÉΓòÉ
-
- Welcome to EDM/2 - The Electronic OS/2 Developer's Magazine!
- Portions copyright (c) by Larry Salomon Jr.
- Volume 2, issue 6
-
- Copyright Notice and Other Stuff
-
- The Editor-in-Chief of this electronic magazine is Larry Salomon, Jr.
-
- Portions of EDM/2 are copyrighted by the editors. This publication may be
- freely distributed in electronic form provided that all parts are present in
- their original unmodified form. A reasonable fee may be charged for the
- physical act of distribution; no fee may be charged for the publication itself.
-
- All articles are copyrighted by their authors. No part of any article may be
- reproduced without permission from the original author.
-
- Neither this publication nor the editors are affiliated with International
- Business Machines Corporation.
-
- OS/2 is a registered trademark of International Business Machines Corporation.
- Other trademarks are property of their respective owners. Any mention of a
- product in this publication does not constitute an endorsement or affiliation
- unless specifically stated in the text.
-
- Administrivia
-
- This month has been another hectic one. After a couple of months, when
- releasing a new issue meant around the 10th or so, I decided to get this one
- out on time.
-
- You can see how well I did.
-
- At least one good thing has happened this past month: we now have cable here
- at our house, so my wife watches the Chinese channel (she's from the mainland)
- instead of griping about how much time I spend on the computer.
-
- Seriously, there is a lot of stuff in this issue. The Scratch Patch is teeming
- with goodies for you to snatch up, and there is part 2 of the sprites series as
- well as how to interpret and decompile resources from EXE and DLL files. Great
- stuff!
-
- Format Change
-
- In the quest to make EDM/2 easier to concatenate, Carsten suggested adding a
- header to the beginning of each article and column, to show the title of the
- article or column you are reading. This inspired me to also add a footer at
- the bottom of each section with the article/column/panel name, the date, and
- the volume and issue number. These have been done this issue; contact us to
- let us know what you think about them.
-
- While I'm talking about him, let me publicly acknowledge the work
- above-and-beyond the call of duty that Carsten has put into each issue. The
- quality, in my not-so-humble opinion, has gone up considerably since he started
- catching my mistakes and those of the authors. Thanks a lot for your hard
- work!
-
- Conferences
-
- PC Expo is just around the corner. If you plan to be in New York City, I'm
- interested in meeting you. Send me email. Speaking of which, become more than
- a Team OS/2 member; become more than an OS/2 Evangelist; become an EDM/2
- Promoter. If you go to a SIG that either has OS/2 as its reason for existence,
- or is multi-platform oriented with development being the primary focus, let me
- know; for the IBM PSP Conference, I drew some fliers that I handed out
- throughout the week that I was there, and I can easily send you a PostScript
- version of the flyer so that you can tell everyone about EDM/2 at your next
- gathering.
-
- Title Page - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2. Features for June 1994 ΓòÉΓòÉΓòÉ
-
- The following articles constitute this issue's features:
-
- o Sprites and Animation - Part 2
- o Resources and Decompiling Them
- o Visual REXX Faceoff
-
- Features - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.1. Sprites and Animation - Part 2 ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 2.1.1. Introduction ΓòÉΓòÉΓòÉ
-
- Sprites and Animation - Part 2
-
- Written by Larry Salomon, Jr.
-
- Introduction
-
- Last month, we took a good look at the beginnings of a sprite library that is
- well-suited for simple animation. We looked at:
-
- o how a sprite is drawn
- o how the drawing of sprites requires a mask, which adds an extra burden on the
- management of the sprite data structure by the library
- o how a sprite is moved in a manner that minimizes flicker
-
- But even discussing these things left some holes, namely the background and the
- workarea that enables the flicker-free movement. This month, we will wrap up
- our discussion on the design of the library and will begin delving into the
- code for the sprite library itself. Next month's conclusion will look into the
- intricacies of animating a set of sprites using the i495.exe sample as a
- starting point.
-
- Ch-Ch-Ch-Changes
-
- Ah, there's nothing like quintessential Bowie...
-
- Since last month, I have integrated the sprite library into the Common/2
- library that was on hobbes (if this new version isn't there already, wait for a
- week and remind me if I still have forgotten). However, I have kept the
- original version and have modified it to provide semaphore exclusion to the
- data structures (actually, I surgically cut-n-pasted the related functions from
- Common/2 <grin>), and it is this version that we will present in this series.
- It should be noted, though, that the version in Common/2 does come complete
- with an online reference.
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.1.2. Monkey Bars and the Like ΓòÉΓòÉΓòÉ
-
- Monkey Bars and the Like
-
- A distinguishing characteristic between a sprite and a bitmap is that the
- former has a transparency color which means that whatever is below the sprite
- shows through it. If the background were simply a solid color, this could be
- done through sleight-of-hand by drawing the bitmap with the background color in
- the areas that are to be see-through. Movement would be quite simple, reduced
- to a few WinFillRect() calls and a single GpiWCBitBlt().
-
- Unfortunately, a sprite can make no assumptions about the underlying surface:
- it could be a solid color or it could be a complex drawing or it even could be
- another sprite. Worse yet, we cannot simply take what is already on the
- screen, for what shall we restore there if - for example - the sprite has its
- visibility state set to FALSE?
-
- Because of this (and other reasons), we need to maintain yet another data
- structure which will, among other things, manage a static bitmap to be used for
- the background; we will call it a playground since it is the area in which we
- will let the sprites play. Conceptually, a playground is the "blackboard"
- while each sprite is just a chalk drawing on the blackboard, so all drawing
- related functions are considered to be associated with a playground instead of
- the sprites that occupy a playground.
-
- The playground support must provide the following functions:
-
- o Create a playground
- o Destroy a playground
- o Add a sprite to the playground
- o Remove a sprite from the playground
- o Draw the entire playground
-
- Adding and removing sprites from the playground is needed so that we can access
- data structures in the playground given the sprite handle. For example, only
- one work area is needed per playground since one thread at most can access an
- HPS, so we put the work area in the playground, but need to access this work
- area from each sprite.
-
- Drawing a playground involves drawing the background and then looping through
- its membership list to draw each sprite at its current position. This is
- intended to provide a simple method of processing the WM_PAINT message within
- an application.
-
- ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- If all of these design issues get confusing, remember that I have the power of
- hindsight and you do not, so do not get dismayed or (worse yet) think that I
- have some divine capability to think of these things before writing a line of
- code; I had the same trial-n-error development process that you would have were
- our places exchanged.
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.1.3. Final Design Considerations ΓòÉΓòÉΓòÉ
-
- Final Design Considerations
-
- In even the most elementary computer programming classes, the concept of code
- reuse is hammered into the brains of the students; here, this concept is
- stressed as well. There are many code blocks that are needed in various places
- throughout the library, so these code blocks were turned into functions.
-
- Mutually exclusive access to the data structures is also an important part of
- any good library, and it is implemented here through the use of a mutex
- sempahore and a status flag; the status flag indicates if access has already
- been granted to a function, i.e. if a function calls another function, the
- called function will deadlock if it requests the semaphore. The
- access-granting function is accessSem(), and it would be worth the time to
- understand how this is implemented to avoid confusion later.
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.1.4. Where's Your Library Card? ΓòÉΓòÉΓòÉ
-
- Where's Your Library Card?
-
- Since utilitizing the library involves far more complex coding than the code
- for the library itself (did I ever say that animation was easy?), we will look
- at the library itself. If you have not already done so, unzip the source.zip
- file and take a look at the files within.
-
- MAKEFILE the makefile for the library
-
- SPRITE.C the source file
-
- SPRITE.HPP the .H preprocessor file. This is fed to HEADER.EXE which
- generates an implementor's .H file and a user's .H file.
- You should change the first two lines of this file so that
- the paths make sense.
-
- //@HEADER OUTFILE INT D:\SOURCE\SPRITE\SPRITE.H
- //@HEADER OUTFILE EXT D:\MYINC\SPRITE.H
-
- The INT line defines the file name of the "internal" use .H
- file, while the EXT line defines the file name of the
- "external" use .H file.
-
- SPRITE.H Generated by the command "HEADER -tINT SPRITE.HPP"
-
- SPRITE.OBJ Object file
-
- SPRITE.LIB Library file
-
- HEADER.EXE Header file preprocessor. I think I have placed this on
- hobbes, possibly under the name HPREP. If not, this is an
- older version, but it will do. (I keep forgetting to bring
- the newer version in to work.)
-
- Before we can begin to understand the code, we must first understand the data
- structures on which the code operates, so we first look at the playground:
-
- typedef struct _PLAYGROUND {
- ULONG ulSig;
- ULONG ulStatus;
- HMTX hsmAccess;
-
- HAB habAnchor;
- HDC hdcWork;
- HPS hpsWork;
- HBITMAP hbmWork;
-
- HBITMAP hbmBack;
- BITMAPINFOHEADER2 bmihBack;
- LONG lBackColor;
-
- BOOL bUpdate;
-
- HSPRITE ahsSprites[MAX_SPRITES];
- ULONG ulNumMembers;
- } PLAYGROUND, *HPLAYGROUND;
- typedef HPLAYGROUND *PHPLAYGROUND;
-
- ulSig 4-byte signature for the data structure, used for parameter
- validation.
-
- ulStatus 32-bit status flags used for semaphore access at this time.
-
- hsmAccess mutex (mutual exclusion) semaphore handle.
-
- habAnchor anchor block handle of the calling thread.
-
- hdcWork OD_MEMORY device context handle for the work area.
-
- hpsWork presentation space handle associated with hdcWork.
-
- hbmWork bitmap handle set into hpsWork.
-
- hbmBack bitmap handle for the background bitmap. If NULLHANDLE,
- the playground has a background color instead (lBackColor).
-
- bmihBack bitmap information header for hbmBack. If hbmBack is
- NULLHANDLE, the cx and cy fields indicate the size of the
- playground; otherwise the size of the playground is
- specified by the size of the background bitmap.
-
- lBackColor the background color of the playground, if hbmBack is
- NULLHANDLE.
-
- bUpdate update flag. If FALSE, no drawing is actually performed.
- This is useful for changing sprites in place.
-
- ahsSprites array of sprite handles comprising the membership list.
-
- ulNumMembers current number of members.
-
- We will see how these fields are used when we look at the code. But now, we
- will look at the sprite structure:
-
- typedef struct _SPRITE {
- ULONG ulSig;
- ULONG ulStatus;
- HMTX hsmAccess;
-
- HAB habAnchor;
- HBITMAP hbmBitmap;
- HBITMAP hbmMask;
- BITMAPINFOHEADER2 bmihBitmap;
- BITMAPINFOHEADER2 bmihMask;
-
- struct _PLAYGROUND *hpgPlay;
- POINTL ptlPos;
- BOOL bVisible;
- } SPRITE, *HSPRITE;
- typedef HSPRITE *PHSPRITE;
-
- ulSig 4-byte signature for the data structure, used for parameter
- validation.
-
- ulStatus 32-bit status flags used for semaphore access at this time.
-
- hsmAccess mutex (mutual exclusion) semaphore handle.
-
- habAnchor anchor block handle of the calling thread.
-
- hbmBitmap bitmap handle which defines the sprite.
-
- hbmMask bitmap handle which defines the mask.
-
- bmihBitmap bitmap information header for hbmBitmap.
-
- bmihMask bitmap information header for hbmMask.
-
- hpgPlay playground handle of which the sprite is a member.
-
- ptlPos current position.
-
- bVisible current visibility state.
-
- A comment on the list of exposed functions below: notice the symmetry of the
- function names. For each create, there is a destroy; querys have corresponding
- sets when appropriate; the add has a remove. While much is often said about
- intuitiveness of the user-interface, the same concepts along with the
- advantages gained can be applied to the "programmer-interface". The
- non-exposed (internal) functions, obviously, do not need to follow this
- guideline, although it does help if more than one person is developing and/or
- maintaining the code.
-
- Each function below is a hypertext link to its code and the explanation of the
- code; feel free to explore the functions in any order.
-
- Internal Functions
-
- o accessSem
- o clipBltPoints
- o drawSpriteAt
- o drawBackAt
- o getMemHps
- o queryHandleType
-
- External Functions
-
- o SprAddSprite
- o SprCreatePlayground
- o SprCreateSprite
- o SprDestroyPlayground
- o SprDestroySprite
- o SprDrawPlayground
- o SprDrawSprite
- o SprQueryPlaygroundBack
- o SprQueryPlaygroundColor
- o SprQueryPlaygroundSize
- o SprQuerySpritePosition
- o SprQuerySpriteRect
- o SprQuerySpriteSize
- o SprQuerySpriteVisibility
- o SprQueryUpdateFlag
- o SprRemoveSprite
- o SprSetPlaygroundBack
- o SprSetPlaygroundColor
- o SprSetPlaygroundSize
- o SprSetSpritePosition
- o SprSetSpriteVisibility
- o SprSetUpdateFlag
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.1.5. Summary ΓòÉΓòÉΓòÉ
-
- Summary
-
- This month, we finished our discussion of the design of the sprite library by
- describing the need for a master data structure called the playground, and the
- code to implement the library routines was presented to illustrate the concepts
- that we have already learned in our discussions up to this point. Next month,
- we will take these underpinings and will apply them to the i495.exe application
- to see how they can be utililized to perform rudimentary animation.
-
- All comments, suggestions, bugs, etc. are welcome c/o the author.
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> queryHandleType ΓòÉΓòÉΓòÉ
-
- queryHandleType
-
- The purpose of this function is parameter validation, and uses the ulSig field
- of both data structures. Note that for non-accessible memory pointers, this
- function will still cause the application to trap (although it is possible to
- check for NULL).
-
- static ULONG queryHandleType(PVOID pvHandle)
- //-------------------------------------------------------------------------
- // This function returns a QH_* constant specifying the handle type. It
- // will be replaced by CmnQueryHandle() when this subsystem is integrated
- // into Common/2.
- //
- // Input: pvHandle - points the the handle to query
- // Returns: QH_ERROR if error, QH_* constant otherwise
- //-------------------------------------------------------------------------
- {
- if (pvHandle==NULL) {
- return QH_ERROR;
- } /* endif */
-
- switch (((PHEADER)pvHandle)->ulSig) {
- case SIG_HSPRITE:
- return QH_HSPRITE;
- case SIG_HPLAYGROUND:
- return QH_HPLAYGROUND;
- default:
- return QH_ERROR;
- } /* endswitch */
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> accessSem ΓòÉΓòÉΓòÉ
-
- accessSem
-
- The purpose of this function is to provide mutually exclusive access to the
- data structures used by the library. By requiring that all data structures
- have a common set of fields defined first (semaphore handle, etc.), we can cast
- the data structures to the type PHANDLE to allow us access to the common
- fields.
-
- static USHORT accessSem(PHEADER phHandle,USHORT usAction)
- //-------------------------------------------------------------------------
- // This function provides semaphore access for mutual exclusion of private
- // data access.
- //
- // Input: phHandle - points to the handle header
- // usAction - specifies the action to perform:
- // ACCSEM_SET - requests access to the handle
- // ACCSEM_CLEAR - relinquishes access to the handle
- // ACCSEM_ALREADYSET - not used
- // ACCSEM_NOTSET - not used
- // Returns: ACCSEM_ERROR if an error occurred, else the action to take
- // on the next call to this function
- //-------------------------------------------------------------------------
- {
- switch (usAction) {
- case ACCSEM_SET:
- if ((phHandle->ulStatus & HSTATUS_INLIBRARY)!=0) {
- return ACCSEM_ALREADYSET;
- } /* endif */
-
- DosRequestMutexSem(phHandle->hsmAccess,SEM_INDEFINITE_WAIT);
- phHandle->ulStatus|=HSTATUS_INLIBRARY;
- return ACCSEM_CLEAR;
- case ACCSEM_CLEAR:
- if ((phHandle->ulStatus & HSTATUS_INLIBRARY)==0) {
- return ACCSEM_NOTSET;
- } /* endif */
-
- DosReleaseMutexSem(phHandle->hsmAccess);
- phHandle->ulStatus&=~HSTATUS_INLIBRARY;
- return ACCSEM_SET;
- case ACCSEM_ALREADYSET:
- return ACCSEM_NOTSET;
- case ACCSEM_NOTSET:
- return ACCSEM_ALREADYSET;
- default:
- return ACCSEM_ERROR;
- } /* endswitch */
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> getMemHps ΓòÉΓòÉΓòÉ
-
- getMemHps
-
- There is nothing special about this function that needs to be noted.
-
- static HPS getMemHps(HAB habAnchor)
- //-------------------------------------------------------------------------
- // This function creates an HPS associated with a memory HDC. The
- // HDC handle can be retrieved using the GpiQueryDevice() function.
- //
- // Input: habAnchor - anchor block of the calling thread.
- // Returns: HPS handle if successful, NULLHANDLE otherwise
- //-------------------------------------------------------------------------
- {
- HDC hdcMem;
- SIZEL szlHps;
- HPS hpsMem;
-
- hdcMem=DevOpenDC(habAnchor,OD_MEMORY,"*",0,NULL,NULLHANDLE);
- if (hdcMem==NULLHANDLE) {
- return NULLHANDLE;
- } /* endif */
-
- szlHps.cx=0;
- szlHps.cy=0;
-
- hpsMem=GpiCreatePS(habAnchor,
- hdcMem,
- &szlHps,
- PU_PELS|GPIT_MICRO|GPIA_ASSOC);
- if (hpsMem==NULLHANDLE) {
- DevCloseDC(hdcMem);
- } /* endif */
-
- return hpsMem;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> clipBltPoints ΓòÉΓòÉΓòÉ
-
- clipBltPoints
-
- The library clips all drawing to the playground size. (A future enhancement to
- the library would be to allow the application to specify where in a window the
- lower-left corner of the playground should be.) This function clips a pair of
- rectangles (which are defined by a pair of points, meaning that we have four
- points total) to a rectangle defined to be (0,0)-(pszlPlay->cx,pszlPlay->cy).
-
- You can see the clipping effect by enlarging the size of the i495 window.
-
- static BOOL clipBltPoints(HAB habAnchor,PPOINTL pptlArray,PSIZEL pszlPlay)
- //-------------------------------------------------------------------------
- // This function clips the first two points in pptlArray to a rectangle
- // of size pszlPlay. The last two points in pptlArray are then adjusted
- // by the amount clipped.
- //
- // It is assumed that the first two points refer to a coordinate space
- // of size pszlPlay and that the two rectangles formed by the first and
- // last pair of points in pptlArray are of the same size.
- //
- // Input: habAnchor - anchor block of the calling thread.
- // pptlArray - points to array of 4 points for GpiBitBlt()
- // pszlPlay - points to the size of the playground to clip to
- // Output: pptlArray - points to adjusted array
- // Returns: TRUE if at least one pel was *not* clipped, FALSE if all
- // points fell outside of the clipping region.
- //-------------------------------------------------------------------------
- {
- RECTL rclPlay;
- RECTL rclDest;
- RECTL rclInter;
- RECTL rclDelta;
-
- rclPlay.xLeft=0;
- rclPlay.yBottom=0;
- rclPlay.xRight=pszlPlay->cx-1;
- rclPlay.yTop=pszlPlay->cy-1;
-
- rclDest.xLeft=pptlArray[0].x;
- rclDest.yBottom=pptlArray[0].y;
- rclDest.xRight=pptlArray[1].x;
- rclDest.yTop=pptlArray[1].y;
-
- WinIntersectRect(habAnchor,&rclInter,&rclPlay,&rclDest);
-
- //----------------------------------------------------------------------
- // If the result is an empty rectangle, return FALSE to indicate so.
- //----------------------------------------------------------------------
- if (WinIsRectEmpty(habAnchor,&rclInter)) {
- return FALSE;
- } /* endif */
-
- rclDelta.xLeft=rclDest.xLeft-rclInter.xLeft;
- rclDelta.yBottom=rclDest.yBottom-rclInter.yBottom;
- rclDelta.xRight=rclDest.xRight-rclInter.xRight;
- rclDelta.yTop=rclDest.yTop-rclInter.yTop;
-
- pptlArray[0].x-=rclDelta.xLeft;
- pptlArray[0].y-=rclDelta.yBottom;
- pptlArray[1].x-=rclDelta.xRight;
- pptlArray[1].y-=rclDelta.yTop;
- pptlArray[2].x-=rclDelta.xLeft;
- pptlArray[2].y-=rclDelta.yBottom;
- pptlArray[3].x-=rclDelta.xRight;
- pptlArray[3].y-=rclDelta.yTop;
- return TRUE;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> drawSpriteAt ΓòÉΓòÉΓòÉ
-
- drawSpriteAt
-
- This function draws a sprite at the specified position; it calls
- clipBltPoints() to insure that all necessary clipping is performed. An
- advantage of having this as a function is that the transition to z-order
- implementation is eased somewhat. It is because of this that the background is
- not drawn in this function, but is removed to its own function - drawBackAt().
-
- static BOOL drawSpriteAt(HPS hpsDraw,
- HSPRITE hsSprite,
- PSIZEL pszlSize,
- PPOINTL pptlPos)
- //-------------------------------------------------------------------------
- // This function draws the sprite at the specified position. It is assumed
- // that the background has already been drawn into hpsDraw before this
- // function is called.
- //
- // Input: hpsDraw - handle of the presentation space to draw in
- // hsSprite - handle of the sprite to draw
- // pszlSize - points to the size of hpsDraw. If NULL, the size
- // of the playground is used.
- // pptlPos - points to the point specifying the position. If
- // NULL, the sprite's current position is used.
- // Returns: TRUE if successful, FALSE otherwise
- //-------------------------------------------------------------------------
- {
- POINTL ptlUse;
- SIZEL szlUse;
- POINTL aptlPoints[4];
-
- if (!hsSprite->hpgPlay->bUpdate) {
- return TRUE;
- } /* endif */
-
- //----------------------------------------------------------------------
- // Initialize the local variables with either what was passed in or
- // the defaults as noted above in the function prologue
- //----------------------------------------------------------------------
- if (pptlPos==NULL) {
- ptlUse=hsSprite->ptlPos;
- } else {
- ptlUse=*pptlPos;
- } /* endif */
-
- if (pszlSize==NULL) {
- SprQueryPlaygroundSize(hsSprite->hpgPlay,&szlUse);
- } else {
- szlUse=*pszlSize;
- } /* endif */
-
- aptlPoints[0].x=ptlUse.x;
- aptlPoints[0].y=ptlUse.y;
- aptlPoints[1].x=aptlPoints[0].x+hsSprite->bmihMask.cx-1;
- aptlPoints[1].y=aptlPoints[0].y+hsSprite->bmihMask.cy-1;
- aptlPoints[2].x=0;
- aptlPoints[2].y=0;
- aptlPoints[3].x=aptlPoints[2].x+hsSprite->bmihMask.cx;
- aptlPoints[3].y=aptlPoints[2].y+hsSprite->bmihMask.cy;
-
- if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlUse)) {
- //-------------------------------------------------------------------
- // Blit the mask and then the bitmap
- //-------------------------------------------------------------------
- GpiWCBitBlt(hpsDraw,
- hsSprite->hbmMask,
- 4,
- aptlPoints,
- ROP_SRCAND,
- BBO_IGNORE);
-
- GpiWCBitBlt(hpsDraw,
- hsSprite->hbmBitmap,
- 4,
- aptlPoints,
- ROP_SRCPAINT,
- BBO_IGNORE);
- } /* endif */
-
- return TRUE;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> drawBackAt ΓòÉΓòÉΓòÉ
-
- drawBackAt
-
- This function draws the background at the specified position with the specified
- size. This is used to copy the background onto the display as well as into the
- work area as needed. Notice that this is where background coloring is done if
- a background bitmap was not specified.
-
- static BOOL drawBackAt(HPS hpsDraw,
- HPLAYGROUND hpgPlay,
- PRECTL prclDest,
- PSIZEL pszlDest,
- PRECTL prclSrc)
- //-------------------------------------------------------------------------
- // This function draws the background in the specified presentation space.
- //
- // Input: hpsDraw - handle of the presentation space to draw in
- // hpgPlay - handle of the playground containing the background
- // prclDest - points to the destination rectangle. If NULL, the
- // value of prclSrc is used.
- // pszlDest - points to the size of hpsDraw. If NULL, the size of
- // the playground is used.
- // prclSrc - points to the source rectangle. If NULL, the entire
- // background is painted.
- // Returns: TRUE if successful, FALSE otherwise
- //-------------------------------------------------------------------------
- {
- RECTL rclUseSrc;
- RECTL rclUseDest;
- SIZEL szlUse;
- POINTL aptlPoints[4];
-
- if (!hpgPlay->bUpdate) {
- return TRUE;
- } /* endif */
-
- if (prclSrc==NULL) {
- rclUseSrc.xLeft=0;
- rclUseSrc.yBottom=0;
- rclUseSrc.xRight=hpgPlay->bmihBack.cx;
- rclUseSrc.yTop=hpgPlay->bmihBack.cy;
- } else {
- rclUseSrc=*prclSrc;
- } /* endif */
-
- if (prclDest==NULL) {
- rclUseDest=rclUseSrc;
- rclUseDest.xRight--;
- rclUseDest.yTop--;
- } else {
- rclUseDest=*prclDest;
- } /* endif */
-
- if (pszlDest==NULL) {
- szlUse.cx=hpgPlay->bmihBack.cx;
- szlUse.cy=hpgPlay->bmihBack.cy;
- } else {
- szlUse=*pszlDest;
- } /* endif */
-
- aptlPoints[0].x=rclUseDest.xLeft;
- aptlPoints[0].y=rclUseDest.yBottom;
- aptlPoints[1].x=rclUseDest.xRight;
- aptlPoints[1].y=rclUseDest.yTop;
- aptlPoints[2].x=rclUseSrc.xLeft;
- aptlPoints[2].y=rclUseSrc.yBottom;
- aptlPoints[3].x=rclUseSrc.xRight;
- aptlPoints[3].y=rclUseSrc.yTop;
-
- if (clipBltPoints(hpgPlay->habAnchor,aptlPoints,&szlUse)) {
- //-------------------------------------------------------------------
- // If there is a background bitmap, blit it, otherwise black out the
- // area.
- //-------------------------------------------------------------------
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- GpiWCBitBlt(hpsDraw,
- hpgPlay->hbmBack,
- 4,
- aptlPoints,
- ROP_SRCCOPY,
- BBO_IGNORE);
- } else {
- //----------------------------------------------------------------
- // WinFillRect() excludes the top and right of the rectangle
- //----------------------------------------------------------------
- rclUseDest.xRight++;
- rclUseDest.yTop++;
- WinFillRect(hpsDraw,&rclUseDest,hpgPlay->lBackColor);
- } /* endif */
- } /* endif */
-
- return TRUE;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprAddSprite ΓòÉΓòÉΓòÉ
-
- SprAddSprite
-
- This function adds a sprite handle to the end of the ahsSprites array within
- the HPLAYGROUND structure. By insuring - in SprRemoveSprite() - that the array
- is always compact, we save a test for NULL in the SprDrawPlayground() loop.
- Note that there are no functions for modifying the order of the sprite within
- the array, because as of now there is no need. However, once z-ordering is
- added to the library, another function - SprSetLayer() - will be added to set
- the sprite's position to the top, bottom, previous, or next position in the
- z-order stack.
-
- SPRERROR EXPENTRY SprAddSprite(HPLAYGROUND hpgPlay,HSPRITE hsSprite)
- //-------------------------------------------------------------------------
- // This function labels a sprite as a "member" of the specified playground.
- // Doing so allows the application to control the sprite's position,
- // visibility, etc. on a drawing surface.
- //
- // Input: hpgPlay - handle to the playground
- // hsSprite - handle to the sprite to add
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } else
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hsSprite->hpgPlay!=NULL) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_HASPLAYGROUND;
- } else
- if (hpgPlay->ulNumMembers==MAX_SPRITES) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_PLAYGROUNDFULL;
- } /* endif */
-
- hpgPlay->ahsSprites[hpgPlay->ulNumMembers]=hsSprite;
- hpgPlay->ulNumMembers++;
-
- hsSprite->hpgPlay=hpgPlay;
-
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprCreatePlayground ΓòÉΓòÉΓòÉ
-
- SprCreatePlayground
-
- Note the use of calloc(). Using any of the C runtime is not a good thing
- because it is implemented (usually) using suballocation, meaning an application
- can accidentally increment hpgPlay by 2 bytes (for example) and would not get a
- trap notification by OS/2; instead unpredictable behavior would occur, which
- misleads the developer into thinking a stack error is occuring. It would be
- better to use DosAllocMem() instead.
-
- SPRERROR EXPENTRY SprCreatePlayground(HAB habAnchor,PHPLAYGROUND phpgPlay)
- //-------------------------------------------------------------------------
- // This function creates a playground to which sprites can be added.
- //
- // Input: habAnchor - anchor block of the calling thread.
- // Output: phpgPlay - points to the variable with the HPLAYGROUND handle
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- BITMAPINFOHEADER2 bmihInfo;
- LONG lValue;
-
- *phpgPlay=calloc(1,sizeof(PLAYGROUND));
- if (*phpgPlay==NULL) {
- *phpgPlay=NULL;
- return SPR_ERR_NOMEMORY;
- } /* endif */
-
- (*phpgPlay)->ulSig=SIG_HPLAYGROUND;
- (*phpgPlay)->ulStatus=0;
-
- if (DosCreateMutexSem(NULL,&(*phpgPlay)->hsmAccess,0,FALSE)) {
- free(*phpgPlay);
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- (*phpgPlay)->habAnchor=habAnchor;
-
- (*phpgPlay)->hpsWork=getMemHps(habAnchor);
- if ((*phpgPlay)->hpsWork==NULLHANDLE) {
- free(*phpgPlay);
- *phpgPlay=NULL;
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- (*phpgPlay)->hdcWork=GpiQueryDevice((*phpgPlay)->hpsWork);
-
- Since the workarea is used for moving sprites with position overlap, the size
- of the bitmap to be set in the HPS is (MAX_SPRITE_CX*2,MAX_SPRITE_CY*2).
-
- bmihInfo.cbFix=16;
- bmihInfo.cx=MAX_SPRITE_CX*2;
- bmihInfo.cy=MAX_SPRITE_CY*2;
- bmihInfo.cPlanes=1;
-
- DevQueryCaps((*phpgPlay)->hdcWork,CAPS_COLOR_BITCOUNT,1,&lValue);
- bmihInfo.cBitCount=lValue;
-
- (*phpgPlay)->hbmWork=GpiCreateBitmap((*phpgPlay)->hpsWork,
- &bmihInfo,
- 0,
- NULL,
- NULL);
- if ((*phpgPlay)->hbmWork==NULLHANDLE) {
- GpiDestroyPS((*phpgPlay)->hpsWork);
- DevCloseDC((*phpgPlay)->hdcWork);
- free(*phpgPlay);
- *phpgPlay=NULL;
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- GpiSetBitmap((*phpgPlay)->hpsWork,(*phpgPlay)->hbmWork);
-
- (*phpgPlay)->lBackColor=CLR_BLACK;
- (*phpgPlay)->bUpdate=TRUE;
-
- (*phpgPlay)->hbmBack=NULLHANDLE;
- (*phpgPlay)->ulNumMembers=0;
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprCreateSprite ΓòÉΓòÉΓòÉ
-
- SprCreateSprite
-
- See SprCreatePlayground() for notes on using calloc().
-
- SPRERROR EXPENTRY SprCreateSprite(HAB habAnchor,
- HBITMAP hbmBitmap,
- PHSPRITE phsSprite)
- //-------------------------------------------------------------------------
- // This function creates a sprite from the specified bitmap. The sprite
- // cannot be moved, shown, etc., however, until it is associated with a
- // playground.
- //
- // The color black is used as the transparency color. If you need to use
- // black in the bitmap without it becoming transparent, use the next
- // closest color. <grin>
- //
- // New sprites are initialized as being at position (0,0) and hidden.
- //
- // Note that, once this function is called, the bitmap is managed by
- // the sprite subsystem. The bitmap should *NOT* be deleted by the
- // application or else unpredictable results will occur.
- //
- // Input: habAnchor - anchor block of the calling thread.
- // hbmBitmap - handle to the bitmap
- // Output: phsSprite - points to the sprite handle
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- HPS hpsMem;
- HDC hdcMem;
- POINTL aptlPoints[4];
-
- *phsSprite=calloc(1,sizeof(SPRITE));
- if (*phsSprite==NULL) {
- *phsSprite=NULL;
- return SPR_ERR_NOMEMORY;
- } /* endif */
-
- (*phsSprite)->ulSig=SIG_HSPRITE;
- (*phsSprite)->ulStatus=0;
-
- if (DosCreateMutexSem(NULL,&(*phsSprite)->hsmAccess,0,FALSE)) {
- free(*phsSprite);
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- (*phsSprite)->habAnchor=habAnchor;
-
- (*phsSprite)->hbmBitmap=hbmBitmap;
-
- (*phsSprite)->ptlPos.x=0;
- (*phsSprite)->ptlPos.y=0;
- (*phsSprite)->bVisible=FALSE;
-
- (*phsSprite)->bmihBitmap.cbFix=16;
- GpiQueryBitmapInfoHeader((*phsSprite)->hbmBitmap,&(*phsSprite)->bmihBitmap);
-
- //----------------------------------------------------------------------
- // Get an OD_MEMORY HDC and HPS to create the mask in. Since we will
- // save the bitmap handle, but don't give a $%#@ about the HDC/HPS, they
- // can be local variables.
- //----------------------------------------------------------------------
- hpsMem=getMemHps(habAnchor);
- if (hpsMem==NULLHANDLE) {
- free(*phsSprite);
- *phsSprite=NULL;
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- hdcMem=GpiQueryDevice(hpsMem);
-
- (*phsSprite)->bmihMask=(*phsSprite)->bmihBitmap;
- (*phsSprite)->bmihMask.cPlanes=1;
- (*phsSprite)->bmihMask.cBitCount=1;
-
- (*phsSprite)->hbmMask=GpiCreateBitmap(hpsMem,
- &(*phsSprite)->bmihMask,
- 0,
- NULL,
- NULL);
- if ((*phsSprite)->hbmMask==NULLHANDLE) {
- GpiDestroyPS(hpsMem);
- DevCloseDC(hdcMem);
- free(*phsSprite);
- *phsSprite=NULL;
- return SPR_ERR_RESOURCE;
- } /* endif */
-
- GpiSetBitmap(hpsMem,(*phsSprite)->hbmMask);
-
- aptlPoints[0].x=0;
- aptlPoints[0].y=0;
- aptlPoints[1].x=aptlPoints[0].x+(*phsSprite)->bmihMask.cx-1;
- aptlPoints[1].y=aptlPoints[0].y+(*phsSprite)->bmihMask.cy-1;
- aptlPoints[2].x=0;
- aptlPoints[2].y=0;
- aptlPoints[3].x=aptlPoints[2].x+(*phsSprite)->bmihBitmap.cx;
- aptlPoints[3].y=aptlPoints[2].y+(*phsSprite)->bmihBitmap.cy;
-
- //----------------------------------------------------------------------
- // Set the foreground to white and the background to black so that this
- // works. The resulting behavior in the GpiWCBitBlt() call is
- // inconsistent with the docs, so I don't know what to think.
- //----------------------------------------------------------------------
- GpiSetColor(hpsMem,CLR_WHITE);
- GpiSetBackColor(hpsMem,CLR_BLACK);
-
- GpiWCBitBlt(hpsMem,
- (*phsSprite)->hbmBitmap,
- 4,
- aptlPoints,
- ROP_SRCCOPY,
- BBO_IGNORE);
- GpiSetBitmap(hpsMem,NULLHANDLE);
- GpiDestroyPS(hpsMem);
- DevCloseDC(hdcMem);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprDestroyPlayground ΓòÉΓòÉΓòÉ
-
- SprDestroyPlayground
-
- This function destroys the sprites in the playground before destroying the
- playground itself. However, if you look in SprDestroySprite() you'll see a
- check to see if the sprite is still a member of a playground (and fails if it
- is); thus, we have to call SprRemoveSprite() first.
-
- SPRERROR EXPENTRY SprDestroyPlayground(HPLAYGROUND hpgPlay)
- //-------------------------------------------------------------------------
- // This function destroys the playground including any sprites that are
- // still members of it. All resources consumed by the playground,
- // including the back bitmap, are returned to the system.
- //
- // Input: hpgPlay - handle to the playground
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- ULONG ulIndex;
- HSPRITE hsSprite;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- GpiDeleteBitmap(hpgPlay->hbmBack);
- } /* endif */
-
- for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
- hsSprite=hpgPlay->ahsSprites[ulIndex];
- SprRemoveSprite(hpgPlay,hsSprite);
- SprDestroySprite(hsSprite);
- } /* endfor */
-
- GpiSetBitmap(hpgPlay->hpsWork,NULLHANDLE);
-
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- GpiDeleteBitmap(hpgPlay->hbmBack);
- } /* endif */
-
- GpiDestroyPS(hpgPlay->hpsWork);
- DevCloseDC(hpgPlay->hdcWork);
- accessSem((PHEADER)hpgPlay,usAction);
- free(hpgPlay);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprDestroySprite ΓòÉΓòÉΓòÉ
-
- SprDestroySprite
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprDestroySprite(HSPRITE hsSprite)
- //-------------------------------------------------------------------------
- // This function destroys the sprite and returns all resources to the
- // system.
- //
- // Input: hsSprite - handle to the sprite
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay!=NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASPLAYGROUND;
- } /* endif */
-
- GpiDeleteBitmap(hsSprite->hbmBitmap);
- GpiDeleteBitmap(hsSprite->hbmMask);
- accessSem((PHEADER)hsSprite,usAction);
- free(hsSprite);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprDrawPlayground ΓòÉΓòÉΓòÉ
-
- SprDrawPlayground
-
- See SprAddSprite() for notes about ahsSprites being a compact array for
- performance reasons.
-
- SPRERROR EXPENTRY SprDrawPlayground(HPS hpsDraw,HPLAYGROUND hpgPlay)
- //-------------------------------------------------------------------------
- // This function redraws the playground and all sprites belonging to the
- // playground.
- //
- // Input: hpsDraw - handle to the HPS to draw the playground in
- // hpgPlay - handle to the playground
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- ULONG ulIndex;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hpgPlay->bUpdate) {
- drawBackAt(hpsDraw,hpgPlay,NULL,NULL,NULL);
-
- for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
- SprDrawSprite(hpsDraw,hpgPlay->ahsSprites[ulIndex]);
- } /* endfor */
- } /* endif */
-
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprDrawSprite ΓòÉΓòÉΓòÉ
-
- SprDrawSprite
-
- Given the drawSpriteAt() and drawBackAt() functions, the implementation of this
- function is fairly trivial.
-
- SPRERROR EXPENTRY SprDrawSprite(HPS hpsDraw,HSPRITE hsSprite)
- //-------------------------------------------------------------------------
- // This function draws a sprite
- //
- // Input: hpsDraw - handle to the HPS to draw the sprite in
- // hsSprite - handle to the sprite
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- RECTL rclSprite;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- if ((!hsSprite->bVisible) || (!hsSprite->hpgPlay->bUpdate)) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- } /* endif */
-
- rclSprite.xLeft=hsSprite->ptlPos.x;
- rclSprite.yBottom=hsSprite->ptlPos.y;
- rclSprite.xRight=rclSprite.xLeft+hsSprite->bmihMask.cx;
- rclSprite.yTop=rclSprite.yBottom+hsSprite->bmihMask.cy;
-
- drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSprite);
- drawSpriteAt(hpsDraw,hsSprite,NULL,NULL);
-
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundBack ΓòÉΓòÉΓòÉ
-
- SprQueryPlaygroundBack
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQueryPlaygroundBack(HPLAYGROUND hpgPlay,
- HBITMAP *phbmBack)
- //-------------------------------------------------------------------------
- // This function returns the handle of the background bitmap currently in
- // use.
- //
- // Input: hpgPlay - handle to the playground
- // Output: phbmBack - points to the handle to the background bitmap.
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
- *phbmBack=hpgPlay->hbmBack;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundColor ΓòÉΓòÉΓòÉ
-
- SprQueryPlaygroundColor
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQueryPlaygroundColor(HPLAYGROUND hpgPlay,
- PLONG plBackColor)
- //-------------------------------------------------------------------------
- // This function returns the background color of the playground and is
- // only valid if the playground doesn't have a bitmap.
- //
- // Input: hpgPlay - handle to the playground
- // plBackColor - points to the variable to receive the background
- // color
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_HASBACKGROUND;
- } /* endif */
-
- *plBackColor=hpgPlay->lBackColor;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQueryPlaygroundSize ΓòÉΓòÉΓòÉ
-
- SprQueryPlaygroundSize
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQueryPlaygroundSize(HPLAYGROUND hpgPlay,PSIZEL pszlSize)
- //-------------------------------------------------------------------------
- // This function returns the size of the playground. For playgrounds with
- // bitmaps set as the background, the returned value is the size of the
- // bitmap. Otherwise, the returned value is that which was specified on
- // the last call to SprSetPlaygroundSize().
- //
- // Input: hpgPlay - handle to the playground
- // pszlSize - points to the variable to receive the size of the
- // playground
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
- pszlSize->cx=hpgPlay->bmihBack.cx;
- pszlSize->cy=hpgPlay->bmihBack.cy;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQuerySpritePosition ΓòÉΓòÉΓòÉ
-
- SprQuerySpritePosition
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQuerySpritePosition(HSPRITE hsSprite,PPOINTL pptlPos)
- //-------------------------------------------------------------------------
- // This function returns the current position of the sprite. Note that
- // a sprite has a current position even if it is hidden.
- //
- // Input: hsSprite - handle to the sprite
- // Output: pptlPos - points to the current position
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- *pptlPos=hsSprite->ptlPos;
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteRect ΓòÉΓòÉΓòÉ
-
- SprQuerySpriteRect
-
- Since the bounding rectangle of a sprite varies with its position, and since a
- sprite cannot have a position until it is a member of a playground, this
- function checks for membership and fails if there is none. Note that the
- rectangle returned is all-inclusive, i.e. the upper and right edge of the
- rectangle is part of the sprite.
-
- SPRERROR EXPENTRY SprQuerySpriteRect(HSPRITE hsSprite,PRECTL prclRect)
- //-------------------------------------------------------------------------
- // This function returns the bounding rectangle of the sprite at its
- // current position.
- //
- // Input: hsSprite - handle to the sprite
- // Output: prclRect - points to the current bounding rectangle
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- prclRect->xLeft=hsSprite->ptlPos.x;
- prclRect->yBottom=hsSprite->ptlPos.y;
- prclRect->xRight=prclRect->xLeft+hsSprite->bmihBitmap.cx-1;
- prclRect->yTop=prclRect->yBottom+hsSprite->bmihBitmap.cy-1;
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteSize ΓòÉΓòÉΓòÉ
-
- SprQuerySpriteSize
-
- Unlike SprQuerySpritePosition() and SprQuerySpriteRect(), SprQuerySpriteSize()
- is not variant, but is fixed at the time of creation, so we do not need to
- check for membership in a playground.
-
- SPRERROR EXPENTRY SprQuerySpriteSize(HSPRITE hsSprite,PSIZEL pszlSize)
- //-------------------------------------------------------------------------
- // This function returns the current size of the sprite.
- //
- // Input: hsSprite - handle to the sprite
- // Output: pszlSize - points to the current size
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
- pszlSize->cx=hsSprite->bmihBitmap.cx;
- pszlSize->cy=hsSprite->bmihBitmap.cy;
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQuerySpriteVisibility ΓòÉΓòÉΓòÉ
-
- SprQuerySpriteVisibility
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQuerySpriteVisibility(HSPRITE hsSprite,PBOOL pbVisible)
- //-------------------------------------------------------------------------
- // This function returns the visibility state of the sprite
- //
- // Input: hsSprite - handle to the sprite
- // Output: pbVisible - points to the visibility state
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- *pbVisible=hsSprite->bVisible;
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprQueryUpdateFlag ΓòÉΓòÉΓòÉ
-
- SprQueryUpdateFlag
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprQueryUpdateFlag(HPLAYGROUND hpgPlay,PBOOL pbUpdate)
- //-------------------------------------------------------------------------
- // This function returns the setting of the update flag. See the notes
- // for SprSetUpdateFlag() for more information about this setting.
- //
- // Input: hpgPlay - handle to the playground
- // pbUpdate - points to the variable to receive the update flag
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
- *pbUpdate=hpgPlay->bUpdate;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprRemoveSprite ΓòÉΓòÉΓòÉ
-
- SprRemoveSprite
-
- This function removes a sprite from the ahsSprites field of the HPLAYGROUND
- structure and moves all members after the sprite down one slot in the array.
-
- SPRERROR EXPENTRY SprRemoveSprite(HPLAYGROUND hpgPlay,HSPRITE hsSprite)
- //-------------------------------------------------------------------------
- // This function removes the sprite from the membership list of the
- // specified playground. The sprite can then be added to another
- // playground, or this one at a later time.
- //
- // Since there is a limited number of sprites that can be members of
- // a playground, this function can be used to temporarily remove unused
- // sprites from a playground so that others can be used.
- //
- // Input: hpgPlay - handle to the playground
- // hsSprite - handle to the sprite to remove
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- ULONG ulIndex;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } else
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- for (ulIndex=0; ulIndex<hpgPlay->ulNumMembers; ulIndex++) {
- if (hpgPlay->ahsSprites[ulIndex]==hsSprite) {
- break;
- } /* endif */
- } /* endfor */
-
- if (ulIndex==hpgPlay->ulNumMembers) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- //----------------------------------------------------------------------
- // Adjust the member array by moving all of the sprites after the one
- // being removed to the slot just before there current position. Then,
- // decrement the number of members and we're done.
- //----------------------------------------------------------------------
- hpgPlay->ulNumMembers--;
-
- while (ulIndex<hpgPlay->ulNumMembers) {
- hpgPlay->ahsSprites[ulIndex]=hpgPlay->ahsSprites[ulIndex+1];
- ulIndex++;
- } /* endwhile */
-
- hpgPlay->ahsSprites[ulIndex]=NULL;
- hsSprite->hpgPlay=NULL;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundBack ΓòÉΓòÉΓòÉ
-
- SprSetPlaygroundBack
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprSetPlaygroundBack(HPLAYGROUND hpgPlay,
- HBITMAP hbmNew,
- HBITMAP *phbmOld)
- //-------------------------------------------------------------------------
- // This function sets the background bitmap of the playground.
- //
- // Note that, once this function is called, the bitmap is managed by
- // the sprite subsystem. The bitmap should *NOT* be deleted by the
- // application unless the bitmap is "unset" from the playground (by
- // calling this function again with a different handle).
- //
- // Input: hpgPlay - handle to the playground
- // hbmNew - handle to the new bitmap to used as the background
- // Output: phbmOld - points to the handle to the old background bitmap.
- // This can be NULL, meaning that the application isn't interested
- // in receiving this value.
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (phbmOld!=NULL) {
- *phbmOld=hpgPlay->hbmBack;
- } /* endif */
-
- hpgPlay->hbmBack=hbmNew;
-
- //----------------------------------------------------------------------
- // We're only interested in the cx and cy fields
- //----------------------------------------------------------------------
- hpgPlay->bmihBack.cbFix=16;
- GpiQueryBitmapInfoHeader(hpgPlay->hbmBack,&hpgPlay->bmihBack);
-
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundColor ΓòÉΓòÉΓòÉ
-
- SprSetPlaygroundColor
-
- Note that we do not force a repaint, since I didn't want to deal with passing
- in an HPS on too many functions. It is conceivable that the background color
- can be set immediately after creation of the playground and let it get
- displayed the next time WM_PAINT is processed.
-
- SPRERROR EXPENTRY SprSetPlaygroundColor(HPLAYGROUND hpgPlay,LONG lBackColor)
- //-------------------------------------------------------------------------
- // This function sets the new background color of the playground and is
- // only valid if the playground doesn't have a bitmap.
- //
- // Input: hpgPlay - handle to the playground
- // lBackColor - specifies the new background color
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_HASBACKGROUND;
- } /* endif */
-
- hpgPlay->lBackColor=lBackColor;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetPlaygroundSize ΓòÉΓòÉΓòÉ
-
- SprSetPlaygroundSize
-
- This function is allowed only if there is no background bitmap.
-
- SPRERROR EXPENTRY SprSetPlaygroundSize(HPLAYGROUND hpgPlay,PSIZEL pszlSize)
- //-------------------------------------------------------------------------
- // This function sets the playground size for playgrounds that do not have
- // a bitmap set as the background.
- //
- // Input: hpgPlay - handle to the playground
- // pszlSize - points to the size of the playground
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
-
- if (hpgPlay->hbmBack!=NULLHANDLE) {
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_HASBACKGROUND;
- } /* endif */
-
- hpgPlay->bmihBack.cx=pszlSize->cx;
- hpgPlay->bmihBack.cy=pszlSize->cy;
-
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetSpritePosition ΓòÉΓòÉΓòÉ
-
- SprSetSpritePosition
-
- SPRERROR EXPENTRY SprSetSpritePosition(HPS hpsDraw,
- HSPRITE hsSprite,
- PPOINTL pptlNew)
- //-------------------------------------------------------------------------
- // This function changes the position of the sprite. This function is
- // optimized so that, if the rectangle bounding the sprite at the new
- // position overlaps the old, only one "bit blit" to the specified HPS
- // is done, eliminating flicker.
- //
- // Input: hpsDraw - handle to the HPS to draw the sprite in once it is
- // moved
- // hsSprite - handle to the sprite
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- SIZEL szlPlay;
- SIZEL szlWork;
- RECTL rclOld;
- RECTL rclNew;
- RECTL rclUnion;
- RECTL rclSrc;
- RECTL rclDest;
- POINTL ptlWork;
- POINTL aptlPoints[4];
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- if ((hsSprite->bVisible) && (hsSprite->hpgPlay->bUpdate)) {
- szlWork.cx=MAX_SPRITE_CX*2;
- szlWork.cy=MAX_SPRITE_CY*2;
-
- SprQueryPlaygroundSize(hsSprite->hpgPlay,&szlPlay);
-
- Note how we query the sprite rectangle before and after the position changes
- and then call WinUnionRect() to check for overlap. This determines our course
- of action. If there is no overlap, call drawBackAt() and SprDrawSprite() to
- erase the sprite at its old position and redraw at its new position.
- Otherwise, perform the delta processing (see below).
-
- SprQuerySpriteRect(hsSprite,&rclOld);
- hsSprite->ptlPos=*pptlNew;
- SprQuerySpriteRect(hsSprite,&rclNew);
-
- WinUnionRect(hsSprite->habAnchor,&rclUnion,&rclOld,&rclNew);
-
- if ((rclUnion.xRight-rclUnion.xLeft>MAX_SPRITE_CX*2) ||
- (rclUnion.yTop-rclUnion.yBottom>MAX_SPRITE_CY*2)) {
-
- rclSrc.xLeft=rclOld.xLeft;
- rclSrc.yBottom=rclOld.yBottom;
- rclSrc.xRight=rclSrc.xLeft+hsSprite->bmihBitmap.cx;
- rclSrc.yTop=rclSrc.yBottom+hsSprite->bmihBitmap.cy;
-
- drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSrc);
-
- SprDrawSprite(hpsDraw,hsSprite);
- } else {
-
- rclUnion contains the bounding rectangle of the old and new positions, so first
- transfer this rectangle from the background to the workarea (offset by
- (-rclUnion.xLeft,-rclUnion.yBottom)).
-
- rclSrc=rclUnion;
- rclSrc.xRight++;
- rclSrc.yTop++;
-
- rclDest.xLeft=0;
- rclDest.yBottom=0;
- rclDest.xRight=rclUnion.xRight-rclUnion.xLeft;
- rclDest.yTop=rclUnion.yTop-rclUnion.yBottom;
-
- drawBackAt(hsSprite->hpgPlay->hpsWork,
- hsSprite->hpgPlay,
- &rclDest,
- &szlWork,
- &rclSrc);
-
- Once the background has been drawn, call drawSpriteAt() with a position also
- offset by (-rclUnion.xLeft,-rclUnion.yBottom). This completes our drawing in
- the workarea; now we simply need to remove the offset, clip to the playground,
- and call GpiBitBlt() to transfer the entire rclUnion-sized rectangle from the
- workarea to the screen.
-
- ptlWork.x=hsSprite->ptlPos.x-rclUnion.xLeft;
- ptlWork.y=hsSprite->ptlPos.y-rclUnion.yBottom;
-
- drawSpriteAt(hsSprite->hpgPlay->hpsWork,hsSprite,&szlWork,&ptlWork);
-
- //----------------------------------------------------------------
- // GpiBitBlt is non-inclusive on source AND target
- //----------------------------------------------------------------
- aptlPoints[0].x=rclUnion.xLeft;
- aptlPoints[0].y=rclUnion.yBottom;
- aptlPoints[1].x=rclUnion.xRight+1;
- aptlPoints[1].y=rclUnion.yTop+1;
- aptlPoints[2].x=0;
- aptlPoints[2].y=0;
- aptlPoints[3].x=rclUnion.xRight-rclUnion.xLeft+1;
- aptlPoints[3].y=rclUnion.yTop-rclUnion.yBottom+1;
-
- if (clipBltPoints(hsSprite->habAnchor,aptlPoints,&szlPlay)) {
- GpiBitBlt(hpsDraw,
- hsSprite->hpgPlay->hpsWork,
- 4,
- aptlPoints,
- ROP_SRCCOPY,
- BBO_IGNORE);
- } /* endif */
- } /* endif */
- } else {
- hsSprite->ptlPos=*pptlNew;
- } /* endif */
-
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetSpriteVisibility ΓòÉΓòÉΓòÉ
-
- SprSetSpriteVisibility
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprSetSpriteVisibility(HPS hpsDraw,
- HSPRITE hsSprite,
- BOOL bVisible)
- //-------------------------------------------------------------------------
- // This function shows or hides a sprite.
- //
- // Input: hpsDraw - handle to the HPS to draw in once the sprite is
- // shown or hidden
- // hsSprite - handle to the sprite
- // bVisible - new visibility state
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
- RECTL rclSprite;
-
- if (queryHandleType(hsSprite)!=QH_HSPRITE) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hsSprite,ACCSEM_SET);
-
- if (hsSprite->hpgPlay==NULL) {
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_HASNOPLAYGROUND;
- } /* endif */
-
- if (hsSprite->bVisible!=bVisible) {
- hsSprite->bVisible=bVisible;
-
- if (hsSprite->hpgPlay->bUpdate) {
- if (hsSprite->bVisible) {
- SprDrawSprite(hpsDraw,hsSprite);
- } else {
- rclSprite.xLeft=hsSprite->ptlPos.x;
- rclSprite.yBottom=hsSprite->ptlPos.y;
- rclSprite.xRight=rclSprite.xLeft+hsSprite->bmihMask.cx;
- rclSprite.yTop=rclSprite.yBottom+hsSprite->bmihMask.cy;
-
- drawBackAt(hpsDraw,hsSprite->hpgPlay,NULL,NULL,&rclSprite);
- } /* endif */
- } /* endif */
- } /* endif */
-
- accessSem((PHEADER)hsSprite,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> SprSetUpdateFlag ΓòÉΓòÉΓòÉ
-
- SprSetUpdateFlag
-
- There is nothing special about this function that needs to be noted.
-
- SPRERROR EXPENTRY SprSetUpdateFlag(HPLAYGROUND hpgPlay,BOOL bUpdate)
- //-------------------------------------------------------------------------
- // This function sets the update flag for the playground. If FALSE, no
- // drawing actually takes place in any of the functions requiring an HPS,
- // and the value of the HPS handle may be NULLHANDLE. If TRUE, updating
- // is reenabled, but you should still call SprDrawPlayground() to refresh
- // the screen with the current contents.
- //
- // Input: hpgPlay - handle to the playground
- // bUpdate - specifies the new update flag
- // Returns: SPR_ERR_NOERROR if successful, SPR_ERR_* constant otherwise
- //-------------------------------------------------------------------------
- {
- USHORT usAction;
-
- if (queryHandleType(hpgPlay)!=QH_HPLAYGROUND) {
- return SPR_ERR_BADHANDLE;
- } /* endif */
-
- usAction=accessSem((PHEADER)hpgPlay,ACCSEM_SET);
- hpgPlay->bUpdate=bUpdate;
- accessSem((PHEADER)hpgPlay,usAction);
- return SPR_ERR_NOERROR;
- }
-
- Sprites and Animation (Part 2) - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2. Resources and Decompiling Them ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 2.2.1. Introduction ΓòÉΓòÉΓòÉ
-
- Resources and Decompiling Them
-
- Written by Martin Lafaix
-
- Introduction
-
- What's that?
-
- OS/2 comes with a resource compiler, RC, which allows us to put resources in an
- executable file; but, it would sometimes be useful to do just the opposite,
- namely, extracting resources from an executable (or from a DLL).
-
- Why?
-
- If we were able to extract resources, it would help us adapting this lovely
- little tool, which unfortunately has all its messages and menus in, say,
- Chinese... :-) and which is no longer supported by its author. Or, it would
- allow us to correct those lovely typographical errors in the base OS/2 system,
- too. (At least, the French version includes some boring typos, in menu items
- and shortcuts :-( ) Or, it would even allow us to grab some lovely dialog box
- and include it in our wonderful projects.
-
- Contents
-
- This article contains four parts. The first one describes the general
- executable file structure, the second one describes the 16-bit EXE structure,
- the third describes the 32-bit EXE structure, and the fourth describes the RES
- to RC translation. Sample code will be given in REXX, which will use many
- user-defined functions, such as readw() or readl().
-
- A (short) bibliography can be found at the end of this document.
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.2. A Voyage to OMF ΓòÉΓòÉΓòÉ
-
- A Voyage to OMF
-
- In the following sections, "EXE" will be used as a generic term for .EXE or
- .DLL files.
-
- The Old DOS Header
-
- Each EXE starts with an old DOS header. Two fields interest us, namely e_magic
- and e_lfanew. The first one contains "MZ" and allowed us to recognize the EXE
- header, and the second one contains the offset of the new EXE header, which is
- where the fun begins. The remaining fields are used for a DOS 'stub', that is,
- a program which displays a message like:
-
- This program cannot be run in a DOS session.
-
- This message is displayed whenever the program is run from vanilla DOS.
-
- struct exe_hdr /* DOS 1, 2, 3 .EXE header */
- {
- unsigned short e_magic; /* Magic number */
- unsigned short e_cblp; /* Bytes on last page of file */
- unsigned short e_cp; /* Pages in file */
- unsigned short e_crlc; /* Relocations */
- unsigned short e_cparhdr; /* Size of header in paragraphs */
- unsigned short e_minalloc; /* Minimum extra paragraphs needed */
- unsigned short e_maxalloc; /* Maximum extra paragraphs needed */
- unsigned short e_ss; /* Initial (relative) SS value */
- unsigned short e_sp; /* Initial SP value */
- unsigned short e_csum; /* Checksum */
- unsigned short e_ip; /* Initial IP value */
- unsigned short e_cs; /* Initial (relative) CS value */
- unsigned short e_lfarlc; /* File address of relocation table */
- unsigned short e_ovno; /* Overlay number */
- unsigned short e_res[ERES1WDS];/* Reserved words */
- unsigned short e_oemid; /* OEM identifier (for e_oeminfo) */
- unsigned short e_oeminfo; /* OEM information; e_oemid specific */
- unsigned short e_res2[ERES2WDS];/* Reserved words */
- long e_lfanew; /* File address of new exe header */
- };
-
- Figure 1. The DOS 1, 2, 3 .EXE header.
-
- Recognizing it from REXX
-
- In the following code, infile contains the EXE filename. base will then contain
- the new header offset.
-
- if charin(infile,,2) = 'MZ' then base = 1+l2d(charin(infile,61,4))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.3. Exploring 16-Bit Headers ΓòÉΓòÉΓòÉ
-
- Exploring 16-Bit Headers
-
- Recognizing a 16-bit EXE header
-
- A 16-bit EXE header starts with the 'NE' magic number; a 16-bit EXE structure
- starts with this magic number:
-
- struct new_exe /* New .EXE header */
- {
- unsigned short ne_magic; /* Magic number NE_MAGIC */
- unsigned char ne_ver; /* Version number */
- unsigned char ne_rev; /* Revision number */
- unsigned short ne_enttab; /* Offset of Entry Table */
- unsigned short ne_cbenttab; /* Number of bytes in Entry Table */
- long ne_crc; /* Checksum of whole file */
- unsigned short ne_flags; /* Flag word */
- unsigned short ne_autodata; /* Automatic data segment number */
- unsigned short ne_heap; /* Initial heap allocation */
- unsigned short ne_stack; /* Initial stack allocation */
- long ne_csip; /* Initial CS:IP setting */
- long ne_sssp; /* Initial SS:SP setting */
- unsigned short ne_cseg; /* Count of file segments */
- unsigned short ne_cmod; /* Entries in Module Reference Table */
- unsigned short ne_cbnrestab; /* Size of non-resident name table */
- unsigned short ne_segtab; /* Offset of Segment Table */
- unsigned short ne_rsrctab; /* Offset of Resource Table */
- unsigned short ne_restab; /* Offset of resident name table */
- unsigned short ne_modtab; /* Offset of Module Reference Table */
- unsigned short ne_imptab; /* Offset of Imported Names Table */
- long ne_nrestab; /* Offset of Non-resident Names Table */
- unsigned short ne_cmovent; /* Count of movable entries */
- unsigned short ne_align; /* Segment alignment shift count */
- unsigned short ne_cres; /* Count of resource entries */
- unsigned char ne_exetyp; /* Target operating system */
- unsigned char ne_flagsothers; /* Other .EXE flags */
- char ne_res[NERESBYTES];
- /* Pad structure to 64 bytes */
- };
-
- Figure 2. The OS/2 286 .EXE header.
-
- The following fields interest us:
-
- Field Contents
-
- ne_cseg is the number of segments in the EXE. Segments containing
- resources are at the end of the segment table.
-
- ne_segtab is the offset of the segment table. Each entry in this
- table contains the following:
-
- ssector (WORD) is the segment's beginning sector, from the beginning of
- the EXE. See ne_align below for more explanations on how
- to compute the segment's effective position in EXE.
- cb (WORD) is the segment's size in bytes.
- sflags (WORD) is the segment's flags. Interesting bits are:
-
- NSMOVE 0x0010 Moveable segment flag
- NSSHARED 0x0020 Shared segment flag
- NSPRELOAD 0x0040 Preload segment flag
- NSDISCARD 0x1000 Segment is discardable
- smin (WORD) is the minimum allocation in bytes. This field's value
- is not used with segments containing resources.
-
- Note: The segment table offset is from the beginning of
- the 286 EXE header, not from the beginning of the EXE.
-
- ne_rsrctab is the offset of the resource table. Each entry in this
- table contains two fields:
-
- etype (WORD) is the resource type.
- ename (WORD) is the resource name (well, for OS/2, it's a number).
-
- Note: The resource table offset is from the beginning of
- the 286 EXE header, not from the beginning of the EXE.
-
- ne_align is the segment alignment shift count. It's the number of
- bits we should shift the segment's beginning sector value
- to find the segment's position in EXE.
-
- For example, if ne_align is 4, segments will be aligned on
- 16-byte boundaries (that is, the EXE will be composed of
- 16-byte 'sectors').
-
- ne_cres is the number of resources in the EXE. Each resource uses
- a segment.
-
- More information on the 16-bit EXE header can be found in NEWEXE.H, which comes
- with the Developer's toolkit. Unfortunately, it isn't very informative.
-
- Extracting a Resource From The EXE
-
- The process of extracting resources from an EXE to a RES file is quite simple.
- We walk through the resource table (rsrctab), and, for each entry, we find and
- emit the corresponding segment. (We have to twiddle the segment flag and
- create a small header for the resource, but that's not a big deal.)
-
- o First, we have to find the corresponding resource table entry (resource
- number cnt):
-
- call charin infile,base+rsrctab+cnt*4,0
-
- o Then, we have to read the entry's content:
-
- etype = readw()
- ename = readw()
-
- o Then, we have to find and read the corresponding segment table entry:
-
- call segin cseg-rsrccnt+1+cnt
-
- o Then we...(I'm using a procedure here for readability.)
-
- segin:
- call charin infile,base+segtab+(arg(1)-1)*8,0
- ssector = readw()
- cb = readw()
- sflags = readw()
- smin = readw()
-
- o We then calculate the resource offset:
-
- pos = 1+(2**segshift)*ssector
-
- o And we translate the segment flag (from NSMMOVE, etc. to MOVEABLE, etc.):
-
- flags = 0
- if bit(sflags,10) then flags = flags+64
- if bit(sflags,12) then flags = flags+16
- if bit(sflags,4) then flags = flags+4096
- if \ bit(sflags,11) then flags = flags+32
-
- o We are now ready to write the resource header to a RES file:
-
- call emit 'FF'x||d2w(etype)'FF'x||d2w(ename)d2w(flags)d2l(cb)
-
- o And, last but not least, we have to write the resource data, too:
-
- call emit charin(infile,pos,cb)
-
- Note: The RES format is explained in the section The RES File Format
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.4. Exploring 32-Bit Headers ΓòÉΓòÉΓòÉ
-
- Exploring 32-Bit Headers
-
- Recognizing a 32-bit EXE header
-
- A 32-bit EXE header starts with the 'LX' magic number; a 32-bit structure
- starts with this magic number:
-
- struct e32_exe /* New 32-bit .EXE header */
- {
- unsigned char e32_magic[2]; /* Magic number E32_MAGIC */
- unsigned char e32_border; /* The byte ordering for the .EXE */
- unsigned char e32_worder; /* The word ordering for the .EXE */
- unsigned long e32_level; /* The EXE format level for now = 0 */
- unsigned short e32_cpu; /* The CPU type */
- unsigned short e32_os; /* The OS type */
- unsigned long e32_ver; /* Module version */
- unsigned long e32_mflags; /* Module flags */
- unsigned long e32_mpages; /* Module # pages */
- unsigned long e32_startobj; /* Object # for instruction pointer */
- unsigned long e32_eip; /* Extended instruction pointer */
- unsigned long e32_stackobj; /* Object # for stack pointer */
- unsigned long e32_esp; /* Extended stack pointer */
- unsigned long e32_pagesize; /* .EXE page size */
- unsigned long e32_pageshift; /* Page alignment shift in .EXE */
- unsigned long e32_fixupsize; /* Fixup section size */
- unsigned long e32_fixupsum; /* Fixup section checksum */
- unsigned long e32_ldrsize; /* Loader section size */
- unsigned long e32_ldrsum; /* Loader section checksum */
- unsigned long e32_objtab; /* Object table offset */
- unsigned long e32_objcnt; /* Number of objects in module */
- unsigned long e32_objmap; /* Object page map offset */
- unsigned long e32_itermap; /* Object iterated data map offset */
- unsigned long e32_rsrctab; /* Offset of Resource Table */
- unsigned long e32_rsrccnt; /* Number of resource entries */
- unsigned long e32_restab; /* Offset of resident name table */
- unsigned long e32_enttab; /* Offset of Entry Table */
- unsigned long e32_dirtab; /* Offset of Module Directive Table */
- unsigned long e32_dircnt; /* Number of module directives */
- unsigned long e32_fpagetab; /* Offset of Fixup Page Table */
- unsigned long e32_frectab; /* Offset of Fixup Record Table */
- unsigned long e32_impmod; /* Offset of Import Module Name Table */
- unsigned long e32_impmodcnt; /* Number of entries in Import Module Name Table */
- unsigned long e32_impproc; /* Offset of Import Procedure Name Table
- unsigned long e32_pagesum; /* Offset of Per-Page Checksum Table */
- unsigned long e32_datapage; /* Offset of Enumerated Data Pages */
- unsigned long e32_preload; /* Number of preload pages */
- unsigned long e32_nrestab; /* Offset of Non-resident Names Table */
- unsigned long e32_cbnrestab; /* Size of Non-resident Name Table */
- unsigned long e32_nressum; /* Non-resident Name Table Checksum */
- unsigned long e32_autodata; /* Object # for automatic data object */
- unsigned long e32_debuginfo; /* Offset of the debugging information */
- unsigned long e32_debuglen; /* The length of the debugging info. in bytes */
- unsigned long e32_instpreload;/* Number of instance pages in preload section of .EXE file */
- unsigned long e32_instdemand; /* Number of instance pages in demand load section of .EXE file */
- unsigned long e32_heapsize; /* Size of heap - for 16-bit apps */
- unsigned long e32_stacksize; /* Size of stack */
- unsigned char e32_res3[E32RESBYTES3];
- /* Pad structure to 196 bytes */
- };
-
- Figure 3. The OS/2 386 .EXE header.
-
- The following fields interest us:
-
- Field Contents
-
- e32_pageshift is the page alignment shift in the EXE. It's the number of
- bits we should shift the page offset value to find the
- page's position in EXE.
-
- For example, if e32_pageshift is 4, pages will be aligned
- on 16-byte boundaries.
-
- e32_objtab is the object table offset. Each entry contains the
- following fields:
-
- 32 1 32 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé size Γöé base Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé flags Γöé pagemap Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé mapsize Γöé reserved Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- o size is the object virtual size.
-
- o base is the object base virtual address.
-
- o flags is the object attribute flags.
-
- o pagemap is the object page map index.
-
- o mapsize is the number of entry in the object's page map.
-
- o reserved is, well, reserved :-)
-
- We're only interested by flags and pagemap. That is, flags
- contains the resource flags (MOVEABLE, LOADONCALL, and so
- on), while pagemap allows us to find the object's pages
- within the EXE. (See the "Tables and Maps Relations"
- section below, for more explanations on pagemap, the object
- table, and other tables.)
-
- flags' interesting bits are:
-
- OBJWRITE 0x0002L Writeable Object
- OBJDISCARD 0x0010L Object is Discardable
- OBJSHARED 0x0020L Object is Shared
- OBJPRELOAD 0x0040L Object has preload pages
-
- Note: The object table offset is from the beginning of the
- 386 EXE header, not from the beginning of the EXE.
-
- e32_objmap is the object page map offset. Each entry contains the
- following fields:
-
- 32 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé pagedataoffset Γöé pagesize Γöé pageflags Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- o pagedataoffset is the file offset of page.
-
- o pagesize is the number of bytes of page data.
-
- o pageflags is per-page attributes.
-
- Note: The object page map offset is from the beginning of
- the 386 EXE header, not from the beginning of the EXE.
-
- e32_rsrctab is the offset of the resource table. Each entry contains
- the following fields:
-
- 16 1 16 1 32 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé type Γöé name Γöé cb Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
- Γöé obj Γöé offset Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
- 16 1 32 1
-
- o type is the resource type.
-
- o name is the resource name.
-
- o cb is the resource size, in bytes.
-
- o obj is the number of the object containing the resource.
-
- o offset is the resource's offset within object. Resource will be in object
- obj, starting at the specified offset:
-
- 0 offset offset+cb
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- objΓöé Γöé<- resource ->Γöé ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- Note: The resource table offset is from the beginning of
- the 386 EXE header, not from the beginning of the EXE.
-
- e32_rsrccnt is the number of resources in the EXE.
-
- e32_datapage is the offset of Enumerated data page. It's the position
- of the first data page in the EXE.
-
- Warning: This offset is from the beginning of the EXE, not
- from the beginning of the 386 EXE header. It's THE
- exception :-/
-
- More information on the 32-bit EXE header can be found on exe386.h, which comes
- with the Developer's toolkit. It's not that informative, though, and OMF.INF
- is much better. I highly recommend it.
-
- Tables and Maps Relations
-
- In this section, we will view the various relations between tables and maps.
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- file Γöé Γöé Γöé Γöé Γöé ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- object's page 1Γöé Γöé object's page 2
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé
- Γöé Γöé
- Γöé Γöé
- : Γöé Γöé
- Γöé Γöé Γöé Γöé : Γöé Γöé Γöé Γöé
- r-1Γöé Γöé Γöé Γöé ΓöîΓöÇΓöÇΓöÇΓöÇΓö£ΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ : Γöé Γöé Γöé p Γöé Γöé ΓöÇΓöÿ Γöé
- r Γöé Γöé ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé Γöé Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ Γöé o-1Γöé Γöé Γöé p+1Γöé Γöé ΓöÇΓöÇΓöÇΓöÿ
- r+1Γöé Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓö£ΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Γöé o Γöé Γöé ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ : Γöé Γöé
- : Γöé Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
- Γöé Γöé o+1Γöé Γöé Γöé Γöé
-
- resource object page map
- table table
-
- Figure 4. Tables and maps relations.
-
- To find the data of a resource r, we first have to read the corresponding entry
- in the resource table. The obj field of this entry allows us to find the
- object which contains the data. The pagemap field of the object table entry
- then allows us to locate the object's pages in the EXE, via the page map. To
- find the resource data, we then just have to read cb bytes from object,
- starting at offset.
-
- Extracting a Resource From The EXE
-
- The process of extracting resources from a 32-bit EXE to a RES file is similar
- to the 16-bit EXE to RES conversion. We walk through the resource table
- (rsrctab), and, for each entry, we find and emit the corresponding resource.
- (We have to twiddle the object flag and create a small header for the resource,
- but that's not a big deal.)
-
- Note: In the following code, we'll assume that objects span over consecutive
- pages. That is, we will not handle the case where the object's pages are
- arranged discontinuously in the EXE.
-
- o First, we have to find the corresponding resource table entry (resource
- number cnt):
-
- call charin infile,base+rsrctab+cnt*14,0
-
- o Then, we have to read the entry's content:
-
- etype = readw() /* resource type */
- ename = readw() /* resource name */
- cb = readl() /* resource size */
- eobj = readw() /* object containing resource */
- eoffset = readl() /* resource's offset in eobj */
- call objin eobj
-
- (I'm using a procedure here for readability.)
-
- objin:
- call charin infile,base+objtab+(arg(1)-1)*24,8
- oflags = readl() /* object attributes */
- opagemap = readl() /* object page map index */
- omapsize = readl() /* -- not used -- */
- opagedataoffset = l2d(charin(infile,base+objmap+(opagemap-1)*8,4))
-
- o We then calculate the resource offset:
-
- pos = 1+datapage+eoffset+(2**pageshift)*opagedataoffset
-
- o And we translate the object flag (from OBJPRELOAD, ... to LOADONCALL, ...):
-
- flags = 0
- if bit(oflags,10) then flags = flags+64
- if bit(oflags,11) then flags = flags+16
- if bit(oflags,12) then flags = flags+4096
- if \ bit(oflags,15) then flags = flags+32
-
- o We are now ready to write the resource header to a RES file:
-
- call emit 'FF'x||d2w(etype)'FF'x||d2w(ename)d2w(flags)d2l(cb)
-
- o And, last but not least, we have to write the resource data, too:
-
- call emit charin(infile,pos,cb)
-
- Note: The RES format is explained in the next section (The RES file format).
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.5. The RES to RC Translation ΓòÉΓòÉΓòÉ
-
- The RES to RC Translation
-
- And now the last part. First, we will describe the RES format, and we will
- then describe some resources data. We will focus our interest on the
- human-readable resources, such as menus, stringtables and so on.
-
- Note: An important exception will be the dialog templates, for the following
- two reasons:
-
- o The Dialog editor already does this.
- o It's not that different from the others resources, and it would necessitated
- an even more fastidious enumeration.
-
- For these reasons, our resource decompiler will not extract dialog templates
- from RES to RC.
-
- And we will finally describe briefly the included resource decompiler, rdc.
-
- The RES format
-
- The RES file is an aggregate of resources. Each resource is composed of a
- header, followed by the resource data.
-
- 8 1 16 1 8 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé0xFFΓöé Type Γöé0xFFΓöé Id Γöé Flags Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
- Γöé cb Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
- 32 1
-
- Figure 5. The resource header.
-
- Type is the resource type (see below).
-
- Id is the resource name/identifier.
-
- Flags is the resource attributes (MOVEABLE, LOADONCALL, ...).
-
- cb is the resource size.
-
- The following types may appear:
-
- RT_POINTER 1 /* mouse pointer shape */
- RT_BITMAP 2 /* bitmap */
- RT_MENU 3 /* menu template */
- RT_DIALOG 4 /* dialog template */
- RT_STRING 5 /* string tables */
- RT_FONTDIR 6 /* font directory */
- RT_FONT 7 /* font */
- RT_ACCELTABLE 8 /* accelerator tables */
- RT_RCDATA 9 /* binary data */
- RT_MESSAGE 10 /* error msg tables */
- RT_DLGINCLUDE 11 /* dialog include file name */
- RT_VKEYTBL 12 /* key to vkey tables */
- RT_KEYTBL 13 /* key to UGL tables */
- RT_CHARTBL 14 /* glyph to character tables */
- RT_DISPLAYINFO 15 /* screen display information */
- RT_FKASHORT 16 /* function key area short form */
- RT_FKALONG 17 /* function key area long form */
- RT_HELPTABLE 18 /* Help table for Cary Help manager */
- RT_HELPSUBTABLE 19 /* Help subtable for Cary Help manager */
- RT_FDDIR 20 /* DBCS uniq/font driver directory */
- RT_FD 21 /* DBCS uniq/font driver */
-
- Other values for type denote user-defined resources.
-
- Resource data format
-
- We first have to read the resource header:
-
- res2rc: /* convert .RES format to .RC */
- call skip 1 /* skipping the 'FF'x */
- rt = readw() /* the resource type */
- call skip 1 /* skipping the 'FF'x */
- id = readw() /* the resource ID/name */
- opt = readw() /* the resource flag */
- cb = readl() /* the resource data size */
-
- Then, according to the resource type, we'll have to do specific operations:
-
- select
- when rt = 1 then call emit 'POINTER 'id' 'option()' 'file('ptr')nl
- when rt = 2 then call emit 'BITMAP 'id' 'option()' 'file('bmp')nl
- when rt = 7 then call emit 'FONT 'id' 'option()' 'file('fon')nl
-
- If the resource is a pointer, a bitmap, a font or an icon, the resource data is
- the corresponding pointer, bitmap, font or icon. We then just have to recreate
- a file containing this data.
-
- when rt = 3 then do; call emit 'MENU 'id' 'option()nl'BEGIN'nl; call emit menuout(' ')nl'END'nl; end
-
- If the resource is a menu, it's not that simple :-) The resource data is the
- corresponding menu structure:
-
- 16 1 16 1 16 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Γöé cb Γöé type Γöé cp Γöé offs Γöé countΓöé ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- cb is the size of the menu data.
-
- type is the menu type (Only 0 and 1 are valid).
-
- cp is the menu code page (850 by default).
-
- offs is the starting offset of the menu data, from the start of the structure.
-
- count is the number of item composing the menu.
-
- If the menu type is 1, count is followed by another 16-bit field, ppoffs
- (presentation parameter offset, from the start of the structure). But we won't
- handle type 1 menus, so...
-
- Every item has the following format:
-
- 16 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Γöéstyle ΓöéattribΓöé Id Γöé [Optional Data]
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- style is the item style (MIS_*).
-
- attrib is the item attributes (MIA_*).
-
- Id is the item identifier.
-
- If the item contains data (that is, if item is a submenu, or has the
- MIS_BITMAP, MIS_STRING or ... style), then the previous structure is followed
- by the corresponding data:
-
- MIS_SUBMENU Data is a menu structure, as previously defined.
- MIS_STRING Data is a null-terminated string.
- MIS_BITMAP Data can be any of the following:
-
- 'FF'x, followed by a 16-bit word, representing the resource
- identifier.
- '00'x. No resource identifier provided.
- "#", and subsequent characters make up the decimal representation
- of the resource identifier.
-
- So, if the resource is a menu, we will have to emit each item, recursively (as
- a menu can contain a submenu, ...).
-
- when rt = 5 then call emit 'STRINGTABLE 'option()nl'BEGIN'strout()'END'nl
- when rt = 10 then call emit 'MESSAGETABLE 'option()nl'BEGIN'strout()'END'nl
-
- If the resource is a stringtable or a messagetable, then we have to emit the
- corresponding table. Each string/messagetable contains up to 16 strings. (In a
- RC file, you can have more than one stringtable, with more than 16 strings, but
- rc does not preserve your ordering -- string IDs are maintained, though.)
-
- In the RES file, STRINGTABLE data looks like the following:
-
- 16 1 8 1 1 len+1 8 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Γöé dummyΓöélenΓöéstring1 0ΓöélenΓöéstring2 ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- Each string is zero-terminated. If len is zero, the string does not exists.
-
- when rt = 8 then do; call emit 'ACCELTABLE 'id' 'option()nl'BEGIN'nl||keyout()'END'nl; end
-
- If the resource is an acceltable, then we have to emit the corresponding table.
- ACCELTABLE resource data looks like the following:
-
- 16 1 16 1 16 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- ΓöécountΓöé cp Γöétype1Γöékey1 Γöécmd1 Γöétype2Γöé... ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- count is the number of keys in the acceltable.
-
- cp is the acceltable codepage.
-
- And the type/key/cmd triplets describe the accel-keys :
-
- type is the key's type (VIRTUALKEY, shifted, ...).
-
- key is the key's value (VK_F1, "a", ...).
-
- cmd is the accel command.
-
- when rt = 11 then do; call emit 'DLGINCLUDE 'id' 'charin(infile,,cb)nl; cb = 0; end
-
- If the resource is a dlginclude statement, then the resource data will contain
- the included file name.
-
- Note: This information is of little value if you don't have the included
- file...
-
- when rt = 18 then call emit 'HELPTABLE 'id||nl'BEGIN'htout()'END'nl
-
- If the resource is a helptable, then the resource data will contain the
- following:
-
- 16 1 16 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Γöéwnd 1Γöésub 1Γöé-----Γöéext 1Γöéwnd 2Γöésub 2Γöé-----Γöéext 2Γöé ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- < helpitem 1 > < helpitem 2 >
-
- wnd n is the application window ID.
-
- sub n is the help subtable ID.
-
- ext n is the extended help panel ID.
-
- when rt = 19 then call emit 'HELPSUBTABLE 'id||hstout()nl
-
- If the resource is a HELPSUBTABLE, then the resource data will contain the
- following:
-
- 16 1 16 1 16 1
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- Γöésize Γöéwnd 1Γöéhelp1Γöéwnd 2Γöéhelp2Γöé ...
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
- <subitem 1> <subitem 2>
-
- Each subitem contains size items (the default size value is 2):
-
- wnd n is the child window ID.
-
- help n is the help panel ID.
-
- And, if size is more than 2, the remaining integers have an application-defined
- meaning.
-
- otherwise
- call emit 'RESOURCE 'rt' 'id' 'option()' 'file('dat')
-
- If the resource is of any other type, then we emit the 'RESOURCE' generic
- statement, and we put the resource data in a .DAT file. The rc compiler will
- handle that gracefully. :-)
-
- end /* select */
-
- The Resource decompiler
-
- The interesting part, at last! A resource decompiler (named rdc.cmd) is
- provided in rdc.zip. It's usage is as follow:
-
- Usage: rdc [<options>] <.EXE input file> [<.RC output file>]
- -r - Extract .res file
- -h - Access Help
-
- Figure 6. The resource decompiler usage.
-
- Note: Please note the following:
-
- o It's not highly polished.
- o The RES to RC translation part is known to be buggy.
- o You can't directly obtain a RC file from an EXE. You have to take a two-step
- process (first, rdc -r xxx.exe, and then rdc xxx.res xxx.rc).
- o If files named res_*.* are present in the current directory, you'll get a
- strange result. (And it may trash these files.)
- o The default RC file extension is '.RC2'. It'll protect you from bad
- surprises.
- o And, as stated earlier, it does not extract dialog templates from RES to RC
- files (but it does extract them from EXE to RES).
-
- But, to be optimistic, it works just fine most of the time :-)
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.6. Summary ΓòÉΓòÉΓòÉ
-
- Summary
-
- In the previous parts, we have seen how to extract resources from an executable
- (a .EXE or a .DLL), and how to extract some resources from a .RES file, as we
- have focused our interest on the 'human-readable' resources.
-
- While I realize there are still many obscure points, I hope you will find the
- included information useful. And I'll try my best to answer all questions on
- it.
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.2.7. Bibliography ΓòÉΓòÉΓòÉ
-
- Bibliography
-
- On EXE format
-
- OMF.INF describes the new 32-bit file format. It's a good
- discussion on OMF (Object Module Format) and the 386 EXE
- header. It's available on ftp-os2.cdrom.com.
- EXE.H, EXE386.H and NEWEXE.H These C header files contain the various EXE
- header structures. But it's not really a good place to
- start with.
-
- On RC/RES format
-
- Control Program Guide and Reference This on-line manual describes the
- DosGetResource/DosFreeResource APIs. It's part of the
- Developer's toolkit.
- PM Reference This on-line manual contains much useful information on the
- resource data format (In Related Information/Resource
- File). It's part of the Developer's toolkit.
- Tools Reference This on-line manual contains the Resource Compiler
- reference. It describes all RC statements/directives.
- It's part of the Developer's toolkit.
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> outname ΓòÉΓòÉΓòÉ
-
- outname
-
- This function, which requires two parameters, returns an output filename (if
- one does not already exists).
-
- outname: /* return name made from infile and extension */
- if outfile = '' then
- if lastpos('.',arg(1)) > lastpos('\',arg(1)) then
- outfile = left(arg(1),lastpos('.',arg(1)))arg(2)
- else
- outfile = arg(1)'.'arg(2)
- return outfile
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> readw ΓòÉΓòÉΓòÉ
-
- readw
-
- This function reads one word (two bytes) from current file position. The
- file's position is updated.
-
- readw: /* read one word from infile */
- return w2d(charin(infile,,2))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> readl ΓòÉΓòÉΓòÉ
-
- readl
-
- This function reads one long word (four bytes) from current file position. The
- file's position is updated.
-
- readl: /* read one long from infile */
- return l2d(charin(infile,,4))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> skip ΓòÉΓòÉΓòÉ
-
- skip
-
- This function skips arg(1) chars in current file. The file's position is
- updated.
-
- skip: /* skip arg(1) chars */
- return charin(infile,,arg(1))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> bit ΓòÉΓòÉΓòÉ
-
- bit
-
- This function returns bit arg(2) of arg(1). arg(1) can contain up to 32 bits.
-
- Note: bits are numbered from left to right.
-
- bit: /* return bit arg(2) of arg(1) */
- return substr(x2b(d2x(arg(1),4)), arg(2),1)
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> w2d ΓòÉΓòÉΓòÉ
-
- w2d
-
- This function translates a little-endian word to a REXX integer.
-
- w2d: /* little-endian word to decimal */
- w = c2x(arg(1))
- return x2d(substr(w,3,2)substr(w,1,2))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> d2w ΓòÉΓòÉΓòÉ
-
- d2w
-
- This function translates a REXX integer to a little-endian word.
-
- d2w: /* decimal to little-endian word */
- w = d2x(arg(1),4)
- return x2c(substr(w,3,2)substr(w,1,2))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> l2d ΓòÉΓòÉΓòÉ
-
- l2d
-
- This function translates a little-endian long word to a REXX integer.
-
- l2d: /* little-endian long to decimal */
- l = c2x(arg(1))
- return x2d(substr(l,7,2)substr(l,5,2)substr(l,3,2)substr(l,1,2))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> d2l ΓòÉΓòÉΓòÉ
-
- d2l
-
- This function translates a REXX integer to a little-endian long word.
-
- d2l: /* decimal to little-endian long */
- l = d2x(arg(1),8)
- return x2c(substr(l,7,2)substr(l,5,2)substr(l,3,2)substr(l,1,2))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> emit ΓòÉΓòÉΓòÉ
-
- emit
-
- This function writes arg(1) to output file.
-
- emit: /* write data to output file */
- return charout(outfile,arg(1))
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> option ΓòÉΓòÉΓòÉ
-
- option
-
- This function translates the option's attributes into a RC string.
-
- option: /* convert flags to option string */
- if bit(opt,10) then r = 'PRELOAD'; else r = 'LOADONCALL'
- if bit(opt,12) then r = r' MOVEABLE'
- if bit(opt, 4) then r = r' DISCARDABLE'
- if \ (bit(opt,4) | bit(opt,12)) then r = r' FIXED'
- if r = 'LOADONCALL MOVEABLE DISCARDABLE' then r = ''
- return r
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> file ΓòÉΓòÉΓòÉ
-
- file
-
- This function creates a new file, with extension arg(1), and fill it with cb
- bytes of infile.
-
- file: /* write cb bytes to res_xxx.arg(1) */
- r = 'res_'right(fnum,4,'0')'.'arg(1)
- call charout r,charin(infile,,cb)
- fnum = fnum+1; cb = 0
- call stream r,'c','close'
- return r
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> strout ΓòÉΓòÉΓòÉ
-
- strout
-
- This function extracts a string/messagetable definitions, and returns a string
- containing the table.
-
- strout: /* extract strings definitions */
- call skip 2
- id = (id-1)*16; cb = cb-2; r = nl
- do while cb > 0
- len = x2d(c2x(charin(infile,,1)))
- if len > 1 then r = r' 'left(id,8)'"'charin(infile,,len-1)'"'nl
- call skip 1
- id = id+1; cb = cb-len-1
- end /* do */
- return r
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> keyout ΓòÉΓòÉΓòÉ
-
- keyout
-
- This functions extracts an acceltable definition, and returns a string
- containing the acceltable.
-
- keyout: /* extract acceltable definitions */
- procedure expose nl cb infile outfile
- cnt = readw()
- cp = readw()
- cb = cb-4
- if cp \= 850 then call emit arg(1)'CODEPAGE 'cp||nl
- do cnt
- typ = readw()
- key = readw()
- if \ bit(typ,15) & key >= 32 & key <= 255 then key = '"'d2c(key)'"'; else key = '0x'd2x(key)
- cmd = readw()
- cb = cb-6; t = ''
- if bit(typ,16) then t = t', CHAR'
- if bit(typ,15) then t = t', VIRTUALKEY'
- if bit(typ,14) then t = t', SCANCODE'
- if bit(typ,13) then t = t', SHIFT'
- if bit(typ,12) then t = t', CONTROL'
- if bit(typ,11) then t = t', ALT'
- if bit(typ,10) then t = t', LONEKEY'
- if bit(typ, 8) then t = t', SYSCOMMAND'
- if bit(typ, 7) then t = t', HELP'
- call emit ' 'left(key',',8)left(cmd',',8)substr(t,3)nl
- end /* do */
- return ''
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> htout ΓòÉΓòÉΓòÉ
-
- htout
-
- This function returns a string containing the HELPTABLE definition.
-
- htout: /* extract helptable definitions */
- r = nl
- i = readw()
- do while i \= 0
- r = r' HELPITEM 'i', 'readw()
- call skip 2
- r = r', 'readw()nl; cb = cb-8
- i = readw()
- end /* do */
- cb = cb-2
- return r
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> hstout ΓòÉΓòÉΓòÉ
-
- hstout
-
- This function returns a string containing the HELPSUBTABLE definition.
-
- hstout: /* extract helpsubtable definitions */
- sis = readw()
- if sis \= 2 then r = nl'SUBITEMSIZE 'sis; else r = ''
- r = r||nl'BEGIN'nl; cb = cb-2
- i = readw()
- do while i \= 0
- r = r||' HELPSUBITEM 'i
- do sis-1; r = r', 'readw(); end
- cb = cb-2*sis; r = r||nl
- i = readw();
- end /* do */
- cb = cb-2
- return r'END'
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> itemout ΓòÉΓòÉΓòÉ
-
- itemout
-
- This functions emits the current menu item.
-
- itemout: /* extract menu item definition */
- procedure expose nl cb infile outfile
- cb = cb-6; s = ''; a = ''; r = arg(1)'MENUITEM "'; x = '| MIS_'; y = '| MIA_'
- sty = readw()
- att = readw()
- iid = readw()
- if \ (bit(sty,13) | bit(sty,14)) then
- do
- c = charin(infile); cb = cb-1
- if c = 'FF'x & bit(sty,15) then do; r = r'#'readw(); cb = cb-2; end
- else do while c \= '00'x; r = r||c; c = charin(infile); cb = cb-1; end
- end
- if bit(sty,15) then s = s x'BITMAP'
- if bit(sty,14) then s = s x'SEPARATOR'
- if bit(sty,13) then s = s x'OWNERDRAW'
- if bit(sty,12) then s = s x'SUBMENU'
- if bit(sty,11) then s = s x'MULTMENU'
- if bit(sty,10) then s = s x'SYSCOMMAND'
- if bit(sty, 9) then s = s x'HELP'
- if bit(sty, 8) then s = s x'STATIC'
- if bit(sty, 7) then s = s x'BUTTONSEPARATOR'
- if bit(sty, 6) then s = s x'BREAK'
- if bit(sty, 5) then s = s x'BREAKSEPARATOR'
- if bit(sty, 4) then s = s x'GROUP'
- if bit(sty, 3) then s = s x'SINGLE'
- if bit(att,11) then a = a y'NODISMISS'
- if bit(att, 4) then a = a y'FRAMED'
- if bit(att, 3) then a = a y'CHECKED'
- if bit(att, 2) then a = a y'DISABLED'
- if bit(att, 1) then a = a y'HILITED'
- if a \= '' then a = ','substr(a,3)
- if s \= '' then s = ','substr(s,3); else if a \= '' then s = ','
- call emit r'", 'iid||s||a||nl
- if bit(sty,12) then do; call emit arg(1)'BEGIN'nl; call emit menuout(arg(1)' ','')arg(1)'END'nl; end
- return
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ <hidden> menuout ΓòÉΓòÉΓòÉ
-
- menuout
-
- This functions emit the current menu or submenu.
-
- menuout: /* extract menus definitions */
- procedure expose nl cb infile outfile
- cb = cb-10;
- cbs = readw()
- typ = readw()
- cp = readw()
- off = readw()
- cnt = readw()
- if arg(2) \= '' then
- do
- if cp \= 850 then call emit 'CODEPAGE 'cp||nl
- call emit arg(2)
- end /* do */
- do cnt; call itemout arg(1); end
- return ''
-
- Resources and Decompiling Them - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.3. Visual REXX Faceoff ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 2.3.1. Introduction ΓòÉΓòÉΓòÉ
-
- Visual Rexx Faceoff
-
- Written by Gordon Zeglinski
-
- Introduction
-
- This issue sees the first part of the Visual Rexx Faceoff. We start by looking
- at VX-REXX.
-
- The Watcom VX-REXX package includes two 3.5" HD floppies and a 700+ page
- manual. The manual is nicely written, but the reference section is slightly
- hard to use. (Fortunately, one doesn't have to use it!) The first few
- chapters are instructions on how to do things, the rest of the manual is all
- reference. There are plenty of sample programs included.
-
- Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.3.2. Installation ΓòÉΓòÉΓòÉ
-
- To install VX-REXX, you need about 5-6 megs of free disk space. The install
- program is pretty simple and non-intrusive. It fits in nicely with the OS/2
- environment. There's nothing I hate more than these "ego-maniac" install
- programs that go out of their way to make you sit and watch them install.
- Fortunately, this package doesn't have one of those. After answering a few
- questions, popping in the two disks, and rebooting, we have the following
- folder on our desktop.
-
- Figure 1. Installation Folder
-
- Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.3.3. Look and Feel ΓòÉΓòÉΓòÉ
-
- The interface is neat and easy to use. It consists of the window you are
- designing and a tool palette, as shown in figure 2.
-
- Figure 2. User Interface
-
- VX-REXX uses SOM to implement its "tools". Each of the objects in the Tools
- window (except for the pointer) is a SOM object. Note, just because VX-REXX is
- based in SOM does not mean it's a WPS app, which is not a bad thing. VX-REXX
- does mimic the feel of the WPS. Each object has a pop-up menu that can be used
- to change the various properties of the object you have clicked on. Figure 2
- shows the popup for the main window; other objects have similar menus. Figure
- 3 shows the properties notebook for a static text object.
-
- Figure 3. Properties Notebook
-
- Overall, if you are used to the WPS, you will quickly learn how to configure
- and create objects. We now get to the best part of the interface.
-
- I found the reference section of the manual a bit difficult to use. It's hard
- to find answers to questions like "How do I put text into the damn listbox?!".
- Fortunately, you don't have to look in the manual for this. VX has a code
- insertion ability. To use this ability, you bring up a context menu, select
- "Code Insert", then select the action you want the code to perform. The
- inserted code will usually require some editing. In addition to the popup menu
- method of code insertion, the user can drag a control from the window they are
- designing and drop it on the code window. VX-REXX will then prompt the user
- for the action to perform, after which the code necessary to perform the action
- is inserted.
-
- Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 2.3.4. Wrapping Things Up ΓòÉΓòÉΓòÉ
-
- I have found one annoying thing/bug in VX, but before I comment on it, I will
- wait for a response from Watcom tech support. Next issue, we'll look at VisPro
- REXX (from HockWare) and see how VX-REXX compares to it.
-
- Visual Rexx Faceoff - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3. Columns ΓòÉΓòÉΓòÉ
-
- The following columns can be found in this issue:
-
- o /dev/EDM/BookReview
- o C++ Corner
- o Introduction to PM Programming
- o Scratch Patch
-
- Columns - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.1. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 3.1.1. Introduction ΓòÉΓòÉΓòÉ
-
- /dev/EDM2/BookReview
-
- Written by Carsten Whimster
-
- Introduction
-
- /dev/EDM2/BookReview is a monthly column which focuses on development oriented
- books and materials. The column is from a beginning PM programmer's eyes,
- because that's what I am. Try to pick up whichever book strikes your fancy,
- and join the growing group of people following our introductory PM programming
- columns. I will review books aimed at beginners for a while, and then move on
- from there.
-
- Please send me your comments and thoughts so that I can make this column as
- effective as possible. After all, this is our magazine, and it will be most
- effective with reader feedback.
-
- This book is the last of my current collection, and even though it was written
- for OS/2 1.3, and thus only covers the 16-bit functions, it still manages to
- give decent coverage to concepts which are 16/32 bit insensitive.
-
- /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.1.2. Errata ΓòÉΓòÉΓòÉ
-
- Errata
-
- There are three things on my agenda this month.
-
- First of all, I got mail from a couple of people who disagreed with my rosy
- evaluation of Writing OS/2 2.1 Device Drivers in C, 2nd Edition, Mastrianni. I
- guess I should have made a couple of things a little clearer. If you are to use
- the book, you need Mastrianni's library, unless you write your own DevHlp
- functions, and the library costs around $150 US. Secondly, the reason I feel
- strongly about his book is that Mastrianni has done a lot of work abstracting
- device driver writing away from naked assembler, giving the opportunity to many
- more people to write device drivers than otherwise would have attempted it.
- This is the main accomplishment, I think. In any case, you must judge for
- yourself whether it is worth it. If you do decide to write a device driver,
- you'll most likely need the device driver kit from IBM, but from what I have
- heard, it is in dire need of cleaning up. It is supposedly messy, expensive,
- and incomplete. IBM would really do us all a huge favour by putting out a
- better kit, and in fact, they may be headed in that direction. Supposedly
- Mastrianni has been hired by IBM, and I presume he'll be working on their kit
- development team. If anyone has any factual information on this development,
- I'd love to hear it. One can always hope. In any case, the book will help you
- get off to a faster, surer start than if you were to try it on your own.
-
- Secondly, I have had a report of an inaccuracy in Real World Programming for
- OS/2 2.1, Blain, Delimon, and English. Here is the deal, courtesy of Gordon
- Zeglinski: on page 440, the following occurs:
-
- !DosSubSet(pHeap,DOSSUB_SPARSE_OBJ|DOSSUB_SERIALIZE))
- If we look in the header file however, we find
-
- #define DosSubSet DosSubSetMem
- #define DOSSUBSET DosSubSetMem
- APIRET APIENTRY DosSubSetMem(PVOID pbBase,
- ULONG flag,
- ULONG cb);
-
- So the code fragment does not even have the correct number of arguments. It
- will not compile without a warning in C, and will not compile at all under C++.
- Look at Gordon's C++ Queue Object column for the proper way to use this API.
-
- Finally, from what I have heard, the new Watcom C/C++ 10.0 is imminent, and
- from reviews of the beta, it is something. It will have an IDE, and an
- assembler (yes!), on top of the usual stuff, and of course will include the new
- 2.1 toolkit. If you are about to buy a C/C++ compiler, wait until this comes
- out before you decide which one to spend your hard-earned money on. It looks
- like IBM may finally get a run for their money in the high-end
- compiler-department.
-
- As a foot-note, I am working (with a little help from my friends here at EDM/2)
- on a tabular content format for what each book covers, and what it does not
- cover. Exiting stuff, and this may be just what you have been waiting for to
- be able to decide which book has what you need. Thanks to Gordon (again) for
- the great idea.
-
- /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.1.3. OS/2 Presentation Manager GPI ΓòÉΓòÉΓòÉ
-
- OS/2 Presentation Manager GPI
-
- Sample code fans will like the layout of this book. In some ways, it is quite
- similar to Real World Programming for OS/2 2.1. Each chapter starts out with a
- small motivating section, followed by detail on how to actually apply the
- concepts being presented. The sample code follows at the end of the chapter,
- and consists of complete snippets of code, with some meaningful function,
- although whole programs are not included. This is in keeping with the author's
- stated objective of assisting the intermediate to advanced PM programmer in
- becoming a proficient GPI programmer. With its 318 pages, the book is fairly
- substantial, considering that it only covers one major topic.
-
- Here are the chapter headings:
-
- 1. Introduction: Simple Text and Graphics Output
- 2. Presentation Spaces and Device Contexts
- 3. Drawing Primitives and Attributes
- 4. Fonts
- 5. Bitmaps
- 6. Color Tables
- 7. Coordinate Spaces and Transformation
- 8. Clipping and Regions
- 9. Orders, Elements, and Segments
- 10. Correlation and Boundary Data Accumulation
- 11. MetaFiles
- 12. Printing
- 13. The OS/2 2.0 32-Bit Operating System
- 14. Appendix 1: DevOpenDC Parameters
- 15. Appendix 2: PMPRINT Queue Processor Parameters
- 16. Appendix 3: Introduction to Transforms and Matrices
- 17. Appendix 4: Sample MetaFile Internals
- 18. Appendix 5: Sample Orders
- 19. Appendix 6: GPI Functions Supported only by a Normal-PS
-
- Before using this book, you should already know how to set up a skeleton
- program, with message queue, window procedure, and all the rest of the
- trimmings. This book ONLY talks about the GPI and a few Dev functions.
-
- The first chapter introduces the methodology and intent of the GPI APIs. Brief
- explanations of device contexts, presentation spaces, and so on are presented.
- Personally, I would have liked a section explaining the design choices made in
- the GPI APIs, but that doesn't hurt the coverage of the book. One thing I did
- miss, though, was a little humour. Like so many programming books, humour is
- conspicuous by its absense. I am not calling for a Monty Python-esque
- treatment of the material, just a little light-hearted jesting. This would make
- it more enjoyable, and less dry. Oh well, it's not the first time I have
- missed that, and it won't be the last.
-
- The general feeling of the subsequent chapters is one of a programmer who knows
- his field very well, but has a lot to cover. Each sentence has terse
- information to present, and it never lets up. This is not a book you sit down
- and read in a couple of days! Every sentence has to be thought through after
- reading it! You probably have to try the code from each chapter in your own
- applications before really understanding what's going on.
-
- Chapter two lays the ground-work for all GPI programming. Device contexts and
- presentation spaces are explained again in much greater detail than the first
- time. There are limitations to each choice of PS, and the correct type of DC
- must be used. This seems logical at first sight, but can be complicated when
- your requirements are not clearly delineated. Unfortunately, the diagrams used
- in the book look like something the original word-processors might have
- produced, not very professional. Not good for a book on presentation graphics
- and printing.
-
- The various drawing primitives and attribute groups, characters and text, lines
- and curves, filled areas or patterns, markers, and image and bitblt pixel
- operations are introduced in depth, and their relationship to each other are
- explained. Non-bundle attributes are explained next. Many functions and their
- related possibilities are explained.
-
- Each of chapters four to eleven introduces its own area, and finally in chapter
- twelve, the particular problems of printing are demonstrated. I did feel that
- chapter five on bitmaps was short, given the disproportionate amount of
- interest this particular topic usually has.
-
- There are a lot of gotcha's in GPI programming, and a lot of little rules you
- have to be aware of. Most people will not really use that much of the GPI,
- except to output a text-string here and there, and for these people, this book
- is overkill. It is not intended as a reference book, there are other books for
- that purpose. This book is intended, in the author's own words "...to provide
- answers (illustrated by programming examples) to any questions that Application
- Developers may have concerning the GPI and Dev functions. Rather than providing
- a tutorial description, I have concentrated on making the description of each
- topic as comprehensive as possible." The end result is a book which is similar
- to a reference in coverage, but more like a tutorial in presentation.
-
- My final impression is a good one, even if the book is a little dry. It
- concentrates on presenting OS/2's way of programming with graphics, not on
- teaching the un-initiated about graphics programming. The one major
- short-coming is that it was written for 16-bit OS/2 1.3. I find it strange
- that the book has not been re-written for OS/2 2.x, but perhaps the sales of
- this book were disappointing because of the slowness with which 1.3 caught on.
- Now is a different story, though. With over 5 million copies of OS/2 sold at
- last count, we need an updated version of this book. My final evaluation of
- this book reflects this.
-
- /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.1.4. Summary and Ratings ΓòÉΓòÉΓòÉ
-
- Summary and Ratings
-
- This book ought to be updated. There aren't many books on the market
- specifically about the GPI, and with the current boom going on with OS/2 2.1,
- 2.11, warp/personal OS/2, and so on, it would be perfect timing to have a new
- edition now. The book is terse, well-written and accurate, but needs
- descriptions of the 32-bit functions, the new functions, and how to interface
- the two with 16-bit functions.
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- ΓöéBOOK ΓöéAUDIENCE ΓöéMARKΓöéCOMMENTS Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéReal World Programming for OS/2 2.1,ΓöéIntermediateΓöéB+ ΓöéLots of good code examples, but sometimes it is Γöé
- ΓöéBlain, Delimon, and English, SAMS Γöéto Advanced Γöé Γöétoo complex for novices. Accurate. Well Γöé
- ΓöéPublishing. ISBN 0-672-30300-0. ΓöéPM C Γöé Γöéorganized. The index needs a little beefing up. Γöé
- ΓöéUS$40, CAN$50. Γöéprogrammers Γöé ΓöéGood, but not entirely complete how-to reference.Γöé
- Γöé Γöé Γöé ΓöéGood purchase. Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéLearning to Program OS/2 2.0 ΓöéBeginning PMΓöéB- ΓöéThis book can be both frustrating and very Γöé
- ΓöéPresentation Manager by Example, ΓöéC Γöé Γöérewarding. It is not very large, and a bit Γöé
- ΓöéKnight, Van Nostrand Reinhold. ISBN ΓöéProgrammers Γöé Γöépricey, but has some excellent chapters on Γöé
- Γöé0-442-01292-6. US$40, CAN$50. Γöé Γöé Γöébeginning topics, such as messages, resources, Γöé
- Γöé Γöé Γöé ΓöéIPF, and dialog boxes. Strictly for beginners. Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéWriting OS/2 2.1 Device Drivers in ΓöéAdvanced C ΓöéA- ΓöéThe only thing a device driver programmer would Γöé
- ΓöéC, 2nd Edition, Mastrianni, Van ΓöéProgrammers,Γöé Γöénot find in here is how to write SCSI, ADD, and Γöé
- ΓöéNostrand Reinhold. ISBN Γöéfamiliar Γöé ΓöéIFS drivers. Most everything else is in here, Γöé
- Γöé0-442-01729-4. US$35, CAN$45. Γöéwith Γöé Γöéalong with skeleton examples. An optional DevHlpΓöé
- Γöé Γöéhardware Γöé Γöélibrary of C-callable functions can be purchased Γöé
- Γöé Γöéprogramming Γöé Γöéby those who don't have time to write their own. Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéOS/2 Presentation Manager GPI, Winn,ΓöéIntermediateΓöéC+ ΓöéThis book needs updating for OS/2 2.x. It is a Γöé
- ΓöéVan Nostrand Reinhold. ISBN Γöéto advanced Γöé Γöéwell-written in-depth coverage of the OS/2 way ofΓöé
- Γöé0-442-00739-6. US$35, CAN$45. ΓöéPM C Γöé Γöéprogramming for graphics. It is not an Γöé
- Γöé Γöéprogrammers Γöé Γöéintroductory PM or graphics programming book. Γöé
- Γöé Γöé Γöé ΓöéYou should know how to create windows etc. Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- This table contains all books I have reviewed, so that you can find what you
- are looking for at a glance. I will be careful to rate books fairly relative
- to each other. If I feel a need to adjust ratings, I will adjust all of them
- at the same time, and write a note explaining why I felt this necessary.
- Please note that books aimed at different audiences should only be compared
- with great care, if at all. I intend to concentrate on the strong points of
- the books I review, but I will point out any weaknesses in a constructive
- manner. Read the reviews carefully.
-
- BOOK: The name of the book, author(s), publishing company, ISBN, and
- approximate price.
-
- AUDIENCE: This is a description of the audience I think the book targets best.
- This is not intended as gospel, just a guideline for people not familiar with
- the book.
-
- MARK: My opinion of the success of the book's presentation, and how well it
- targets its audience. Technical content, accuracy, organization, readability,
- and quality of index all weigh heavily here, but the single most important item
- is how well the book covers what it says it covers. I don't expect to see any
- book score less than C, but the scale is there if necessary.
-
- ΓöîΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- ΓöéA+ ΓöéGround-breaking, all-around outstanding book Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéA ΓöéExcellent book. This is what I want to see happen a lot Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéA- ΓöéExcellent book with minor flaws Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéB+ ΓöéVery good book with minor flaws or omissions Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéB ΓöéGood book with some flaws and omissions Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéB- ΓöéGood book, but in need of improvement Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéC+ ΓöéMediocre book with some potential, but in need of some updating Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéC ΓöéMediocre book with some good sections, but badly in need of fixing Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéC- ΓöéMediocre book, little good material, desperately in need of an overhaul Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéD ΓöéDon't buy this book unless you need it, and nothing else exists Γöé
- Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- ΓöéF ΓöéDon't buy this book. Period Γöé
- ΓööΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- COMMENTS: This is a summary of the review proper, although in a very brief
- format.
-
- /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.1.5. Coming Up ΓòÉΓòÉΓòÉ
-
- Coming Up
-
- Next month I will be looking at The Art of OS/2 C Programming, Panov, Salomon
- and Panov, if it gets here in time (sounds very familiar :). Otherwise I will
- review some REXX book. The books I intend to review are (not necessarily in
- this order):
-
- o The Art of OS/2 C Programming, Panov, Salomon and Panov
- o OS/2 Presentation Manager Programming, Petzold - 1994 - not yet published :(
- o The Design of OS/2, 2nd Edititon, Kogan and Deitel - 1994 - not published
- yet? I will review the old version if someone sends me one, but if I have to
- buy it I will wait for the new edition.
-
- This list is not set in stone, but they are books I am interested in. I am
- considering reviewing the IBM OS/2 Redbooks, since they are readily and cheaply
- available, and look like good introductory reference. I am also considering
- reviewing OS/2 Unleashed, but it is not strictly speaking a development book,
- so I'm going to wait until the list of real development books has diminished a
- bit. By the way, does anyone know why the special edition of OS/2 Unleashed
- has completely different authors? And what is different about the Special
- Edition? Finally, I am considering reviewing Designing OS/2 Applications,
- Reich, mostly because it promises to present a different angle on OS/2
- programming, namely that of how to design OS/2 applications, rather than how
- to program OS/2 applications.
-
- If anyone has a book they want to see reviewed, I will be happy to oblige as
- long as I can afford it. Of course, requests can be satisfied quicker when
- accompanied by a book. :) Publishers can send me books at the address on my
- personal page at the end of the magazine, and I will review all OS/2
- development-related books I receive.
-
- /dev/EDM/BookReview - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.2. C++ Corner ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 3.2.1. Introduction ΓòÉΓòÉΓòÉ
-
- C++ Corner
-
- Written by Gordon Zeglinski
-
- Introduction
-
- This issue's C++ column is in response to a reader's email. Things are
- extremely hectic, so sometimes email doesn't get answered as promptly as I
- would like it to be. Keep the mail coming, but please be patient; I'll answer
- it as soon as I can.
-
- In this issue, we will look at multi-threading using the IThread class. The
- IThread class is part of the ICLUI shipped with C-Set++ 2.0 and 2.1; however,
- we will be building upon the drag and drop example of last issue, which
- requires C-Set++ 2.1.
-
- C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.2.2. The IThread Class ΓòÉΓòÉΓòÉ
-
- The IThread Class
-
- The IThread class is used to manipulate threads in the ICLUI. An instance of
- IThread and the thread it represents are not bound together. If the thread
- terminates, the instance is not destroyed. If the instance is destroyed, the
- thread continues executing.
-
- Starting a Thread with IThread
-
- There are two methods that can be used to start a thread. The first, is to use
- the one of the constructors that take a function address or a reference to an
- instance of IThreadFn as an argument. The second is to use the "start member"
- function. We will look at both methods here.
-
- The following code snippet illustrates both methods of starting a thread. In
- this example, we use a member function of the class foo as the threads starting
- function.
-
- class foo{
-
- public:
- foo();
-
- void fooThread();
-
- };
-
- void main(){
- //Create an instance of the foo class
- foo fooInst;
-
- // create the member thread dispatch object
- IThreadMemberFn<foo> ThreadFnc(fooInst,&foo::fooThread);
-
- // create a reference to the member thread dispatch object
- IReference<IThreadFn> ThreadFncRef(&ThreadFnc);
-
- // create a thread object and start the thread
- IThread ImmediateDispatch(ThreadFncRef);
-
- // create a thread object
- IThread DelayedDispatch;
-
- /*
- Do some work here
- */
-
- DelayedDispatch.start(ThreadFncRef);
- }
-
- The class IThreadMemberFn<class T> holds both an instance of a class and a
- pointer to a member function of that class. These two pieces of information
- are need to start the thread using the correct member function and instance.
- Note, that since IThreadMemberFn is a template class, it can be used with any
- class.
-
- In this example, we only looked at starting threads on member functions. The
- method of starting threads on non-member functions is almost identical to the
- one outlined above. Thus, it is left up to the reader to explore this further.
-
- C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.2.3. Building a Simple Test Application ΓòÉΓòÉΓòÉ
-
- Building a Simple Test Application
-
- This section should look familiar to those who have read the last issue. We
- will take our application from last issue, and move the file loading routine
- into a separate thread. In this section, we will look at only the
- modifications made to last issues code that are needed to accomplish our goal
- here.
-
- The class definition for MyFrame has been expanded to allow multi-threaded
- loading of files into the MLE.
-
- class MyFrame:public IFrameWindow{
-
- public:
- MyFrame(const char *Title);
- void StartLoadThread(); //Added to start thread
-
- void SetFileName(IString &S){FileName=S;} //Added to set the filename
-
- protected:
- void LoadFile(); //Added: load thread start point
-
-
- // New members to support multi-threaded loading
- IReference<IThreadFn> ThreadFncRef;
- IThreadMemberFn<MyFrame> *ExecuteThreadFnc;
- IThread ExecuteThread;
-
- IString FileName;
-
- IMultiLineEdit EditWin;
- AFileProvider FileProvider;
- };
-
- Added to the version of MyFrame shown above, are several several new member
- functions that handle the multi-threaded file loading. The constructor is
- modified as follows to initialize the new data members.
-
- MyFrame::MyFrame(const char *Title):
- IFrameWindow(Title,IResourceId(1), //-------------------
- IFrameWindow::titleBar| //
- IFrameWindow::sizingBorder| //
- IFrameWindow::minimizeButton| // Create the Frame
- IFrameWindow::systemMenu| // Window
- IFrameWindow::shellPosition| //
- IFrameWindow::minimizeButton| //
- IFrameWindow::windowList| //
- IFrameWindow::maximizeButton), //--------------------
- EditWin(10,this,this){ // Create the Edit Window
- // ID=10, use this frame
- // window as the parent and
- //owner
- //---------------------
-
- setIcon(IResourceId(1));
- setClient(&EditWin);
-
- //enable default drag and drop handler
- IDMHandler::enableDragDropFor(&EditWin);
- //attach the provider
- EditWin.setItemProvider(&FileProvider);
-
- //Create the thread support members.
- ExecuteThreadFnc=new IThreadMemberFn<MyFrame>(*this,
- &MyFrame::LoadFile);
-
- ThreadFncRef=IReference<IThreadFn>(ExecuteThreadFnc);
-
- show();
- }
-
- The targetDrop routine is modified so that it uses the member functions we
- added to MyFrame to set the file name and start the thread which will read in
- the file. In the following code, we use the fact that the parent of the MLE is
- an instance of MyFrame to get the instance of the MyFrame window and call the
- thread creation function.
-
- Boolean AFileItem::targetDrop( IDMTargetDropEvent &Event){
- IMultiLineEdit *DropWin=(IMultiLineEdit *)this->targetOperation()->targetWindow();
-
- IString
- fname = this->containerName() + this->sourceName();
-
- MyFrame *FrameWin=(MyFrame*) DropWin->parent();
-
- FrameWin->SetFileName(fname);
- FrameWin->StartLoadThread();
-
- return true;
- }
-
- Now that we've seen how the old code was modified, we look at the two new
- member functions of MyFrame. These functions don't do anything that we haven't
- already seen.
-
- void MyFrame::StartLoadThread(){
- ExecuteThread.start(ThreadFncRef);
- }
-
- void MyFrame::LoadFile(){
- //erase the edit window
- EditWin.removeAll();
-
- //load the file into the edit window
- EditWin.importFromFile(FileName);
- }
-
- The source code to this issue is packaged the same way as the source code in
- the previous issue.
-
- C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.2.4. Summary ΓòÉΓòÉΓòÉ
-
- Summary
-
- In this issue, we have seen how to use IThread and its supporting classes to
- create a multi-threaded PM application by building upon our drag and drop
- example from last issue.
-
- C++ Corner - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.3. Introduction to PM Programming ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 3.3.1. Introduction ΓòÉΓòÉΓòÉ
-
- Introduction to PM Programming
-
- Written by Larry Salomon, Jr.
-
- Introduction
-
- The purpose of this column is to provide the readers out there who are not
- familiar with PM application development the information necessary to satisfy
- their curiousity, educate themselves, and give them an advantage over the
- documentation supplied by IBM. Of course, much of this stuff could probably be
- found in one of the many books out there, but the problem with books in general
- is that they don't answer the questions you have after you read the book the
- first time through.
-
- I will gladly entertain feedback from the readers about what was "glossed over"
- or what was detailed well, what tangential topics need to be covered and what
- superfluous crap should have been removed. This feedback is essential in
- guaranteeing that you get what you pay for. :)
-
- It should be said that you must not depend solely on this column to teach you
- how to develop PM applications; instead, this should be viewed as a supplement
- to your other information storehouses (books, the network conferences, etc.).
- Because this column must take a general approach, there will be some topics
- that you would like to see discussed that really do not belong here. Specific
- questions can be directed to the Scratch Patch, where an attempt to answer them
- will be made.
-
- Last Month
-
- Last month, we explored more of the PM APIs and began looking into the
- WC_ENTRYFIELD window class. This month, we will continue where we left off,
- and will continue in directions unknown; unknown, that is, unless you continue
- reading.
-
- Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.3.2. More Messages ΓòÉΓòÉΓòÉ
-
- More Messages
-
- Let us first begin by looking at the remaining entryfield messages.
-
- EM_CLEAR
-
- This message is sent to delete the selected text in the entryfield.
-
- Parameters
-
- param1
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_COPY
-
- This message is sent to copy the selected text to the clipboard.
-
- Parameters
-
- param1
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_CUT
-
- This message is sent to copy the selected text to the clipboard and then delete
- it. This is equivalent to sending an EM_COPY message followed by an EM_CLEAR
- message.
-
- Parameters
-
- param1
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_PASTE
-
- This message is sent to paste text from the clipboard into the entryfield. If
- there is selected text, it is replaced with the pasted contents; otherwise, the
- text is inserted at the current cursor position.
-
- Parameters
-
- param1
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_SETFIRSTCHAR
-
- This message is sent to set the zero-based index of the first character visible
- in the entryfield.
-
- Parameters
-
- param1
-
- sFirstChar (SHORT)
-
- 0-based index of the first visible character
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_SETINSERTMODE
-
- This message is sent to set the insert mode of the entryfield.
-
- Parameters
-
- param1
-
- bInsert (BOOL)
-
- TRUE insert mode
- FALSE overwrite mode
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bOldState (BOOL)
-
- TRUE the entryfield was previously in insert mode
- FALSE the entryfield was previously in overwrite mode
-
- EM_SETREADONLY
-
- This message is sent to set the read-only state of the entryfield.
-
- Parameters
-
- param1
-
- bReadOnly (BOOL)
-
- TRUE the entryfield should be read-only
- FALSE the entryfield should be editable
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bOldState (BOOL)
-
- TRUE the entryfield was previously read-only
- FALSE the entryfield was previously editable
-
- EM_SETSEL
-
- This message is sent to set the current selection of the entryfield.
-
- Parameters
-
- param1
-
- sMinSel (SHORT)
-
- The first 0-based point of selection
-
- sMaxSel (SHORT)
-
- The last 0-based point of selection
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- EM_SETTEXTLIMIT
-
- This message is sent to set the maximum number of characters the entryfield can
- contain.
-
- Parameters
-
- param1
-
- usLimit (USHORT)
-
- maximum number of characters allowed
-
- param2
-
- ulReserved (ULONG)
-
- Reserved, 0.
-
- Returns
-
- reply
-
- bSuccess (BOOL)
-
- TRUE successful completion
- FALSE an error occurred.
-
- Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.3.3. Conceptually Speaking ΓòÉΓòÉΓòÉ
-
- Conceptually Speaking
-
- Of Selections, Anchor Points, and Cursor Points
-
- What is a selection? A selection is an area that is defined by the user. Any
- "objects" (defined by the context of the selection) that are contained within
- the selected area are defined to be selected. Any selection consists of two
- things: an anchor point, which is defined to be the point where the selection
- was started and is fixed, and a cursor point, which is defined to the be place
- where the cursor/pointer currently is and moves with the cursor/pointer. A
- selection is performed, according to CUA guidelines, using either the mouse or
- the keyboard. Using the mouse requires the user to press one of the buttons
- (usually the first) and hold the button while moving the mouse. When the
- selection has been made, the button is released. Using the keyboard, the user
- presses the Shift key while moving the cursor with the arrow keys. When the
- Shift key is released, the selection is completed.
-
- There are other semantics associated with selections when using the mouse, but
- we will not discuss them here. The point of these definitions is to allow you
- to understand the purpose of the EM_SETSEL message. Its two parameters are
- slightly different that what was discussed above; if the anchor point is always
- before the cursor point ("before" is used, since the entryfield can be
- considered as being a one-dimensional stream of characters), then sMinSel is
- the anchor point and sMaxSel is the cursor point, otherwise the two are
- reversed.
-
- Clipboard
-
- For those of you who have no GUI experience, the clipboard is a temporary
- storage place for placing items to be used later in the same or other
- applications. Items of predefined, or application-defined formats, may be
- placed on the clipboard.
-
- Its capabilities and interfaces are beyond the scope of this discussion, but it
- is important that you know what it is.
-
- Text Limits
-
- When you create an entryfield, by default it allows up to 32 characters maximum
- to be entered. If, however, you need more (or less) than this amount, you must
- first send it an EM_SETTEXTLIMIT message, which tells the entryfield to
- allocate more or less memory for its use.
-
- Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.3.4. Notifications ΓòÉΓòÉΓòÉ
-
- Notifications
-
- The entryfield also sends notifications to its owner. These notifications are
- listed below.
-
- o EN_CHANGE - this is sent whenever the entryfield's contents have changed.
-
- o EN_KILLFOCUS - this is sent whenever the entryfield is losing the input
- focus.
-
- o EN_MEMERROR - this is sent whenever the entryfield cannot allocate memory in
- response to an EM_SETTEXTLIMIT message.
-
- o EN_OVERFLOW - this is sent whenever an attempt to insert or paste more text
- than is allowed by the text limit is made.
-
- o EN_SCROLL - this is sent whenever the entryfield has scrolled from a call to
- WinScrollWindow(), the cursor moving beyond the visible area, or when the
- text has changed.
-
- o EN_SETFOCUS - this is sent whenever the entryfield is gaining the input
- focus.
-
- The notifications you will use the most often are the EN_CHANGE, EN_SETFOCUS,
- and EN_KILLFOCUS ones, although the others have their uses.
-
- Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.3.5. Summary ΓòÉΓòÉΓòÉ
-
- Summary
-
- This month, we finished looking at the entryfield messages, the notifications
- sent by the entryfield, and the concepts associated with the new messages.
- Next month, we will begin looking at the WC_LISTBOX class, and will continue
- with nameDlgProc().
-
- Introduction to PM Programming - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4. Scratch Patch ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 3.4.1. Introduction ΓòÉΓòÉΓòÉ
-
- Scratch Patch
-
- Written by Larry Salomon, Jr.
-
- Introduction
-
- Welcome to this month's "Scratch Patch"! Each month, I collect various items
- that fit into this column sent to me via email. The ones that I feel contribute
- the most to developers, whether in terms of information or as a nifty trick to
- tuck into your cap, get published in this column.
-
- To submit an item, send it via email to my address - os2man@panix.com - and be
- sure to grant permission to publish it (those that forget will not be
- considered for publication).
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4.2. Corrections ΓòÉΓòÉΓòÉ
-
- Corrections
-
- If you remember, last month I stated that APAR number PJ13781 was created
- against the Palette Manager; well, it has been closed. The reason is, if
- you'll look in the source code (ugpm.zip), you'll see that a call to WinGetPS()
- is made without 1) creating a message queue first and 2) without releasing it
- later. This is causing the instabilities that were reported.
-
- My apologies for not figuring this out before, but I never looked at the
- source.
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4.3. Gotcha Notes! ΓòÉΓòÉΓòÉ
-
- Gotcha Notes!
-
- When using the IBM User Interface Class Libraries, if you use the new operator
- to create an instance of your main window in the main() function, you must use
- the delete operator after the IApplication::current().run() call or else the
- application will not close after the main window has been destroyed.
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4.4. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
-
- Snippet(s) of the Month
-
- "When it rains, it pours."
-
- Eberhard Mattes (mattes@azu.informatik.uni-stuttgart.de) submitted the
- following item:
-
- This is the template for a dialog box that contains a system icon. Note that
- DLGEDIT doesn't know how to handle SS_SYSICON.
-
- DLGTEMPLATE 3141
- BEGIN
- DIALOG "A System Icon", 3141, 20, 20, 200, 64, , FCF_TITLEBAR | FCF_SYSMENU
- BEGIN
- CONTROL SPTR_ICONQUESTION, 0, 90, 28, 0, 0, WC_STATIC, WS_VISIBLE | SS_SYSICON
- DEFPUSHBUTTON "OK", 1, 8, 8, 32, 16
- END
- END
-
- ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- Jeff Garzik (jgarzik@pantera.atl.ga.us) submitted the following item:
-
- /*
- * DosStartSession() sample code for a DOS session
- * by Jeff Garzik (jgarzik@pantera.atl.ga.us)
- *
- * It has been tested under BC++ 1.0 and emx+gcc 0.8h.
- */
-
- #define INCL_DOS /* we're lazy */
- #include <os2.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <conio.h>
-
- int main (int argc, char *argv[])
- {
- STARTDATA sd; /* DosStartSession parm structure */
- PID pid = 0, pid2 = 0; /* unused but necessary */
- ULONG SessID; /* "" */
- RESULTCODES rcResults; /* "" */
- APIRET rc; /* OS/2 API return code */
-
- /* the program we want to run */
- char s[128] = "c:\\os2\\mdos\\qbasic.exe",
-
- /* the parms of the program to be exec'd */
- s1[128] = "/EDITOR c:\\autoexec.bat",
-
- /* MS-DOS settings of program */
- DosSettings[200] = "DOS_BACKGROUND_EXECUTION=0\0"
- "DPMI_MEMORY_LIMIT=0\0"
- "EMS_MEMORY_LIMIT=0\0"
- "HW_TIMER=1\0"
- "IDLE_SECONDS=10\0"
- "IDLE_SENSITIVITY=20\0"
- "XMS_MEMORY_LIMIT=0\0"
- "\0";
-
- /* fill in data for DosStartSession() */
- memset((void *)&sd, 0, sizeof(sd));
- sd.Length = sizeof(STARTDATA);
- sd.Related = SSF_RELATED_CHILD;
- sd.FgBg = SSF_FGBG_FORE;
- sd.TraceOpt = SSF_TRACEOPT_NONE;
- sd.PgmTitle = "My First DOS Sub-Process"; /* not really necessary */
- sd.PgmName = s;
- sd.PgmInputs = s1;
- sd.TermQ = NULL;
-
- /*
- * The two following settings are somewhat different for
- * DOS sessions. You CANNOT set the environment of a
- * DOS session. The Environment field in STARTDATA is
- * instead used for the DOS settings. InheritOpt is really
- * irrelevant because DOS sessions get their environment
- * from the settings in DOS_AUTOEXEC (defaults to C:\AUTOEXEC.BAT)
- * exclusively
- */
- sd.Environment = DosSettings; /* or 0 for no settings */
- sd.InheritOpt = SSF_INHERTOPT_SHELL;
-
- /* set to SFF_TYPE_WINDOWEDVDM for windowed session */
- sd.SessionType = SSF_TYPE_VDM;
- sd.IconFile = 0;
- sd.PgmHandle = 0;
- sd.PgmControl = 0;
- sd.InitXPos = 0; /* unused for fullscreen session */
- sd.InitYPos = 0; /* unused for fullscreen session */
- sd.InitXSize = 0; /* unused for fullscreen session */
- sd.InitYSize = 0; /* unused for fullscreen session */
- sd.Reserved = 0;
- sd.ObjectBuffer = NULL;
- sd.ObjectBuffLen = 0;
-
- if ((rc = DosStartSession(&sd, &SessID, &pid)) != 0)
- printf("\nDosStartSession error %ld\n\n", rc);
- else
- printf("Successfully executed DOS Editor on AUTOEXEC.BAT.\n");
- DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &rcResults, &pid2, pid);
-
- printf("\nPress any key to continue...");
- getch();
- putchar('\n');
-
- return 0;
- }
-
- ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- Someone sent me the following in a uuencoded format, and I forgot to save their
- name and email address! Sounds familiar? :)
-
- #define INCL_DOS
- #define INCL_DOSDEVIOCTL
- #define INCL_ERRORS
- #include <os2.h>
- #include <stdio.h>
-
- /*+-------------------------------------------------------------------+
- |Function QueryCommPorts |
- | |
- |Purpose : |
- | Determine nr. of commports available on the PC. |
- | Try to figure out which port is used by the mouse. |
- |Inputparameters : |
- | *cCommPorts : pointer to a byte to place the number of available|
- | comm ports |
- | bVerbose : bool that indicates whether or not a status report|
- | must be displayed |
- |Outputparameters : |
- | cMousePort : byte that contains the nr of the comm port used by |
- | the mouse |
- +-------------------------------------------------------------------+*/
-
- BYTE QueryNrCommPorts( BYTE *cCommPorts, BOOL bVerbose )
- {
- BYTE cMousePort = -1;
- BOOL bMouse = FALSE;
-
- HFILE hfMouse;
- ULONG ulAction;
-
- APIRET rc;
-
- struct
- {
- USHORT DeviceID;
- USHORT CommPort;
- USHORT SecDeviceID;
- } DataWords;
- ULONG ulDataLength = sizeof( DataWords );
-
- CHAR szDeviceID[6][30] = { "Unknown",
- "Bus mouse",
- "Serial Mouse",
- "Inport mouse",
- "PS/2*-style pointing device",
- "IBM* 8516 Touch Display"
- };
-
- /*+----------------------------------------------+
- | Determine the number of comm ports on the PC |
- +----------------------------------------------+*/
-
- DosDevConfig( cCommPorts, DEVINFO_RS232 );
-
- /*+---------------------------------------------+
- | Determine nr of comm port used by the mouse |
- +---------------------------------------------+*/
-
- if ( DosOpen( "MOUSE$",
- &hfMouse,
- &ulAction,
- 0,
- FILE_SYSTEM,
- OPEN_ACTION_OPEN_IF_EXISTS,
- OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
- 0 ) == NO_ERROR )
- {
- rc = DosDevIOCtl( hfMouse,
- IOCTL_POINTINGDEVICE,
- 0x6B, /* Query Pointing Device ID */
- NULL,
- 0L,
- NULL,
- (PVOID) &DataWords,
- ulDataLength,
- &ulDataLength );
- if ( rc != NO_ERROR )
- {
- printf( "\nError while querying mouse info.\n" );
- goto end;
- }
- else
- {
- bMouse = TRUE;
- cMousePort = DataWords.CommPort;
- }
- }
-
- /*+-------------------+
- |Print status report|
- +-------------------+*/
-
- if ( bVerbose )
- {
- printf( "\nSTATUS REPORT COMM PORTS\n\n" );
- printf( "Comm ports available : %d\n", *cCommPorts );
- if ( bMouse )
- {
- printf( "Mouse detected.\n" );
- printf( "\tType : %s\n", szDeviceID[ DataWords.DeviceID ] );
- printf( "\tComm port : %d\n", DataWords.CommPort );
- }
- }
-
- end:
- return ( cMousePort );
- }
-
- ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- Finally, I came up with the following function.
-
- typedef VOID (* _Optlink PFNDRVENUM)(CHAR,PVOID);
-
- VOID enumDrives(PFNDRVENUM pfnEnumFn,PVOID pvData)
- //--------------------------------------------------
- // This function enumerates all of the drives at the
- // time the function is called, and for each local
- // drive calls the callback specified.
- //
- // Input: pfnEnumFn - callback function
- // pvData - pointer to user-defined data to
- // pass to callback
- //
- // Callback has the following form:
- //
- // BOOL _Optlink callBack(CHAR chDrive,PVOID pvData)
- //
- // Input: chDrive - uppercase drive letter
- // pvData - as was passed to enumDrives()
- //--------------------------------------------------
- {
- BYTE abBuffer[1024];
- ULONG ulCurrent;
- ULONG ulDriveMap;
- CHAR chDrive;
- CHAR achDrive[3];
- PFSQBUFFER2 pfsqbBuffer;
- ULONG ulSzBuf;
- APIRET arReturn;
-
- //-----------------------------------------------
- // Disable errors so that we don't get any "device
- // is locked" popups.
- //-----------------------------------------------
- DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
-
- DosQueryCurrentDisk(&ulCurrent,&ulDriveMap);
-
- ulDriveMap>>=2;
- chDrive='C';
- memset(achDrive,0,sizeof(achDrive));
- achDrive[1]=':';
- pfsqbBuffer=(PFSQBUFFER2)abBuffer;
-
- while (chDrive<='Z') {
- if ((ulDriveMap % 2)==1) {
- achDrive[0]=chDrive;
-
- ulSzBuf=sizeof(abBuffer);
- memset(pfsqbBuffer,0,ulSzBuf);
-
- arReturn=DosQueryFSAttach(achDrive,
- 0,
- FSAIL_QUERYNAME,
- pfsqbBuffer,
- &ulSzBuf);
- if (arReturn==0) {
- switch (pfsqbBuffer->iType) {
- case FSAT_LOCALDRV:
- (*pfnEnumFn)(chDrive,pvData);
- break;
- default:
- break;
- } /* endswitch */
- } /* endif */
- } /* endif */
-
- ulDriveMap>>=1;
- chDrive++;
- } /* endwhile */
-
- DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
- }
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4.5. Documentation Chop Shop ΓòÉΓòÉΓòÉ
-
- Documentation Chop Shop
-
- In the File Systems section of the Control Program Guide and Reference, there
- are a couple of problems.
-
- 1. The API DosQueryFileInfo() is referenced when DosQueryFSInfo() is intended.
-
- 2. The sample to retrieve file system information via DosQueryFSAttach() is
- incorrect. Declaring a variable of type FSQBUFFER2 and passing it to
- DosQueryFSAttach() will return ERROR_BUFFER_OVERFLOW. You must pass a
- pointer to a buffer (stack-based or dynamically allocated) that has
- sufficient space.
-
- ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
-
- _wpPopulate is listed in the online reference as having a third parameter of
- WPFolder * and its value is the "real name of the folder to populate". In
- actuality, it is a PSZ which is the path of the folder to populate.
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 3.4.6. Want Ads ΓòÉΓòÉΓòÉ
-
- Want Ads
-
- Below are the hot topics as of this issue's writing. Feel free to write on any
- of these.
-
- Workplace Shell Programming (hot) - this is still quite the "black magic"
- topic, about which we have seen only one article. There are many out there who
- do WPS programming for a living, but they have not been sufficiently
- enlightened about our need. :)
-
- Client/Server (hot) - using either named pipes (with or without a network) or
- sockets, client/server programming is all the rage these days. On a related
- note, some people have also expressed an interest in learning about interfacing
- with the various protocol drivers (e.g. NDIS, IPX/SPX, etc.). Any articles in
- this area are most welcome.
-
- Multimedia (warm) - we recently had two articles on this topic. However, they
- both dealt with sound, which we all know is not the only alternative media
- type. Articles on anything else - MIDI, video, etc. - are needed.
-
- Scratch Patch - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 4. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
-
- How Do I Get EDM/2?
-
- EDM/2 can be obtained in any of the following ways:
-
- On the Internet
-
- o All back issues are available via anonymous FTP from the following sites:
-
- - ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory.
- - ftp.luth.se in the /pub/os2/programming/newsletter directory.
- - generalhq.pc.cc.cmu.edu
-
- o The EDM/2 mailing list. Send an empty message to edm2-info@knex.mind.org to
- receive a file containing (among other things) instructions for subscribing
- to EDM/2. This is a UUCP connection, so be patient please.
- o IBM's external gopher/WWW server in Almaden. The address is
- index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of the
- "OS/2 Information" menu; the URL is
- "gopher://index.almaden.ibm.com/1nonibm/os2nonib.70".
-
- On Compuserve
-
- All back issues are available in the OS/2 Developers Forum 2.
-
- IBM Internal
-
- o IBM's internal gopher/WWW server in Almaden. The address is
- n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; the
- URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70".
- o IBM's REQUEST command on all internal VM systems. Enter the VM command
- REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable packages
- will be sent to you; in this list are the names of the packages containing
- the EDM/2 issues.
-
- How do I Get EDM/2? - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5. Contributors to this Issue ΓòÉΓòÉΓòÉ
-
- Are You a Potential Author?
-
- We are always looking for (new) authors. If you have a topic about which you
- would like to write, send a brief description of the topic electronically to
- any of the editors, whose addresses are listed below, by the 15th of the month
- before the month in which your article will appear. This alerts us that you
- will be sending an article so that we can plan the issue layout accordingly.
- After you have done this, get the latest copy of the Article Submission
- Guidelines from ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory.
- (the file is artsub.zip) The completed text of your article should be sent to
- us no later than five days prior to the last day of the month; any articles
- received after that time may be pushed to the next issue.
-
- The editors can be reached at the following email addresses:
-
- o Larry Salomon - os2man@panix.com (Internet).
- o Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet).
-
- The following people contributed to this issue in one form or another (in
- alphabetical order):
-
- o Martin Lafaix
- o Larry Salomon, Jr.
- o Carsten Whimster
- o Gordon Zeglinski
- o Network distributors
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5.1. Martin Lafaix ΓòÉΓòÉΓòÉ
-
- Martin Lafaix
-
- Martin Lafaix is a computer science student at the UniversitВ de Nice-Sophia
- Antipolis. He currently works on his PhD thesis (key areas: functional
- language, type as value, programming in the large, ...).
-
- He can be reached at the following address: lafaix@sophia.inria.fr
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
-
- Larry Salomon, Jr.
-
- Larry Salomon, Jr. wrote his first Presentation Manager application for OS/2
- version 1.1 in 1989. Since that time, he has written numerous VIO and PM
- applications, including the Scramble applet included with OS/2 and the
- I-Brow/Magnify/Screen Capture trio being distributed by IBM with the
- Professional Developers Kit CD-ROM. Currently, he works for Cheyenne Software
- in Roslyn, New York and resides in Bellerose, New York with his wife Lisa.
-
- Larry can be reached electronically via the Internet at os2man@panix.com.
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5.3. Carsten Whimster ΓòÉΓòÉΓòÉ
-
- Carsten Whimster
-
- I am an undergraduate Computer Science student at the University of Waterloo,
- and an OS/2 enthusiast as of OS/2 2.0. I am currently in my third year, taking
- mainly operating system, language, and compiler courses as much as possible.
- This is not too difficult obviously, since this covers most of what they try to
- teach us in any case :). This summer and fall I am working at the University
- as a tutor in CS241, an introductory course to compilers. I am a TEAM-OS/2
- member, and try to keep up with several OS/2 groups on the Internet.
-
- I am a beginning OS/2 PM programmer with a few projects on the go, and many
- more in my head. I use EMX/GCC 2.5.8, Watcom C/C++ 9.5, and Watcom VX-REXX
- 2.0, and I am anxiously awaiting Watcom C/C++ 10.0's impending release.
-
- You may reach me...
-
- ...via email:
-
- bcrwhims@undergrad.math.uwaterloo.ca - Internet
-
- gopher://descartes.math.uwaterloo.ca:70/h0/mathSOC/.csc/.www/.bcrwhimster/homepage.html
- - Mosaic homepage
-
- ...via snail mail:
-
- Carsten Whimster
- 319 Erb Street West, 3rd floor
- Waterloo, Ontario
- Canada
- N2L 1W4
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
-
- Gordon Zeglinski
-
- Gordon Zeglinski is a freelance programmer/consultant who received his Master's
- degree in Mechanical Engineering with a thesis on C++ sparse matrix objects.
- He has been programming in C++ for 6 years and also has a strong background in
- FORTRAN. He started developing OS/2 applications with version 2.0 .
-
- His current projects include a client/server communications program that
- utilitizes OS/2's features which has entered beta testing. Additionally, he is
- involved in the development of a "real-time" automated vehicle based on OS/2
- and using C++ in which he does device driver development and designs the
- applications that comprise the control logic and user interface.
-
- He can be reached via the Internet at zeglins@cc.umanitoba.ca.
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6
-
-
- ΓòÉΓòÉΓòÉ 5.5. Network distributors ΓòÉΓòÉΓòÉ
-
- Network Distributors
-
- These people are part of our distribution system to provide EDM/2 on networks
- other than the Internet. Their help to provide access to this magazine for
- others is voluntary and we appreciate them a lot!
-
- o Paul Hethmon (hethmon@apac.ag.utk.edu) - Compuserve
- o Gess Shankar (gess@knex.mind.org) - Internet
- o David Singer (singer@almaden.ibm.com) - IBM Internal
- o Andre Asselin (ASSELIN AT RALVM12) - IBM Internal
-
- If you would like to become a "network distributor", be sure to contact the
- editors so that we can give you the credit you deserve!
-
- Contributors - EDM/2 - June 1994 - Volume 2, Issue 6