Icon Reader
Volume Number: | | 3
|
Issue Number: | | 6
|
Column Tag: | | Assembly Language Lab
|
Icon Reader Utility
By Ms. Jean Thomas, Swarthmore, PA
Getting Application Icons
Whenever I receive a number of new programs, one of the things I most look forward to is seeing the new icons. Normally this would require a trip to the Finder, but even there you cant see any related document icons until you open the application and create a file (or use ResEdit). If you dont happen to have 120k free on your disk, you can use this little IconApp utility to view application and document icons.
Even though every application on the Desktop has an icon, applications that havent been bundled or set up to display a specific icon (along with other information) take on a generic application icon which is stored in the Finder. Applications which have been bundled and have a file reference number, used by the Finder to associate applications with their icons (BNDL and FREF), can have a unique icon on the Desktop. The Finder copies the files icons into the destkop file and keeps track of each icon set per each file creator tag. Thus if another applicaton is loaded with the same creator as a previous application, its icon will change to the wrong icon on the desktop. This is why creator tags must be unique. Also, the deskto never forgets, so even if you have a unique creator tag, it may be necessary to force the Finder to rebuild the desktop file by holding down the cmd-option keys during a re-boot. This program opens an applications resource fork and displays the programs bundled icons in a small dialog box.
An icon is a quickdraw object that is defined as a small 128 byte bitmap four bytes wide living in a small rectangle 32 by 32. In our program we define a bitmap to hold the icon as follows:
iconmap: dc.l ; pointer to bit image base address
dc.w ; integer of row bytes (4)
dc.w ; rect top 0
dc.w ; rect left 0
dc.w ; rect bottom 32
dc.w ; rect right 32
We read in the icons and store them in our iconmap, then call PlotIcon to display them in our dialog box.
Getting access to the icons of an application requires that we open its resource fork. Given a filename, _OpenResFile returns the file reference number of the selected file. In order to simplify things, I used the standard file reply dialog to get rname+appreply or a filename from the dialog reply record. _OpenResFile also returns -1 to the stack if an error occurred in opening the resource file, such as no resource file,etc. Normally you would call _ResError to check for the specific error code if anything went wrong, but since we are only dealing with applications, I skipped that step. Unless the file has been corrupted, every application will have a resource fork with at least one resource of type CODE. In the event of corruption, however, IconApp will simply beep and return. One important thing to remember is that _OpenResFile assumes that the resource file to be opened resides on the default volume, so we have to get the volume reference number from the sfreply record before opening any resource first.
SearchIcon
clr -(SP) ; room for resource file ref num
lea rname+appreply,A1 ; get filename
move.l A1,-(SP)
_OpenResFile ; open resource file
move (SP),D7 ; D7=refnum
cmpi #-1,D7 ; error?(no resources)
bne ValidName ; no,get filename
bra NoRez ; yes,beep and return
Once we know the application has a resource fork, its time to look for any icons. Given a resource type, ICN# in this case, _CountResources will return the total number of resources in the chosen file. Applications with unique icons always have at least one ICN# resource, but larger applications often have file or document icons as well.
ValidName
CheckDItem #3 ; get statictext handle
move.l theItem(A5),-(SP)
pea rname+appreply ; get our filename
_SetIText ; print it in dialog
clr -(SP) ; room for # of icons
move.L #ICN#,-(SP) ; resource type
_CountResources
move (SP),D5 ; get # of icons in file
subq #2,D5
cmpi #1,D5 ; is there at least one icon?
blt NoIcon ; no, say so
bra DoIcon ; otherwise,prepare to plot it
At the beginning of IconApp, the handle of a generic icon bitmap was stored in A4. If an application doesnt have an ICN# resource, both the filename and the generic icon will be plotted in our dialog box.
Since the total number of icons in the selected application was stored in D5, creating a loop to plot each icon is straight forward. D6 will be an index to the next plotted icon. Any application which has reached this point will contain at least one ICN# resource, so D6 is initialized to 1. _GetIndResource can be used to call a number of resources consecutively, so passing D6 and a resource type to _GetIndResource returns a handle to the resource. Each time an icon is plotted, the index to the last icon is compared to the total number of resources in the file. I only included frames for three icons, so if the last plotted icon is not the third one, D6 is incremented and we return to plot the next one. The reference number of the most recently opened resource file was saved in D7 when the file was first opened, so we pass that same refnum to _CloseResFile before dealing dealing with another application.
Fig. 0: Our IconApp reads Icons!
Fig.1: Reply Record Equates
In order to draw both a generic icon and any icon resources in an application, I used _BlockMove (register-based), where A0 points to a source, A1 points to a destination and D0 is the number of bytes to transfer from one rectangle to another. In this case, A0 is a handle to the icon and A1 points to a 128-byte bitmap which will hold the icon. Since we want the entire icon, D0 contains 128. In order to transfer the icon bit map to the screen, we call _Ploticon which will draw the icon in a pre-specified rectangle in the dialog box.
MACRO IconDraw IRect =
clr.l -(SP)
move.L #ICN#,-(SP)
move D6,-(SP)
_GetIndResource
move.l (SP),A0
movea.l (A0),A0
cmpa.l #0,A0
beq CloseRez
lea iconmap,A1
movea.l (A1),A1
move.l #128,D0
_BlockMove
pea {IRect}
lea iconmap,A1
move.l A1,-(SP)
_PlotIcon
_BlockMove is a useful way to transfer bitmap images to the screen. It is also a neat way to achieve flicker-free animation without resorting to the dreaded alternate screen buffer.
Fig.2: MacDraw Icons
Fig.3: Generic Icon
User Notes
IconApp is a very simple application, but it demonstrates how to use bitmaps and manipulate resource files effectively. Using the program is easy: just click on the Icons button and select a file in the normal way. Both the application and document icons of the selected file, along with the application name, will be printed out in the dialog box. IconApp will search for and draw up to three icons in the frames.
Some corrupted applications which have been bundled and have a unique icon will appear on the Desktop with a generic icon. IconApp will plot the correct icon in the icon frames instead of the one that appears in the Finder. This is because it reads the icon from the application file and not the desktop file, so even if two applications have the same file creator tag, our utility will display the proper icon.
;IconApp
IncludeMacTraps.D
IncludeSysEqu.D
IncludePackMacs.Txt
;------------------------------Macros----------------
; IconDraw assumes that D5 contains the total number
; of resources of type ICN# in the application, and
; D6 is an index to the icon we are going to plot next.
; A0-> the sourcerect,A1-> the destrect and
; D0-> the number of bytes to transfer.
MACRO IconDraw IRect =
clr.l -(SP) ;handle
move.L #ICN#,-(SP);res type
move D6,-(SP) ;index
_GetIndResource
move.l (SP),A0
movea.l(A0),A0 ;handle to ptr
cmpa.l #0,A0 ;nil?
beq CloseRez ;yes, so exit
lea iconmap,A1
movea.l(A1),A1
move.l #128,D0
_BlockMove ;copy icon res to iconmap
pea {IRect}
lea iconmap,A1 ;get icon handle
move.l A1,-(SP)
_PlotIcon;plot icon in rect
|
MACRO CheckDItem Item=
move.l (A2),-(SP) ; get Dialog pointer
move.w {Item},-(SP) ; Dialog item in question
pea theType(A5); VAR type
pea theItem(A5); VAR item
pea theRect(A5); VAR box
_GetDItem
|
XDEF START ; linker requisite
;------------------Equates----------------------
AllEvents equ $0000FFFF
DWindLenequ $AA
;------------------Initialize Managers----------
START
pea -4(A5); push Quickdraw globals
_InitGraf; init Quickdraw
_InitFonts ; init Font manager
_InitWindows ; init Window manager
_InitMenus ; init Menu manager
clr.l -(SP) ; no restart procedure
_InitDialogs ; init Dialog manager
_TEInit; init TextEdit
move.l #AllEvents,D0 ; all standard events
_FlushEvents ; flushed from event queue
_InitCursor; get standard arrow cursor
;--------------------------Miscellaneous------------------
move.l #128,D0 ; 128 bytes for icon
_NewPtr; get pointer
cmpi #0,D0 ; error?
Bne Quit; yes, exit out
lea iconmap,A1 ; no, get handle to icon
move.l A0,(A1) ; save pointer to icon data
move.L #ICON,-(SP); res type for icon
move #128,-(SP) ; ResID of our generic icon
_GetResource ; get generic icon from system
move.l (SP),A4 ; save its handle in A4
bra IconInfo ; get IconDialog box
Quit
_ExitToShell
;------------------------------------------------------------------
IconInfo
clr.l -(SP) ; get room for Dialog pointer
move.w #160,-(SP) ; resource ID
pea IconDialog(A5) ; storage for Dialog record
move.l #-1,-(SP); in front of other windows
_GetNewDialog
lea IconHandle,A2; duplicate handle
move.l (SP),(A2); leave handle on stack
_DrawDialog; draw dialog box and..
lea IconHandle,A2
move.l (A2),-(SP) ; set port to us
_SetPort
DialogLoop
bsr Outline ; outline the quit button
bsr GetFrames ; draw our three icon frames
clr.l -(SP) ; no filter proc
pea ItemHit ; VAR ItemHit
_ModalDialog
move ItemHit,D0 ; Get Item chosen
cmp.b #1,D0 ; quit?
beq.s CloseIt
cmp.b #2,D0 ; get appl. icon?
beq.s GetFile
bra DialogLoop ; no,wait for a valid choice
CloseIt
move.l (A2),-(SP) ; get dialog ptr.
_CloseDialog ; close dialog
_ExitToShell ; exit...
GetFile
move.w #100,-(sp) ; upper corner of reply box
move.w #100,-(sp)
pea scratch ; dummy string
clr.l -(sp) ; filter
move #1,-(sp) ; only applications
pea apptype ; type list
clr.l -(sp) ; dialog hook
pea appreply ; reply record
move #2,-(sp) ; standard file reply dialog
_pack3
move rgood+appreply,d0 ; was a file chosen?
beq DialogLoop ; no, return
lea parmblock(A5),A0 ; A0-> parameter block
clr.l ioCompletion(A0) ; no completion routine
lea appreply,A1; A1-> reply record
move.w 6(A1),ioVRefNum(A0) ; get drive refnum
clr.l ioVNPtr(A0); volume name pointer
_SetVol
SearchIcon
clr -(SP) ; room for resource file ref num
lea rname+appreply,A1 ; get filename
move.l A1,-(SP)
_OpenResFile ; open resource file
move (SP),D7 ; D7=refnum
cmpi #-1,D7; error?(no resources)
Bne ValidName ; no,get filename
bra NoRez ; yes,beep and return
NoRez
move #20,-(SP)
_SysBeep
bra DialogLoop
ValidName
CheckDItem #3 ; get statictext handle
move.l theItem(A5),-(SP)
pea rname+appreply ; get our filename
_SetIText; print it in dialog
clr -(SP) ; room for # of icons
move.L #ICN#,-(SP); resource type
_CountResources
move (SP),D5 ; get # of icons in file
subq #2,D5
cmpi #1,D5 ; is there at least one icon?
blt NoIcon; no, say so
bra DoIcon; otherwise,prepare to plot it
DoIcon
move #1,D6 ; get first icon
IconDraw iconrect1; plot it
cmp D5,D6 ; is this the only icon?
beq CloseRez ; yes,close resource file
addq #1,D6 ; no,add one to counter
bra DoIcon2 ; get second icon
DoIcon2
IconDraw iconrect2; plot second icon
cmp D5,D6 ; is there a third icon?
beq CloseRez ; no, close resource file
addq #1,D6 ; yes, add one to counter
bra DoIcon3 ; get third icon
DoIcon3
IconDraw iconrect3; plot third icon
bra CloseRez ; close resource file
NoIcon
CheckDItem #3 ; get statictext handle
move.l theItem(A5),-(SP)
pea rname+appreply ; get our filename
_SetIText; print it in dialog
move.l A4,A0 ; get handle of generic icon
movea.l(A0),A0 ; A0-> sourcerect
cmpa.l #0,A0
beq CloseRez
lea iconmap,A1 ; A1-> destrect
movea.l(A1),A1
move.l #128,D0 ; D0 = number of bytes to move
_BlockMove
pea iconrect1
lea iconmap,A1
move.l A1,-(SP)
_PlotIcon; plot generic icon
bra DialogLoop ; return
GetFrames:; print icon frames
pea iconframe1
_FrameRect
pea iconframe2
_FrameRect
pea iconframe3
_FrameRect
rts
OutLine:; outline first item in dialog, or quit button
CheckDItem #1
move #3,-(SP)
move #3,-(SP)
_PenSize
pea theRect(A5); VAR box
move #-4,-(SP)
move #-4,-(SP)
_InsetRect
pea theRect(A5)
move #16,-(SP)
move #16,-(SP)
_FrameRoundRect
rts
CloseRez
move D7,-(SP) ; D7=rsrc.file refnum
_CloseResFile ; close resource file
bra DialogLoop ; return
;----------------------Local storage------------------
EventRecord
What: dc.w0 ;what event number
Message: dc.l 0 ;ptr. to msg
When: dc.l0 ;Time event was posted
Point: dc.l0 ;mouse coordinates
Modify:dc.w0 ;state of keys & button
WWindow: dc.l 0 ;Find windows result
IconHandledc.l 0
ItemHit dc.w0 ; dialog items
scratch
dc.b 14
dc.b
dc.l 0
apptype dc.bAPPL
dcb.b 14,$ff
appreplydc.w5
dc.b 63
dcb.b 63,0
iconmap dc.w 0,0,4,0,0,$20,$20
iconrect1 dc.w 17,61,49,93
iconrect2 dc.w 17,120,49,152
iconrect3 dc.w 17,174,49,206
iconframe1dc.w 10,57,54,98
iconframe2dc.w 10,115,54,156
iconframe3dc.w 10,169,54,210
;----------------------Globals----------------
IconDialogds.w DWindLen
theType ds.w1 ; VAR for GetDItem
theItem ds.l1 ; VAR for GetDItem
theRect ds.w4 ; VAR for GetDItem
parmblock ds.w 80
; IconApp_rscs.ASM
RESOURCE INAP 0 IDENTIFICATION
DC.B 15, ICON RETRIEVER
.ALIGN 2
RESOURCE BNDL 128 BUNDLE
DC.L INAP;NAME OF SIGNATURE
DC.W 0,1 ;DATA (DOESNT CHANGE)
DC.L ICN#;ICON MAPPINGS
DC.W0 ;NUMBER OF MAPPINGS-1
DC.W 0,128 ;MAP 0 TO ICON 128
DC.L FREF;FREF MAPPINGS
DC.W0 ;NUMBER OF MAPPINGS-1
DC.W0,128 ;MAP 0 TO FREF 128
RESOURCE FREF 128 FREF 1
DC.B APPL, 0, 0, 0
.ALIGN 2
RESOURCE ICN# 128 MY ICON
; APPLICATION ICON BIT MAP
DC.L $00000000,$00000000,$3FFFFFFC,$35555554
DC.L $2AAAAAAC,$35555554,$2AAAAAAC,$35FFFFD4
DC.L $2B0000AC,$354000D4,$2B4000AC,$355800D4
DC.L $2B5000AC,$355000D4,$2B1380AC,$351A80D4
DC.L $2B0280AC,$3502A0D4,$2B03B2AC,$35002AD4
DC.L $2B0026AC,$350022D4,$2B0000AC,$350000D4
DC.L $2BFFFFAC,$35555554,$2AAAAAAC,$35555554
DC.L $2AAAAAAC,$3FFFFFFC,$00000000,$00000000
*
DC.L $00000000,$00000000,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$3FFFFFFC,$3FFFFFFC
DC.L $3FFFFFFC,$3FFFFFFC,$00000000,$00000000
.ALIGN 2
RESOURCE ICON 128 THE ICON
; GENERIC APPLICATION ICON BIT MAP
DC.L $00010000,$00028000,$00044000,$00082000
DC.L $00101000,$00200800,$00400400,$00800200
DC.L $01000100,$02000080,$04000040,$08000020
DC.L $10000010,$20000008,$40003F04,$80004082
DC.L $40008041,$20013022,$1001C814,$080E7F8F
DC.L $04023007,$02010007,$01008007,$00806007
DC.L $00401FE7,$0020021F,$00100407,$00080800
DC.L $00041000,$00022000,$00014000,$00008000
*
DC.L $00010000,$00038000,$0007C00,$0000FE000
DC.L $001FF000,$003FF800,$007FFC0,$000FFFE00
DC.L $01FFFF00,$03FFFF80,$07FFFFC,$00FFFFFE0
DC.L $1FFFFFF0,$3FFFFFF8,$7FFFFFF,$CFFFFFFFE
DC.L $7FFFFFFF,$3FFFFFFE,$1FFFFFF,$C0FFFFFFF
DC.L $07FFFFFF,$03FFFFFF,$01FFFFF,$F00FFFFFF
DC.L $007FFFFF,$003FFE1F,$001FFC0,$7000FF800
DC.L $0007F000,$0003E000,$0001C00,$000008000
.ALIGN 2
RESOURCE DLOG 160 Icon Dialog
DC.W 107,122,227,376 ;BoundsRect
DC.W 1 ; Dialog box w/ outline
DC.B 1,1 ; Visible
DC.B 0,0 ; NoGoAway
DC.L 0 ; RefCon
DC.W 160 ; DITL ResID
DC.B Icon.. ; Title
.ALIGN 2
RESOURCE DITL 160 Icon..
STRING_FORMAT 2
DC.W 3 ;3 Items (4-1=3)
DC.L 0 ; handle holder
DC.W 86,194,115,248 ; BoundsRect
DC.B 4 ; Button #1
DC.B Quit; title
DC.L 0 ; handle holder
DC.W 86,106,115,185 ; BoundsRect
DC.B 4 ; button #2
DC.B Icons.. ; title
DC.L 0 ; handle holder
DC.W 60,78,76,241 ; BoundsRect
DC.B 8 ; statictext #1
DC.B
DC.L 0 ; handle holder
DC.W 60,3,76,76 ; BoundsRect
DC.B 8 ; statictext #2
DC.B File Name:
STRING_FORMAT 0 ; normal
!START
[
)
/OUTPUT IconApp
IconApp
/TYPE APPL INAP
/BUNDLE
/RESOURCES
IconApp_rscs
$