home *** CD-ROM | disk | FTP | other *** search
- /*
- GetFileIcon.c
- 1/2/95
- ver 1.0
- -------
-
-
- GetFileIcon is based on the FindIcon.c code by James Walker.
-
- Q: Why does GetFileIcon exist? Why not use FindIcon?
- A: There are several reasons:
- 1. Displaying a file's icon is one of the most intuitive things to do on a
- a Macintosh. Unfortunately, it is also very difficult; I would estimate
- that there is at least one person a week on the comp.sys.mac.programmer
- newsgroup who asks how to display the icon of a file. Most programmers
- are usually referred to the FindIcon code by James Walker, but the code only
- shows how to get a files' icon; it doesn’t demonstrate how to display the
- icon. Several programmers have posted messages requesting further help...
- this snippet is intended to take care of that need.
-
- 2. The FindIcon routines are able to get a file or a folders' icon.
- Personally, I do not need to retrieve a folders' icon, so I took everything
- that pertained to folders out (thus, reducing the amount of code by
- approximately half).
-
- 3. The FindIcon routine is comprised of 13 source files and 14 header files.
- With GetFileIcon, there are only two files to keep track of (GetFileIcon.c
- and GetFileIcon.h).
-
- 4. When I compile my project, I always have strict type checking turned on.
- Since GetFileIcon uses forbid_action() and forbid() in conjunction with
- 'gotos', it took quite a bit of tweaking on my part to get the code to work.
-
-
-
- Q: How do I use GetFileIcon?
- A: Simple, In your THINK C project, make sure you have MacTraps and MacTraps2
- added, then add GetFileIcon.c to the project. For an example on how to call
- GetFileIcon, look in GetFileIconExample.c. BTW: This code seems to compile
- fine under THINK C 6.0 -> 7.0.4... I do not know about earlier versions of
- THINK C.
-
-
-
- Other useful information: If you wish to contact me, my Internet address is
- jbeeghly@u.washington.edu (at least it is until June '95). I make no guarantees
- over the stability of the code (in other words, use it at your own risk). If
- you want to find out more about getting & plotting a files' icon, I strongly suggest
- you get the code to FindIcon (available at most mac development FTP sites) and THINK
- Reference.
-
-
- */
-
-
- #include "GetFileIcon.h"
-
-
- /* ------------------------------------------------------------------
- GetFileIcon Given a file specification for a file, folder, or
- volume, create an appropriate icon suite
- and find its label color.
- ------------------------------------------------------------------ */
- pascal OSErr GetFileIcon(
- /* --> */ FSSpec *thing,
- /* --> */ IconSelectorValue iconSelector,
- /* <-- */ Handle *theSuite)
- {
- CInfoPBRec cpb;
- OSErr err;
-
-
- *theSuite = NULL;
-
-
- if( IsVolEjected(thing->vRefNum) )
- {
- err = volOffLinErr;
- }
- else
- {
- cpb.hFileInfo.ioVRefNum = thing->vRefNum;
- cpb.hFileInfo.ioDirID = thing->parID;
- cpb.hFileInfo.ioNamePtr = thing->name;
- cpb.hFileInfo.ioFDirIndex = 0;
- err = PBGetCatInfoSync( &cpb );
-
-
- if( !err )
- {
- if( (cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0) // file
- {
- if(cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon)
- {
- err = GetCustomFileIcon(thing, iconSelector, theSuite );
- }
- else // no custom icon
- {
- err = GetNormalFileIcon(&cpb, iconSelector, theSuite);
- }
- }
- // ----------- end of normal case --------------
- }
- }
-
- // ------- error handler ---------
- /*if(thing->parID == fsRtParID) // a volume
- {
- if(err == volOffLinErr)
- {
- *labelColor = ttOffline;
- }
- err = GetVolumeIcon(thing->vRefNum, iconSelector, theSuite);
- }*/
-
- return( err );
- }
-
-
- Boolean IsVolEjected( short vRefNum )
- {
- OSErr err;
- HVolumeParam vol_pb;
-
- vol_pb.ioNamePtr = NULL;
- vol_pb.ioVRefNum = vRefNum;
- vol_pb.ioVolIndex = 0;
- err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
-
- return( (err == noErr) && (vol_pb.ioVDRefNum > 0) );
- }
-
-
-
- OSErr GetCustomFileIcon(
- /* --> */ FSSpec *filespec,
- /* --> */ IconSelectorValue iconSelector,
- /* <-- */ Handle *theSuite)
- {
- short saveResFile, customResFile;
- OSErr err;
-
- saveResFile = CurResFile();
- SetResLoad( false );
- customResFile = FSpOpenResFile(filespec, fsRdPerm);
-
- SetResLoad( true );
-
- if(customResFile == -1)
- {
- err = ResError();
- }
- else
- {
- err = GetResourceIcons(theSuite, kCustomIconResource, iconSelector);
- if( !err )
- {
- if( IsSuiteEmpty( *theSuite ) )
- {
- err = GetResourceIcons(theSuite, kVolumeAliasIconResource, iconSelector);
- }
- }
-
- CloseResFile( customResFile );
- UseResFile( saveResFile );
- }
- return( err );
- }
-
-
- OSErr GetNormalFileIcon(
- /* --> */ CInfoPBRec *cpb,
- /* --> */ IconSelectorValue iconSelector,
- /* <-- */ Handle *theSuite)
- {
- OSErr err;
- long dataSize;
- Handle iconData;
- Byte iconType;
- GetIconData getData;
- short iconID;
- Boolean inFinder;
- short saveResFile, FinderResFile, sysVRefNum;
- long sysDirID;
-
-
-
- iconID = FindGenericIconID(cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
- saveResFile = CurResFile();
-
-
- if( inFinder )
- {
- //(void) FindFolder( kOnSystemDisk, kSystemFolderType,
- // kDontCreateFolder, &sys_vRefNum, &sys_dirID );
- FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);
-
- SetResLoad( false );
- FinderResFile = HOpenResFile(sysVRefNum, sysDirID, "\pFinder", fsRdPerm);
- SetResLoad( true );
-
- if(FinderResFile == -1)
- {
- err = ResError();
- }
- else
- {
- err = GetResourceIcons(theSuite, iconID, iconSelector);
- CloseResFile( FinderResFile );
- }
- }
- else // icons in desktop DB or in System
- {
- getData.DTRefNum = FindDesktopDatabase(cpb->dirInfo.ioVRefNum,
- cpb->hFileInfo.ioFlFndrInfo.fdCreator );
-
- if(getData.DTRefNum != 0) // the right icons are in some desktop
- {
- err = NewIconSuite( theSuite );
- if( !err )
- {
- getData.fileCreator = cpb->hFileInfo.ioFlFndrInfo.fdCreator;
- getData.fileType = cpb->hFileInfo.ioFlFndrInfo.fdType;
- if(getData.fileType == kApplicationAliasType)
- {
- getData.fileType = 'APPL';
- }
- err = ForEachIconDo(*theSuite, iconSelector, GetIconProc, &getData);
- }
- }
- if( (getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ) )
- {
- UseResFile( 0 );
- err = GetResourceIcons(theSuite, iconID, iconSelector);
- }
- }
-
- UseResFile( saveResFile );
-
- return( err );
- }
-
-
-
- /* ------------------------------------------------------------------
- GetIcon This is an IconAction procedure to fill in one
- slot of an icon suite, given a file type, creator,
- and desktop database.
- ------------------------------------------------------------------ */
- static pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
- {
- OSErr err;
- GetIconData *data;
- DTPBRec deskRec;
-
- err = noErr;
- data = (GetIconData *)yourDataPtr;
-
- *theIcon = NewHandle( kLarge8BitIconSize );
-
-
-
- //require_action( *theIcon, NewHandle, err = memFullErr );
-
- if( !(*theIcon) )
- {
- err = memFullErr;
- }
- else
- {
- HLock( *theIcon );
-
- deskRec.ioDTRefNum = data->DTRefNum;
- deskRec.ioDTBuffer = **theIcon;
- deskRec.ioDTReqCount = kLarge8BitIconSize;
- deskRec.ioFileCreator = data->fileCreator;
- deskRec.ioFileType = data->fileType;
-
- switch( theType )
- {
- case large1BitMask:
- deskRec.ioIconType = kLargeIcon;
- break;
-
- case large4BitData:
- deskRec.ioIconType = kLarge4BitIcon;
- break;
-
- case large8BitData:
- deskRec.ioIconType = kLarge8BitIcon;
- break;
-
- case small1BitMask:
- deskRec.ioIconType = kSmallIcon;
- break;
-
- case small4BitData:
- deskRec.ioIconType = kSmall4BitIcon;
- break;
-
- case small8BitData:
- deskRec.ioIconType = kSmall8BitIcon;
- break;
-
- default:
- // The desktop database does not have "mini" icons
- deskRec.ioIconType = 1000;
- break;
- }
-
-
- err = PBDTGetIconSync( &deskRec );
-
- if(err == noErr)
- {
- HUnlock( *theIcon );
- SetHandleSize(*theIcon, deskRec.ioDTActCount);
- }
- else
- {
- DisposeHandle( *theIcon );
- *theIcon = NULL;
- err = noErr;
- }
-
- }
- return( err );
- }
-
-
- /* ------------------------------------------------------------------
- Find_desktop_database Find the reference number of a
- desktop database containing icons
- for a specified creator code.
- The search begins on a specified volume, but covers all volumes.
- ------------------------------------------------------------------ */
- static short FindDesktopDatabase(
- /* --> */ short firstVRefNum,
- /* --> */ OSType fileCreator) // returns a DT refnum or 0
- {
- OSErr err;
- VolumeParam vpb;
- short DTRefNum;
-
- DTRefNum = 0;
-
- if(!InOneDesktop(firstVRefNum, fileCreator, &DTRefNum))
- {
- vpb.ioNamePtr = NULL;
- for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
- {
- if(vpb.ioVRefNum == firstVRefNum)
- continue;
- if( InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum) )
- break;
- }
- }
-
- return( DTRefNum );
- }
-
-
-
- /* ------------------------------------------------------------------
- InOneDesktop Determine whether the desktop database for
- one particular volume contains icons for
- a given creator code, and if so, return its
- reference number.
- ------------------------------------------------------------------
- */
- static Boolean InOneDesktop(
- /* --> */ short vRefNum,
- /* --> */ OSType fileCreator,
- /* <-- */ short *dtRefNum)
- {
- OSErr err;
- DTPBRec deskRec;
- Boolean retVal;
-
- retVal = false; // default to failure
- deskRec.ioNamePtr = NULL;
- deskRec.ioVRefNum = vRefNum;
- err = PBDTGetPath( &deskRec );
-
-
- if( !err )
- {
- /* We want to ignore any non-icon data, such as the 'paul'
- item that is used for drag-and-drop. */
-
- deskRec.ioFileCreator = fileCreator;
- deskRec.ioIndex = 1;
- do
- {
- deskRec.ioTagInfo = 0;
- err = PBDTGetIconInfoSync( &deskRec );
- deskRec.ioIndex += 1;
- }while( (err == noErr) && (deskRec.ioIconType <= 0) );
-
- if(err == noErr)
- {
- retVal = true;
- *dtRefNum = deskRec.ioDTRefNum;
- }
- }
- return( retVal );
- }
-
-
- pascal OSErr GetResourceIcons(
- /* <-- */ Handle *theSuite,
- /* --> */ short theID,
- /* --> */ long theSelector)
- {
- OSErr err;
-
- err = Get1IconSuite(theSuite, theID, theSelector);
- if(err == noErr)
- {
- err = CopyEachIcon( *theSuite );
- }
-
- return( err );
- }
-
-
-
- OSErr CopyEachIcon(
- /* <-> */ Handle theSuite)
- {
- return( ForEachIconDo(theSuite, svAllAvailableData, CopyOneIcon, NULL) );
- }
-
-
- static pascal OSErr CopyOneIcon(
- /* --> */ ResType theType,
- /* <-> */ Handle *theIcon,
- /* --- */ void *yourDataPtr)
- {
- OSErr err;
-
- if(*theIcon != NULL)
- {
- LoadResource( *theIcon );
- err = HandToHand( theIcon );
- if(err != noErr)
- *theIcon = NULL;
- }
-
- return( noErr );
- }
-
-
- short FindGenericIconID(
- /* --> */ OSType theType,
- /* <-- */ Boolean *inFinder)
- {
- short id;
- register OSType *iconTypes;
- register short *iconIDs;
- Ptr iconIDsStart;
- OSType *beginSysIcons;
-
- asm {
- BRA @start
- @icon_type_storage
- dc.L 'ifil'
- dc.L 'sfil'
- dc.L 'ffil'
- dc.L 'tfil'
- dc.L 'kfil'
- dc.L 'FFIL'
- dc.L 'DFIL'
- @Finder_icons_end
- dc.L kContainerFolderAliasType
- dc.L kContainerTrashAliasType
- dc.L kSystemFolderAliasType
- dc.L 'INIT'
- dc.L 'APPL'
- dc.L 'dfil'
- dc.L 'pref'
- dc.L kAppleMenuFolderAliasType
- dc.L kControlPanelFolderAliasType
- dc.L kExtensionFolderAliasType
- dc.L kPreferencesFolderAliasType
- dc.L kStartupFolderAliasType
- dc.L kApplicationAliasType
- dc.L kExportedFolderAliasType
- dc.L kDropFolderAliasType
- dc.L kSharedFolderAliasType
- dc.L kMountedFolderAliasType
- @icon_id_storage
- dc.W 12500
- dc.W 14000
- dc.W 14500
- dc.W 14501
- dc.W 14750
- dc.W 15500
- dc.W 15750
-
- dc.W genericFolderIconResource
- dc.W trashIconResource
- dc.W systemFolderIconResource
- dc.W genericExtensionIconResource
- dc.W genericApplicationIconResource
- dc.W genericDeskAccessoryIconResource
- dc.W genericPreferencesIconResource
- dc.W appleMenuFolderIconResource
- dc.W controlPanelFolderIconResource
- dc.W extensionsFolderIconResource
- dc.W preferencesFolderIconResource
- dc.W startupFolderIconResource
- dc.W genericApplicationIconResource
- dc.W ownedFolderIconResource
- dc.W dropFolderIconResource
- dc.W sharedFolderIconResource
- dc.W mountedFolderIconResource
- @start
- LEA @icon_type_storage, iconTypes
- LEA @icon_id_storage, iconIDs
- LEA @Finder_icons_end, A0
- move.L A0, beginSysIcons
- }
-
- iconIDsStart = (Ptr )iconIDs;
- id = genericDocumentIconResource; // default
-
- while( ((Ptr )iconTypes) < iconIDsStart)
- {
- if(theType == *iconTypes)
- {
- id = *iconIDs;
- break;
- }
- iconTypes++;
- iconIDs++;
- }
-
- *inFinder = (iconTypes < beginSysIcons);
-
- return( id );
- }
-
-
-
- /* --------------------------------------------------------------------
- Get1IconSuite Like GetIconSuite, but only looks in
- the current resource file.
-
- In case you're wondering why it would be necessary to ensure that
- icons come from only one file, suppose you're looking at a
- file that has its custom icon bit set, but for some reason does
- not contain a custom icon, or at least not a full family.
- Way down the resource chain, there may be another file, say a
- font file, that does have a full family of custom icons.
- So you get an unexpected icon.
- -------------------------------------------------------------------- */
-
- pascal OSErr Get1IconSuite(
- /* <-- */ Handle *theSuite,
- /* --> */ short theID,
- /* --> */ long theSelector)
- {
- OSErr err;
-
- err = NewIconSuite( theSuite );
- if( !err )
- {
- err = ForEachIconDo(*theSuite, theSelector,
- (IconAction ) Get1Icon, &theID);
- }
- return( err );
- }
-
-
-
- static pascal OSErr Get1Icon(
- /* --> */ ResType theType,
- /* <-> */ Handle *theIcon,
- /* --> */ short *resID)
- {
- *theIcon = Get1Resource(theType, *resID);
-
- return( noErr );
- }
-
-
- static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr)
- {
- if(*theIcon != NULL)
- *(Boolean *)yourDataPtr = false; // not empty!
-
- return( noErr );
- }
-
-
- Boolean IsSuiteEmpty( Handle theSuite )
- {
- Boolean retVal;
-
- retVal = true;
- ForEachIconDo(theSuite, svAllAvailableData, TestHandle, &retVal);
-
- return( retVal );
- }
-
-
-