Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MoreDesktopMgr.c
/* |
File: MoreDesktopMgr.c |
Description:A collection of useful high-level Desktop Manager routines. |
If the Desktop Manager isn't available, use the Desktop file |
for 'read' operations. |
We do more because we can... |
Author: JL & NG |
Copyright: Copyright: © 1992-1999 by Apple Computer, Inc. |
all rights reserved. |
Disclaimer: You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
Change History (most recent first): |
6/25/99 Updated for Metrowerks Codewarror Pro 2.1(KG) |
*/ |
#include <Types.h> |
#include <Errors.h> |
#include <Memory.h> |
#include <Files.h> |
#include <Resources.h> |
#include <Icons.h> |
#define __COMPILINGMOREFILES |
#include "MoreFiles.h" |
#include "MoreFilesExtras.h" |
#include "Search.h" |
#include "MoreDesktopMgr.h" |
/*****************************************************************************/ |
/* Desktop file notes: |
** |
** ¥ The Desktop file is owned by the Finder and is normally open by the |
** Finder. That means that we only have read-only access to the Desktop |
** file. |
** ¥ Since the Resource Manager doesn't support shared access to resource |
** files and we're using read-only access, we don't ever leave the |
** Desktop file open. We open a path to it, get the data we want out |
** of it, and then close the open path. This is the only safe way to |
** open a resource file with read-only access since some other program |
** could have it open with write access. |
** ¥ The bundle related resources in the Desktop file are normally |
** purgable, so when we're looking through them, we don't bother to |
** release resources we're done looking at - closing the resource file |
** (which we always do) will release them. |
** ¥ Since we can't assume the Desktop file is named "Desktop" |
** (it probably is everywhere but France), we get the Desktop |
** file's name by searching the volume's root directory for a file |
** with fileType == 'FNDR' and creator == 'ERIK'. The only problem with |
** this scheme is that someone could create another file with that type |
** and creator in the root directory and we'd find the wrong file. |
** The chances of this are very slim. |
*/ |
/*****************************************************************************/ |
/* local defines */ |
enum |
{ |
kBNDLResType = 'BNDL', |
kFREFResType = 'FREF', |
kIconFamResType = 'ICN#', |
kFCMTResType = 'FCMT', |
kAPPLResType = 'APPL' |
}; |
/*****************************************************************************/ |
/* local data structures */ |
#if PRAGMA_ALIGN_SUPPORTED |
#pragma options align=mac68k |
#endif |
struct IDRec |
{ |
short localID; |
short rsrcID; |
}; |
typedef struct IDRec IDRec; |
typedef IDRec *IDRecPtr; |
struct BundleType |
{ |
OSType type; /* 'ICN#' or 'FREF' */ |
short count; /* number of IDRecs - 1 */ |
IDRec idArray[1]; |
}; |
typedef struct BundleType BundleType; |
typedef BundleType *BundleTypePtr; |
struct BNDLRec |
{ |
OSType signature; /* creator type signature */ |
short versionID; /* version - should always be 0 */ |
short numTypes; /* number of elements in typeArray - 1 */ |
BundleType typeArray[1]; |
}; |
typedef struct BNDLRec BNDLRec; |
typedef BNDLRec **BNDLRecHandle; |
struct FREFRec |
{ |
OSType fileType; /* file type */ |
short iconID; /* icon local ID */ |
Str255 fileName; /* file name */ |
}; |
typedef struct FREFRec FREFRec; |
typedef FREFRec **FREFRecHandle; |
struct APPLRec |
{ |
OSType creator; /* creator type signature */ |
long parID; /* parent directory ID */ |
Str255 applName; /* application name */ |
}; |
typedef struct APPLRec APPLRec; |
typedef APPLRec *APPLRecPtr; |
#if PRAGMA_ALIGN_SUPPORTED |
#pragma options align=reset |
#endif |
/*****************************************************************************/ |
/* static prototypes */ |
static OSErr GetDesktopFileName(short vRefNum, |
Str255 desktopName); |
static OSErr GetAPPLFromDesktopFile(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
short *applVRefNum, |
long *applParID, |
Str255 applName); |
static OSErr FindBundleGivenCreator(OSType creator, |
BNDLRecHandle *returnBndl); |
static OSErr FindTypeInBundle(OSType typeToFind, |
BNDLRecHandle theBndl, |
BundleTypePtr *returnBundleType); |
static OSErr GetLocalIDFromFREF(BundleTypePtr theBundleType, |
OSType fileType, |
short *iconLocalID); |
static OSErr GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType, |
short iconLocalID, |
short *iconRsrcID); |
static OSType DTIconToResIcon(short iconType); |
static OSErr GetIconFromDesktopFile(ConstStr255Param volName, |
short vRefNum, |
short iconType, |
OSType fileCreator, |
OSType fileType, |
Handle *iconHandle); |
static OSErr GetCommentID(short vRefNum, |
long dirID, |
ConstStr255Param name, |
short *commentID); |
static OSErr GetCommentFromDesktopFile(short vRefNum, |
long dirID, |
ConstStr255Param name, |
Str255 comment); |
/*****************************************************************************/ |
/* |
** GetDesktopFileName |
** |
** Get the name of the Desktop file. |
*/ |
static OSErr GetDesktopFileName(short vRefNum, |
Str255 desktopName) |
{ |
OSErr error; |
HParamBlockRec pb; |
short index; |
Boolean found; |
pb.fileParam.ioNamePtr = desktopName; |
pb.fileParam.ioVRefNum = vRefNum; |
pb.fileParam.ioFVersNum = 0; |
index = 1; |
found = false; |
do |
{ |
pb.fileParam.ioDirID = fsRtDirID; |
pb.fileParam.ioFDirIndex = index; |
error = PBHGetFInfoSync(&pb); |
if ( error == noErr ) |
{ |
if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') && |
(pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') ) |
{ |
found = true; |
} |
} |
++index; |
} while ( (error == noErr) && !found ); |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DTOpen(ConstStr255Param volName, |
short vRefNum, |
short *dtRefNum, |
Boolean *newDTDatabase) |
{ |
OSErr error; |
GetVolParmsInfoBuffer volParmsInfo; |
long infoSize; |
DTPBRec pb; |
/* Check for volume Desktop Manager support before calling */ |
infoSize = sizeof(GetVolParmsInfoBuffer); |
error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize); |
if ( error == noErr ) |
{ |
if ( hasDesktopMgr(volParmsInfo) ) |
{ |
pb.ioNamePtr = (StringPtr)volName; |
pb.ioVRefNum = vRefNum; |
error = PBDTOpenInform(&pb); |
/* PBDTOpenInform informs us if the desktop was just created */ |
/* by leaving the low bit of ioTagInfo clear (0) */ |
*newDTDatabase = ((pb.ioTagInfo & 1L) == 0); |
if ( error == paramErr ) |
{ |
error = PBDTGetPath(&pb); |
/* PBDTGetPath doesn't tell us if the database is new */ |
/* so assume it is not new */ |
*newDTDatabase = false; |
} |
*dtRefNum = pb.ioDTRefNum; |
} |
else |
{ |
error = paramErr; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** GetAPPLFromDesktopFile |
** |
** Get a application's location from the |
** Desktop file's 'APPL' resources. |
*/ |
static OSErr GetAPPLFromDesktopFile(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
short *applVRefNum, |
long *applParID, |
Str255 applName) |
{ |
OSErr error; |
short realVRefNum; |
Str255 desktopName; |
short savedResFile; |
short dfRefNum; |
Handle applResHandle; |
Boolean foundCreator; |
Ptr applPtr; |
long applSize; |
error = DetermineVRefNum(volName, vRefNum, &realVRefNum); |
if ( error == noErr ) |
{ |
error = GetDesktopFileName(realVRefNum, desktopName); |
if ( error == noErr ) |
{ |
savedResFile = CurResFile(); |
/* |
** Open the 'Desktop' file in the root directory. (because |
** opening the resource file could preload unwanted resources, |
** bracket the call with SetResLoad(s)) |
*/ |
SetResLoad(false); |
dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm); |
SetResLoad(true); |
if ( dfRefNum != -1) |
{ |
/* Get 'APPL' resource ID 0 */ |
applResHandle = Get1Resource(kAPPLResType, 0); |
if ( applResHandle != NULL ) |
{ |
applSize = InlineGetHandleSize((Handle)applResHandle); |
if ( applSize != 0 ) /* make sure the APPL resource isn't empty */ |
{ |
foundCreator = false; |
applPtr = *applResHandle; |
/* APPL's don't have a count so I have to use the size as the bounds */ |
while ( (foundCreator == false) && |
(applPtr < (*applResHandle + applSize)) ) |
{ |
if ( ((APPLRecPtr)applPtr)->creator == creator ) |
{ |
foundCreator = true; |
} |
else |
{ |
/* fun with pointer math... */ |
applPtr += sizeof(OSType) + |
sizeof(long) + |
((APPLRecPtr)applPtr)->applName[0] + 1; |
/* application mappings are word aligned within the resource */ |
if ( ((unsigned long)applPtr % 2) != 0 ) |
{ |
applPtr += 1; |
} |
} |
} |
if ( foundCreator == true ) |
{ |
*applVRefNum = realVRefNum; |
*applParID = ((APPLRecPtr)applPtr)->parID; |
BlockMoveData(((APPLRecPtr)applPtr)->applName, |
applName, |
((APPLRecPtr)applPtr)->applName[0] + 1); |
/* error is already noErr */ |
} |
else |
{ |
error = afpItemNotFound; /* didn't find a creator match */ |
} |
} |
else |
{ |
error = afpItemNotFound; /* no APPL mapping available */ |
} |
} |
else |
{ |
error = afpItemNotFound; /* no APPL mapping available */ |
} |
/* restore the resource chain and close the Desktop file */ |
UseResFile(savedResFile); |
CloseResFile(dfRefNum); |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DTXGetAPPL(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
Boolean searchCatalog, |
short *applVRefNum, |
long *applParID, |
Str255 applName) |
{ |
OSErr error; |
UniversalFMPB pb; |
short dtRefNum; |
Boolean newDTDatabase; |
short realVRefNum; |
short index; |
Boolean applFound; |
FSSpec spec; |
long actMatchCount; |
/* get the real vRefNum */ |
error = DetermineVRefNum(volName, vRefNum, &realVRefNum); |
if ( error == noErr ) |
{ |
error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase); |
if ( error == noErr ) |
{ |
if ( !newDTDatabase ) |
{ |
index = 0; |
applFound = false; |
do |
{ |
pb.dtPB.ioNamePtr = applName; |
pb.dtPB.ioDTRefNum = dtRefNum; |
pb.dtPB.ioIndex = index; |
pb.dtPB.ioFileCreator = creator; |
error = PBDTGetAPPLSync(&pb.dtPB); |
if ( error == noErr ) |
{ |
/* got a match - see if it is valid */ |
*applVRefNum = realVRefNum; /* get the vRefNum now */ |
*applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */ |
/* pb.hPB.fileParam.ioNamePtr is already set */ |
pb.hPB.fileParam.ioVRefNum = realVRefNum; |
pb.hPB.fileParam.ioFVersNum = 0; |
pb.hPB.fileParam.ioDirID = *applParID; |
pb.hPB.fileParam.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ |
if ( PBHGetFInfoSync(&pb.hPB) == noErr ) |
{ |
if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) && |
(pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') ) |
{ |
applFound = true; |
} |
} |
} |
++index; |
} while ( (error == noErr) && !applFound ); |
if ( error != noErr ) |
{ |
error = afpItemNotFound; |
} |
} |
else |
{ |
/* Desktop database is empty (new), set error to try CatSearch */ |
error = afpItemNotFound; |
} |
} |
/* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */ |
if ( error == paramErr ) |
{ |
/* if paramErr, the volume didn't support the Desktop Manager */ |
/* try the Desktop file */ |
error = GetAPPLFromDesktopFile(volName, vRefNum, creator, |
applVRefNum, applParID, applName); |
if ( error == noErr ) |
{ |
/* got a match - see if it is valid */ |
pb.hPB.fileParam.ioNamePtr = applName; |
pb.hPB.fileParam.ioVRefNum = *applVRefNum; |
pb.hPB.fileParam.ioFVersNum = 0; |
pb.hPB.fileParam.ioDirID = *applParID; |
pb.hPB.fileParam.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ |
if ( PBHGetFInfoSync(&pb.hPB) == noErr ) |
{ |
if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) || |
(pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') ) |
{ |
error = afpItemNotFound; |
} |
} |
else if ( error == fnfErr ) |
{ |
error = afpItemNotFound; |
} |
} |
} |
/* acceptable error from DesktopFile code to continue is afpItemNotFound */ |
if ( (error == afpItemNotFound) && searchCatalog) |
{ |
/* Couldn't be found in the Desktop file either, */ |
/* try searching with CatSearch if requested */ |
error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1, |
&actMatchCount, true); |
if ( (error == noErr) || (error == eofErr) ) |
{ |
if ( actMatchCount > 0 ) |
{ |
*applVRefNum = spec.vRefNum; |
*applParID = spec.parID; |
BlockMoveData(spec.name, applName, spec.name[0] + 1); |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpDTXGetAPPL(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
Boolean searchCatalog, |
FSSpec *spec) |
{ |
return ( DTXGetAPPL(volName, vRefNum, creator, searchCatalog, |
&(spec->vRefNum), &(spec->parID), spec->name) ); |
} |
/*****************************************************************************/ |
pascal OSErr DTGetAPPL(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
short *applVRefNum, |
long *applParID, |
Str255 applName) |
{ |
/* Call DTXGetAPPL with the "searchCatalog" parameter true */ |
return ( DTXGetAPPL(volName, vRefNum, creator, true, |
applVRefNum, applParID, applName) ); |
} |
/*****************************************************************************/ |
pascal OSErr FSpDTGetAPPL(ConstStr255Param volName, |
short vRefNum, |
OSType creator, |
FSSpec *spec) |
{ |
/* Call DTXGetAPPL with the "searchCatalog" parameter true */ |
return ( DTXGetAPPL(volName, vRefNum, creator, true, |
&(spec->vRefNum), &(spec->parID), spec->name) ); |
} |
/*****************************************************************************/ |
/* |
** FindBundleGivenCreator |
** |
** Search the current resource file for the 'BNDL' resource with the given |
** creator and return a handle to it. |
*/ |
static OSErr FindBundleGivenCreator(OSType creator, |
BNDLRecHandle *returnBndl) |
{ |
OSErr error; |
short numOfBundles; |
short index; |
BNDLRecHandle theBndl; |
error = afpItemNotFound; /* default to not found */ |
/* Search each BNDL resource until we find the one with a matching creator. */ |
numOfBundles = Count1Resources(kBNDLResType); |
index = 1; |
*returnBndl = NULL; |
while ( (index <= numOfBundles) && (*returnBndl == NULL) ) |
{ |
theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index); |
if ( theBndl != NULL ) |
{ |
if ( (*theBndl)->signature == creator ) |
{ |
/* numTypes and typeArray->count will always be the actual count minus 1, */ |
/* so 0 in both fields is valid. */ |
if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) ) |
{ |
/* got it */ |
*returnBndl = theBndl; |
error = noErr; |
} |
} |
} |
index ++; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** FindTypeInBundle |
** |
** Given a Handle to a BNDL return a pointer to the desired type |
** in it. If the type is not found, or if the type's count < 0, |
** return afpItemNotFound. |
*/ |
static OSErr FindTypeInBundle(OSType typeToFind, |
BNDLRecHandle theBndl, |
BundleTypePtr *returnBundleType) |
{ |
OSErr error; |
short index; |
Ptr ptrIterator; /* use a Ptr so we can do ugly pointer math */ |
error = afpItemNotFound; /* default to not found */ |
ptrIterator = (Ptr)((*theBndl)->typeArray); |
index = 0; |
*returnBundleType = NULL; |
while ( (index < ((*theBndl)->numTypes + 1)) && |
(*returnBundleType == NULL) ) |
{ |
if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) && |
(((BundleTypePtr)ptrIterator)->count >= 0) ) |
{ |
*returnBundleType = (BundleTypePtr)ptrIterator; |
error = noErr; |
} |
else |
{ |
ptrIterator += ( sizeof(OSType) + |
sizeof(short) + |
( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) ); |
++index; |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** GetLocalIDFromFREF |
** |
** Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource |
** looking for a matching fileType. If a matching fileType is found, return |
** its icon local ID. If no match is found, return afpItemNotFound as the |
** function result. |
*/ |
static OSErr GetLocalIDFromFREF(BundleTypePtr theBundleType, |
OSType fileType, |
short *iconLocalID) |
{ |
OSErr error; |
short index; |
IDRecPtr idIterator; |
FREFRecHandle theFref; |
error = afpItemNotFound; /* default to not found */ |
/* For each localID in this type, get the FREF resource looking for fileType */ |
index = 0; |
idIterator = &theBundleType->idArray[0]; |
*iconLocalID = 0; |
while ( (index <= theBundleType->count) && (*iconLocalID == 0) ) |
{ |
theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID); |
if ( theFref != NULL ) |
{ |
if ( (*theFref)->fileType == fileType ) |
{ |
*iconLocalID = (*theFref)->iconID; |
error = noErr; |
} |
} |
++idIterator; |
++index; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** GetIconRsrcIDFromLocalID |
** |
** Given a pointer to a 'ICN#' BundleType record, look for the IDRec with |
** the localID that matches iconLocalID. If a matching IDRec is found, |
** return the IDRec's rsrcID field value. If no match is found, return |
** afpItemNotFound as the function result. |
*/ |
static OSErr GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType, |
short iconLocalID, |
short *iconRsrcID) |
{ |
OSErr error; |
short index; |
IDRecPtr idIterator; |
error = afpItemNotFound; /* default to not found */ |
/* Find the rsrcID of the icon family type, given the localID */ |
index = 0; |
idIterator = &theBundleType->idArray[0]; |
*iconRsrcID = 0; |
while ( (index <= theBundleType->count) && (*iconRsrcID == 0) ) |
{ |
if ( idIterator->localID == iconLocalID ) |
{ |
*iconRsrcID = idIterator->rsrcID; |
error = noErr; |
} |
idIterator ++; |
index ++; |
} |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** DTIconToResIcon |
** |
** Map a Desktop Manager icon type to the corresponding resource type. |
** Return (OSType)0 if there is no corresponding resource type. |
*/ |
static OSType DTIconToResIcon(short iconType) |
{ |
OSType resType; |
switch ( iconType ) |
{ |
case kLargeIcon: |
resType = large1BitMask; |
break; |
case kLarge4BitIcon: |
resType = large4BitData; |
break; |
case kLarge8BitIcon: |
resType = large8BitData; |
break; |
case kSmallIcon: |
resType = small1BitMask; |
break; |
case kSmall4BitIcon: |
resType = small4BitData; |
break; |
case kSmall8BitIcon: |
resType = small8BitData; |
break; |
default: |
resType = (OSType)0; |
break; |
} |
return ( resType ); |
} |
/*****************************************************************************/ |
/* |
** GetIconFromDesktopFile |
** |
** INPUT a pointer to a non-existent Handle, because we'll allocate one |
** |
** search each BNDL resource for the right fileCreator and once we get it |
** find the 'FREF' type in BNDL |
** for each localID in the type, open the FREF resource |
** if the FREF is the desired fileType |
** get its icon localID |
** get the ICN# type in BNDL |
** get the icon resource number from the icon localID |
** get the icon resource type from the desktop mgr's iconType |
** get the icon of that type and number |
*/ |
static OSErr GetIconFromDesktopFile(ConstStr255Param volName, |
short vRefNum, |
short iconType, |
OSType fileCreator, |
OSType fileType, |
Handle *iconHandle) |
{ |
OSErr error; |
short realVRefNum; |
Str255 desktopName; |
short savedResFile; |
short dfRefNum; |
BNDLRecHandle theBndl = NULL; |
BundleTypePtr theBundleType; |
short iconLocalID; |
short iconRsrcID; |
OSType iconRsrcType; |
Handle returnIconHandle; |
char bndlState; |
*iconHandle = NULL; |
error = DetermineVRefNum(volName, vRefNum, &realVRefNum); |
if ( error == noErr ) |
{ |
error = GetDesktopFileName(realVRefNum, desktopName); |
if ( error == noErr ) |
{ |
savedResFile = CurResFile(); |
/* |
** Open the 'Desktop' file in the root directory. (because |
** opening the resource file could preload unwanted resources, |
** bracket the call with SetResLoad(s)) |
*/ |
SetResLoad(false); |
dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm); |
SetResLoad(true); |
if ( dfRefNum != -1 ) |
{ |
/* |
** Find the BNDL resource with the specified creator. |
*/ |
error = FindBundleGivenCreator(fileCreator, &theBndl); |
if ( error == noErr ) |
{ |
/* Lock the BNDL resource so it won't be purged when other resources are loaded */ |
bndlState = HGetState((Handle)theBndl); |
HLock((Handle)theBndl); |
/* Find the 'FREF' BundleType record in the BNDL resource. */ |
error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType); |
if ( error == noErr ) |
{ |
/* Find the local ID in the 'FREF' resource with the specified fileType */ |
error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID); |
if ( error == noErr ) |
{ |
/* Find the 'ICN#' BundleType record in the BNDL resource. */ |
error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType); |
if ( error == noErr ) |
{ |
/* Find the icon's resource ID in the 'ICN#' BundleType record */ |
error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID); |
if ( error == noErr ) |
{ |
/* Map Desktop Manager icon type to resource type */ |
iconRsrcType = DTIconToResIcon(iconType); |
if ( iconRsrcType != (OSType)0 ) |
{ |
/* Load the icon */ |
returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID); |
if ( returnIconHandle != NULL ) |
{ |
/* Copy the resource handle, and return the copy */ |
HandToHand(&returnIconHandle); |
if ( MemError() == noErr ) |
{ |
*iconHandle = returnIconHandle; |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
} |
} |
} |
} |
/* Restore the state of the BNDL resource */ |
HSetState((Handle)theBndl, bndlState); |
} |
/* Restore the resource chain and close the Desktop file */ |
UseResFile(savedResFile); |
CloseResFile(dfRefNum); |
} |
else |
{ |
error = ResError(); /* could not open Desktop file */ |
} |
} |
if ( (error != noErr) && (error != memFullErr) ) |
{ |
error = afpItemNotFound; /* force an error we should return */ |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DTGetIcon(ConstStr255Param volName, |
short vRefNum, |
short iconType, |
OSType fileCreator, |
OSType fileType, |
Handle *iconHandle) |
{ |
OSErr error; |
DTPBRec pb; |
short dtRefNum; |
Boolean newDTDatabase; |
Size bufferSize; |
*iconHandle = NULL; |
error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase); |
if ( error == noErr ) |
{ |
/* there was a desktop database and it's now open */ |
if ( !newDTDatabase ) /* don't bother to look in a new (empty) database */ |
{ |
/* get the buffer size for the requested icon type */ |
switch ( iconType ) |
{ |
case kLargeIcon: |
bufferSize = kLargeIconSize; |
break; |
case kLarge4BitIcon: |
bufferSize = kLarge4BitIconSize; |
break; |
case kLarge8BitIcon: |
bufferSize = kLarge8BitIconSize; |
break; |
case kSmallIcon: |
bufferSize = kSmallIconSize; |
break; |
case kSmall4BitIcon: |
bufferSize = kSmall4BitIconSize; |
break; |
case kSmall8BitIcon: |
bufferSize = kSmall8BitIconSize; |
break; |
default: |
iconType = 0; |
bufferSize = 0; |
break; |
} |
if ( bufferSize != 0 ) |
{ |
*iconHandle = NewHandle(bufferSize); |
if ( *iconHandle != NULL ) |
{ |
HLock(*iconHandle); |
pb.ioDTRefNum = dtRefNum; |
pb.ioTagInfo = 0; |
pb.ioDTBuffer = **iconHandle; |
pb.ioDTReqCount = bufferSize; |
pb.ioIconType = iconType; |
pb.ioFileCreator = fileCreator; |
pb.ioFileType = fileType; |
error = PBDTGetIconSync(&pb); |
HUnlock(*iconHandle); |
if ( error != noErr ) |
{ |
DisposeHandle(*iconHandle); /* dispose of the allocated memory */ |
*iconHandle = NULL; |
} |
} |
else |
{ |
error = memFullErr; /* handle could not be allocated */ |
} |
} |
else |
{ |
error = paramErr; /* unknown icon type requested */ |
} |
} |
else |
{ |
error = afpItemNotFound; /* the desktop database was empty - nothing to return */ |
} |
} |
else |
{ |
/* There is no desktop database - try the Desktop file */ |
error = GetIconFromDesktopFile(volName, vRefNum, iconType, |
fileCreator, fileType, iconHandle); |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DTSetComment(short vRefNum, |
long dirID, |
ConstStr255Param name, |
ConstStr255Param comment) |
{ |
DTPBRec pb; |
OSErr error; |
short dtRefNum; |
Boolean newDTDatabase; |
error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase); |
if ( error == noErr ) |
{ |
pb.ioDTRefNum = dtRefNum; |
pb.ioNamePtr = (StringPtr)name; |
pb.ioDirID = dirID; |
pb.ioDTBuffer = (Ptr)&comment[1]; |
/* Truncate the comment to 200 characters just in case */ |
/* some file system doesn't range check */ |
if ( comment[0] <= 200 ) |
{ |
pb.ioDTReqCount = comment[0]; |
} |
else |
{ |
pb.ioDTReqCount = 200; |
} |
error = PBDTSetCommentSync(&pb); |
} |
return (error); |
} |
/*****************************************************************************/ |
pascal OSErr FSpDTSetComment(const FSSpec *spec, |
ConstStr255Param comment) |
{ |
return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment)); |
} |
/*****************************************************************************/ |
/* |
** GetCommentID |
** |
** Get the comment ID number for the Desktop file's 'FCMT' resource ID from |
** the file or folders fdComment (frComment) field. |
*/ |
static OSErr GetCommentID(short vRefNum, |
long dirID, |
ConstStr255Param name, |
short *commentID) |
{ |
CInfoPBRec pb; |
OSErr error; |
error = GetCatInfoNoName(vRefNum, dirID, name, &pb); |
*commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment; |
return ( error ); |
} |
/*****************************************************************************/ |
/* |
** GetCommentFromDesktopFile |
** |
** Get a file or directory's Finder comment field (if any) from the |
** Desktop file's 'FCMT' resources. |
*/ |
static OSErr GetCommentFromDesktopFile(short vRefNum, |
long dirID, |
ConstStr255Param name, |
Str255 comment) |
{ |
OSErr error; |
short commentID; |
short realVRefNum; |
Str255 desktopName; |
short savedResFile; |
short dfRefNum; |
StringHandle commentHandle; |
/* Get the comment ID number */ |
error = GetCommentID(vRefNum, dirID, name, &commentID); |
if ( error == noErr ) |
{ |
if ( commentID != 0 ) /* commentID == 0 means there's no comment */ |
{ |
error = DetermineVRefNum(name, vRefNum, &realVRefNum); |
if ( error == noErr ) |
{ |
error = GetDesktopFileName(realVRefNum, desktopName); |
if ( error == noErr ) |
{ |
savedResFile = CurResFile(); |
/* |
** Open the 'Desktop' file in the root directory. (because |
** opening the resource file could preload unwanted resources, |
** bracket the call with SetResLoad(s)) |
*/ |
SetResLoad(false); |
dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm); |
SetResLoad(true); |
if ( dfRefNum != -1) |
{ |
/* Get the comment resource */ |
commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID); |
if ( commentHandle != NULL ) |
{ |
if ( InlineGetHandleSize((Handle)commentHandle) > 0 ) |
{ |
BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1); |
} |
else |
{ |
error = afpItemNotFound; /* no comment available */ |
} |
} |
else |
{ |
error = afpItemNotFound; /* no comment available */ |
} |
/* restore the resource chain and close the Desktop file */ |
UseResFile(savedResFile); |
CloseResFile(dfRefNum); |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
else |
{ |
error = afpItemNotFound; |
} |
} |
} |
else |
{ |
error = afpItemNotFound; /* no comment available */ |
} |
} |
return ( error ); |
} |
/*****************************************************************************/ |
pascal OSErr DTGetComment(short vRefNum, |
long dirID, |
ConstStr255Param name, |
Str255 comment) |
{ |
DTPBRec pb; |
OSErr error; |
short dtRefNum; |
Boolean newDTDatabase; |
if (comment != NULL) |
{ |
comment[0] = 0; /* return nothing by default */ |
/* attempt to open the desktop database */ |
error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase); |
if ( error == noErr ) |
{ |
/* There was a desktop database and it's now open */ |
if ( !newDTDatabase ) |
{ |
pb.ioDTRefNum = dtRefNum; |
pb.ioNamePtr = (StringPtr)name; |
pb.ioDirID = dirID; |
pb.ioDTBuffer = (Ptr)&comment[1]; |
/* |
** IMPORTANT NOTE #1: Inside Macintosh says that comments |
** are up to 200 characters. While that may be correct for |
** the HFS file system's Desktop Manager, other file |
** systems (such as Apple Photo Access) return up to |
** 255 characters. Make sure the comment buffer is a Str255 |
** or you'll regret it. |
** |
** IMPORTANT NOTE #2: Although Inside Macintosh doesn't |
** mention it, ioDTReqCount is a input field to |
** PBDTGetCommentSync. Some file systems (like HFS) ignore |
** ioDTReqCount and always return the full comment -- |
** others (like AppleShare) respect ioDTReqCount and only |
** return up to ioDTReqCount characters of the comment. |
*/ |
pb.ioDTReqCount = sizeof(Str255) - 1; |
error = PBDTGetCommentSync(&pb); |
if (error == noErr) |
{ |
comment[0] = (unsigned char)pb.ioDTActCount; |
} |
} |
} |
else |
{ |
/* There is no desktop database - try the Desktop file */ |
error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment); |
if ( error != noErr ) |
{ |
error = afpItemNotFound; /* return an expected error */ |
} |
} |
} |
else |
{ |
error = paramErr; |
} |
return (error); |
} |
/*****************************************************************************/ |
pascal OSErr FSpDTGetComment(const FSSpec *spec, |
Str255 comment) |
{ |
return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment)); |
} |
/*****************************************************************************/ |
pascal OSErr DTCopyComment(short srcVRefNum, |
long srcDirID, |
ConstStr255Param srcName, |
short dstVRefNum, |
long dstDirID, |
ConstStr255Param dstName) |
/* The destination volume must support the Desktop Manager for this to work */ |
{ |
OSErr error; |
Str255 comment; |
error = DTGetComment(srcVRefNum, srcDirID, srcName, comment); |
if ( (error == noErr) && (comment[0] > 0) ) |
{ |
error = DTSetComment(dstVRefNum, dstDirID, dstName, comment); |
} |
return (error); |
} |
/*****************************************************************************/ |
pascal OSErr FSpDTCopyComment(const FSSpec *srcSpec, |
const FSSpec *dstSpec) |
/* The destination volume must support the Desktop Manager for this to work */ |
{ |
return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, |
dstSpec->vRefNum, dstSpec->parID, dstSpec->name)); |
} |
/*****************************************************************************/ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-13