4         Contains:       A collection of useful high-level Desktop Manager routines. 
   5                                 If the Desktop Manager is not available, use the Desktop file 
  10         Copyright:      © 1992-2001 by Apple Computer, Inc., all rights reserved. 
  12         You may incorporate this sample code into your applications without 
  13         restriction, though the sample code has been provided "AS IS" and the 
  14         responsibility for its operation is 100% yours.  However, what you are 
  15         not permitted to do is to redistribute the source as "DSC Sample Code" 
  16         after having made changes. If you're going to re-distribute the source, 
  17         we require that you make it clear in the source that the code was 
  18         descended from Apple Sample Code, but that you've made changes. 
  22                 DRI:                            Apple Macintosh Developer Technical Support 
  24                 Other Contact:          Apple Macintosh Developer Technical Support 
  25                                                         <http://developer.apple.com/bugreporter/> 
  27                 Technology:                     DTS Sample Code 
  34         Change History (most recent first): 
  36                  <2>      2/7/01        JL              Added standard header. Updated names of includes. Updated 
  37                                                                         various routines to use new calling convention of the 
  38                                                                         MoreFilesExtras accessor functions. 
  39                 <1>             12/06/99        JL              MoreFiles 1.5. 
  43 #include <MacErrors.h> 
  44 #include <MacMemory.h> 
  46 #include <Resources.h> 
  49 #define __COMPILINGMOREFILES 
  51 #include "MoreFiles.h" 
  52 #include "MoreFilesExtras.h" 
  54 #include "MoreDesktopMgr.h" 
  56 /*****************************************************************************/ 
  58 /*      Desktop file notes: 
  60 **      ¥      The Desktop file is owned by the Finder and is normally open by the 
  61 **              Finder. That means that we only have read-only access to the Desktop 
  63 **      ¥      Since the Resource Manager doesn't support shared access to resource 
  64 **              files and we're using read-only access, we don't ever leave the 
  65 **              Desktop file open.  We open a path to it, get the data we want out 
  66 **              of it, and then close the open path. This is the only safe way to 
  67 **              open a resource file with read-only access since some other program 
  68 **              could have it open with write access. 
  69 **      ¥      The bundle related resources in the Desktop file are normally 
  70 **              purgable, so when we're looking through them, we don't bother to 
  71 **              release resources we're done looking at - closing the resource file 
  72 **              (which we always do) will release them. 
  73 **      ¥      Since we can't assume the Desktop file is named "Desktop" 
  74 **              (it probably is everywhere but France), we get the Desktop 
  75 **              file's name by searching the volume's root directory for a file 
  76 **              with fileType == 'FNDR' and creator == 'ERIK'. The only problem with 
  77 **              this scheme is that someone could create another file with that type 
  78 **              and creator in the root directory and we'd find the wrong file. 
  79 **              The chances of this are very slim. 
  82 /*****************************************************************************/ 
  88         kBNDLResType    
= 'BNDL', 
  89         kFREFResType    
= 'FREF', 
  90         kIconFamResType 
= 'ICN#', 
  91         kFCMTResType    
= 'FCMT', 
  95 /*****************************************************************************/ 
  97 /* local data structures */ 
  99 #if PRAGMA_STRUCT_ALIGN 
 100 #pragma options align=mac68k 
 108 typedef struct IDRec IDRec
; 
 109 typedef IDRec 
*IDRecPtr
; 
 113         OSType          type
;                   /* 'ICN#' or 'FREF' */ 
 114         short           count
;                  /* number of IDRecs - 1 */ 
 117 typedef struct BundleType BundleType
; 
 118 typedef BundleType 
*BundleTypePtr
; 
 122         OSType          signature
;              /* creator type signature */ 
 123         short           versionID
;              /* version - should always be 0 */ 
 124         short           numTypes
;               /* number of elements in typeArray - 1 */ 
 125         BundleType      typeArray
[1]; 
 127 typedef struct BNDLRec BNDLRec
; 
 128 typedef BNDLRec 
**BNDLRecHandle
; 
 132         OSType          fileType
;               /* file type */ 
 133         short           iconID
;                 /* icon local ID */ 
 134         Str255          fileName
;               /* file name */ 
 136 typedef struct FREFRec FREFRec
; 
 137 typedef FREFRec 
**FREFRecHandle
; 
 141         OSType          creator
;                /* creator type signature */ 
 142         long            parID
;                  /* parent directory ID */ 
 143         Str255          applName
;               /* application name */ 
 145 typedef struct APPLRec APPLRec
; 
 146 typedef APPLRec 
*APPLRecPtr
; 
 148 #if PRAGMA_STRUCT_ALIGN 
 149 #pragma options align=reset 
 152 /*****************************************************************************/ 
 154 /* static prototypes */ 
 156 static  OSErr   
GetDesktopFileName(short vRefNum
, 
 159 static  OSErr   
GetAPPLFromDesktopFile(ConstStr255Param volName
, 
 166 static  OSErr   
FindBundleGivenCreator(OSType creator
, 
 167                                                                            BNDLRecHandle 
*returnBndl
); 
 169 static  OSErr   
FindTypeInBundle(OSType typeToFind
, 
 170                                                                  BNDLRecHandle theBndl
, 
 171                                                                  BundleTypePtr 
*returnBundleType
); 
 173 static  OSErr   
GetLocalIDFromFREF(BundleTypePtr theBundleType
, 
 177 static  OSErr   
GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType
, 
 181 static  OSType  
DTIconToResIcon(short iconType
); 
 183 static  OSErr   
GetIconFromDesktopFile(ConstStr255Param volName
, 
 190 static  OSErr   
GetCommentID(short vRefNum
, 
 192                                                          ConstStr255Param name
, 
 195 static  OSErr   
GetCommentFromDesktopFile(short vRefNum
, 
 197                                                                                   ConstStr255Param name
, 
 200 /*****************************************************************************/ 
 203 **      GetDesktopFileName 
 205 **      Get the name of the Desktop file. 
 207 static  OSErr   
GetDesktopFileName(short vRefNum
, 
 215         pb
.fileParam
.ioNamePtr 
= desktopName
; 
 216         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
 217         pb
.fileParam
.ioFVersNum 
= 0; 
 222                 pb
.fileParam
.ioDirID 
= fsRtDirID
; 
 223                 pb
.fileParam
.ioFDirIndex 
= index
; 
 224                 error 
= PBHGetFInfoSync(&pb
); 
 225                 if ( error 
== noErr 
) 
 227                         if ( (pb
.fileParam
.ioFlFndrInfo
.fdType 
== 'FNDR') && 
 228                                  (pb
.fileParam
.ioFlFndrInfo
.fdCreator 
== 'ERIK') ) 
 234         } while ( (error 
== noErr
) && !found 
); 
 239 /*****************************************************************************/ 
 241 pascal  OSErr   
DTOpen(ConstStr255Param volName
, 
 244                                            Boolean 
*newDTDatabase
) 
 247         GetVolParmsInfoBuffer volParmsInfo
; 
 251         /* Check for volume Desktop Manager support before calling */ 
 252         infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
 253         error 
= HGetVolParms(volName
, vRefNum
, &volParmsInfo
, &infoSize
); 
 254         if ( error 
== noErr 
) 
 256                 if ( hasDesktopMgr(&volParmsInfo
) ) 
 258                         pb
.ioNamePtr 
= (StringPtr
)volName
; 
 259                         pb
.ioVRefNum 
= vRefNum
; 
 260                         error 
= PBDTOpenInform(&pb
); 
 261                         /* PBDTOpenInform informs us if the desktop was just created */ 
 262                         /* by leaving the low bit of ioTagInfo clear (0) */ 
 263                         *newDTDatabase 
= ((pb
.ioTagInfo 
& 1L) == 0); 
 264                         if ( error 
== paramErr 
) 
 266                                 error 
= PBDTGetPath(&pb
); 
 267                                 /* PBDTGetPath doesn't tell us if the database is new */ 
 268                                 /* so assume it is not new */ 
 269                                 *newDTDatabase 
= false; 
 271                         *dtRefNum 
= pb
.ioDTRefNum
; 
 281 /*****************************************************************************/ 
 284 **      GetAPPLFromDesktopFile 
 286 **      Get a application's location from the 
 287 **      Desktop file's 'APPL' resources. 
 289 static  OSErr   
GetAPPLFromDesktopFile(ConstStr255Param volName
, 
 301         Handle applResHandle
; 
 302         Boolean foundCreator
; 
 306         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 307         if ( error 
== noErr 
) 
 309                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
 310                 if ( error 
== noErr 
) 
 312                         savedResFile 
= CurResFile(); 
 314                         **      Open the 'Desktop' file in the root directory. (because 
 315                         **      opening the resource file could preload unwanted resources, 
 316                         **      bracket the call with SetResLoad(s)) 
 319                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
 324                                 /* Get 'APPL' resource ID 0 */ 
 325                                 applResHandle 
= Get1Resource(kAPPLResType
, 0); 
 326                                 if ( applResHandle 
!= NULL 
) 
 328                                         applSize 
= GetHandleSize((Handle
)applResHandle
); 
 329                                         if ( applSize 
!= 0 )    /* make sure the APPL resource isn't empty */ 
 331                                                 foundCreator 
= false; 
 332                                                 applPtr 
= *applResHandle
; 
 334                                                 /* APPL's don't have a count so I have to use the size as the bounds */ 
 335                                                 while ( (foundCreator 
== false) && 
 336                                                                 (applPtr 
< (*applResHandle 
+ applSize
)) ) 
 338                                                         if ( ((APPLRecPtr
)applPtr
)->creator 
== creator 
) 
 344                                                                 /* fun with pointer math... */ 
 345                                                                 applPtr 
+= sizeof(OSType
) + 
 347                                                                                    ((APPLRecPtr
)applPtr
)->applName
[0] + 1; 
 348                                                                 /* application mappings are word aligned within the resource */ 
 349                                                                 if ( ((unsigned long)applPtr 
% 2) != 0 ) 
 355                                                 if ( foundCreator 
== true ) 
 357                                                         *applVRefNum 
= realVRefNum
; 
 358                                                         *applParID 
= ((APPLRecPtr
)applPtr
)->parID
; 
 359                                                         BlockMoveData(((APPLRecPtr
)applPtr
)->applName
, 
 361                                                                                   ((APPLRecPtr
)applPtr
)->applName
[0] + 1); 
 362                                                         /* error is already noErr */ 
 366                                                         error 
= afpItemNotFound
;        /* didn't find a creator match */ 
 371                                                 error 
= afpItemNotFound
;        /* no APPL mapping available */ 
 376                                         error 
= afpItemNotFound
;        /* no APPL mapping available */ 
 379                                 /* restore the resource chain and close the Desktop file */ 
 380                                 UseResFile(savedResFile
); 
 381                                 CloseResFile(dfRefNum
); 
 385                                 error 
= afpItemNotFound
; 
 393 /*****************************************************************************/ 
 395 pascal  OSErr   
DTXGetAPPL(ConstStr255Param volName
, 
 398                                                    Boolean searchCatalog
, 
 406         Boolean newDTDatabase
; 
 413         /* get the real vRefNum */ 
 414         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 415         if ( error 
== noErr 
) 
 417                 error 
= DTOpen(volName
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
 418                 if ( error 
== noErr 
) 
 420                         if ( !newDTDatabase 
) 
 426                                         pb
.dtPB
.ioNamePtr 
= applName
; 
 427                                         pb
.dtPB
.ioDTRefNum 
= dtRefNum
; 
 428                                         pb
.dtPB
.ioIndex 
= index
; 
 429                                         pb
.dtPB
.ioFileCreator 
= creator
; 
 430                                         error 
= PBDTGetAPPLSync(&pb
.dtPB
); 
 431                                         if ( error 
== noErr 
) 
 433                                                 /* got a match - see if it is valid */ 
 435                                                 *applVRefNum 
= realVRefNum
; /* get the vRefNum now */ 
 436                                                 *applParID 
= pb
.dtPB
.ioAPPLParID
; /* get the parent ID now */ 
 438                                                 /* pb.hPB.fileParam.ioNamePtr is already set */ 
 439                                                 pb
.hPB
.fileParam
.ioVRefNum 
= realVRefNum
; 
 440                                                 pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
 441                                                 pb
.hPB
.fileParam
.ioDirID 
= *applParID
; 
 442                                                 pb
.hPB
.fileParam
.ioFDirIndex 
= 0;       /* use ioNamePtr and ioDirID */ 
 443                                                 if ( PBHGetFInfoSync(&pb
.hPB
) == noErr 
) 
 445                                                         if ( (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdCreator 
== creator
) && 
 446                                                                  (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdType 
== 'APPL') ) 
 453                                 } while ( (error 
== noErr
) && !applFound 
); 
 454                                 if ( error 
!= noErr 
) 
 456                                         error 
= afpItemNotFound
; 
 461                                 /* Desktop database is empty (new), set error to try CatSearch */ 
 462                                 error 
= afpItemNotFound
; 
 465                 /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */ 
 466                 if ( error 
== paramErr 
) 
 468                         /* if paramErr, the volume didn't support the Desktop Manager */ 
 469                         /* try the Desktop file */ 
 471                         error 
= GetAPPLFromDesktopFile(volName
, vRefNum
, creator
, 
 472                                                                                         applVRefNum
, applParID
, applName
); 
 473                         if ( error 
== noErr 
) 
 475                                 /* got a match - see if it is valid */ 
 477                                 pb
.hPB
.fileParam
.ioNamePtr 
= applName
; 
 478                                 pb
.hPB
.fileParam
.ioVRefNum 
= *applVRefNum
; 
 479                                 pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
 480                                 pb
.hPB
.fileParam
.ioDirID 
= *applParID
; 
 481                                 pb
.hPB
.fileParam
.ioFDirIndex 
= 0;       /* use ioNamePtr and ioDirID */ 
 482                                 if ( PBHGetFInfoSync(&pb
.hPB
) == noErr 
) 
 484                                         if ( (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdCreator 
!= creator
) || 
 485                                                  (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdType 
!= 'APPL') ) 
 487                                                 error 
= afpItemNotFound
; 
 490                                 else if ( error 
== fnfErr 
) 
 492                                         error 
= afpItemNotFound
; 
 496                 /* acceptable error from DesktopFile code to continue is afpItemNotFound */ 
 497                 if ( (error 
== afpItemNotFound
) && searchCatalog
) 
 499                         /* Couldn't be found in the Desktop file either, */ 
 500                         /* try searching with CatSearch if requested */ 
 502                         error 
= CreatorTypeFileSearch(NULL
, realVRefNum
, creator
, kAPPLResType
, &spec
, 1, 
 503                                                                                         &actMatchCount
, true); 
 504                         if ( (error 
== noErr
) || (error 
== eofErr
) ) 
 506                                 if ( actMatchCount 
> 0 ) 
 508                                         *applVRefNum 
= spec
.vRefNum
; 
 509                                         *applParID 
= spec
.parID
; 
 510                                         BlockMoveData(spec
.name
, applName
, spec
.name
[0] + 1); 
 514                                         error 
= afpItemNotFound
; 
 523 /*****************************************************************************/ 
 525 pascal  OSErr   
FSpDTXGetAPPL(ConstStr255Param volName
, 
 528                                                           Boolean searchCatalog
, 
 531         return ( DTXGetAPPL(volName
, vRefNum
, creator
, searchCatalog
, 
 532                                                 &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
 535 /*****************************************************************************/ 
 537 pascal  OSErr   
DTGetAPPL(ConstStr255Param volName
, 
 544         /* Call DTXGetAPPL with the "searchCatalog" parameter true */  
 545         return ( DTXGetAPPL(volName
, vRefNum
, creator
, true, 
 546                                                 applVRefNum
, applParID
, applName
) ); 
 549 /*****************************************************************************/ 
 551 pascal  OSErr   
FSpDTGetAPPL(ConstStr255Param volName
, 
 556         /* Call DTXGetAPPL with the "searchCatalog" parameter true */  
 557         return ( DTXGetAPPL(volName
, vRefNum
, creator
, true, 
 558                                                 &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
 561 /*****************************************************************************/ 
 564 **      FindBundleGivenCreator 
 566 **      Search the current resource file for the 'BNDL' resource with the given 
 567 **      creator and return a handle to it. 
 569 static  OSErr   
FindBundleGivenCreator(OSType creator
, 
 570                                                                            BNDLRecHandle 
*returnBndl
) 
 575         BNDLRecHandle   theBndl
; 
 577         error 
= afpItemNotFound
;        /* default to not found */ 
 579         /* Search each BNDL resource until we find the one with a matching creator. */ 
 581         numOfBundles 
= Count1Resources(kBNDLResType
); 
 585         while ( (index 
<= numOfBundles
) && (*returnBndl 
== NULL
) ) 
 587                 theBndl 
= (BNDLRecHandle
)Get1IndResource(kBNDLResType
, index
); 
 589                 if ( theBndl 
!= NULL 
) 
 591                         if ( (*theBndl
)->signature 
== creator 
) 
 593                                 /* numTypes and typeArray->count will always be the actual count minus 1, */ 
 594                                 /* so 0 in both fields is valid. */ 
 595                                 if ( ((*theBndl
)->numTypes 
>= 0) && ((*theBndl
)->typeArray
->count 
>= 0) ) 
 598                                         *returnBndl 
= theBndl
; 
 610 /*****************************************************************************/ 
 615 **      Given a Handle to a BNDL return a pointer to the desired type 
 616 **      in it. If the type is not found, or if the type's count < 0, 
 617 **      return afpItemNotFound. 
 619 static  OSErr   
FindTypeInBundle(OSType typeToFind
, 
 620                                                                  BNDLRecHandle theBndl
, 
 621                                                                  BundleTypePtr 
*returnBundleType
) 
 625         Ptr                             ptrIterator
;    /* use a Ptr so we can do ugly pointer math */ 
 627         error 
= afpItemNotFound
;        /* default to not found */ 
 629         ptrIterator 
= (Ptr
)((*theBndl
)->typeArray
); 
 631         *returnBundleType 
= NULL
; 
 633         while ( (index 
< ((*theBndl
)->numTypes 
+ 1)) && 
 634                         (*returnBundleType 
== NULL
) ) 
 636                 if ( (((BundleTypePtr
)ptrIterator
)->type 
== typeToFind
) && 
 637                          (((BundleTypePtr
)ptrIterator
)->count 
>= 0) ) 
 639                                 *returnBundleType 
= (BundleTypePtr
)ptrIterator
; 
 644                         ptrIterator 
+= ( sizeof(OSType
) + 
 646                                                          ( sizeof(IDRec
) * (((BundleTypePtr
)ptrIterator
)->count 
+ 1) ) ); 
 654 /*****************************************************************************/ 
 657 **      GetLocalIDFromFREF 
 659 **      Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource 
 660 **      looking for a matching fileType. If a matching fileType is found, return 
 661 **      its icon local ID. If no match is found, return afpItemNotFound as the 
 664 static  OSErr   
GetLocalIDFromFREF(BundleTypePtr theBundleType
, 
 671         FREFRecHandle   theFref
; 
 673         error 
= afpItemNotFound
;        /* default to not found */ 
 675         /* For each localID in this type, get the FREF resource looking for fileType */ 
 677         idIterator 
= &theBundleType
->idArray
[0]; 
 680         while ( (index 
<= theBundleType
->count
) && (*iconLocalID 
== 0) ) 
 682                 theFref 
= (FREFRecHandle
)Get1Resource(kFREFResType
, idIterator
->rsrcID
); 
 683                 if ( theFref 
!= NULL 
) 
 685                         if ( (*theFref
)->fileType 
== fileType 
) 
 687                                 *iconLocalID 
= (*theFref
)->iconID
; 
 699 /*****************************************************************************/ 
 702 **      GetIconRsrcIDFromLocalID 
 704 **      Given a pointer to a 'ICN#' BundleType record, look for the IDRec with 
 705 **      the localID that matches iconLocalID. If a matching IDRec is found, 
 706 **      return the IDRec's rsrcID field value. If no match is found, return 
 707 **      afpItemNotFound as the function result. 
 709 static  OSErr   
GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType
, 
 717         error 
= afpItemNotFound
;        /* default to not found */ 
 719         /* Find the rsrcID of the icon family type, given the localID */ 
 721         idIterator 
= &theBundleType
->idArray
[0]; 
 724         while ( (index 
<= theBundleType
->count
) && (*iconRsrcID 
== 0) ) 
 726                 if ( idIterator
->localID 
== iconLocalID 
) 
 728                         *iconRsrcID 
= idIterator
->rsrcID
; 
 739 /*****************************************************************************/ 
 744 **      Map a Desktop Manager icon type to the corresponding resource type. 
 745 **      Return (OSType)0 if there is no corresponding resource type. 
 747 static  OSType  
DTIconToResIcon(short iconType
) 
 754                         resType 
= large1BitMask
; 
 757                         resType 
= large4BitData
; 
 760                         resType 
= large8BitData
; 
 763                         resType 
= small1BitMask
; 
 766                         resType 
= small4BitData
; 
 769                         resType 
= small8BitData
; 
 779 /*****************************************************************************/ 
 782 **      GetIconFromDesktopFile 
 784 **      INPUT a pointer to a non-existent Handle, because we'll allocate one 
 786 **      search each BNDL resource for the right fileCreator and once we get it 
 787 **              find the 'FREF' type in BNDL 
 788 **              for each localID in the type, open the FREF resource 
 789 **                      if the FREF is the desired fileType 
 790 **                              get its icon localID 
 791 **                              get the ICN# type in BNDL 
 792 **                              get the icon resource number from the icon localID 
 793 **                              get the icon resource type from the desktop mgr's iconType 
 794 **                              get the icon of that type and number 
 796 static  OSErr   
GetIconFromDesktopFile(ConstStr255Param volName
, 
 808         BNDLRecHandle   theBndl 
= NULL
; 
 809         BundleTypePtr   theBundleType
; 
 813         Handle                  returnIconHandle
;        
 818         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 819         if ( error 
== noErr 
) 
 821                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
 822                 if ( error 
== noErr 
) 
 824                         savedResFile 
= CurResFile(); 
 827                         **      Open the 'Desktop' file in the root directory. (because 
 828                         **      opening the resource file could preload unwanted resources, 
 829                         **      bracket the call with SetResLoad(s)) 
 832                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
 835                         if ( dfRefNum 
!= -1 ) 
 838                                 **      Find the BNDL resource with the specified creator. 
 840                                 error 
= FindBundleGivenCreator(fileCreator
, &theBndl
); 
 841                                 if ( error 
== noErr 
) 
 843                                         /* Lock the BNDL resource so it won't be purged when other resources are loaded */ 
 844                                         bndlState 
= HGetState((Handle
)theBndl
); 
 845                                         HLock((Handle
)theBndl
); 
 847                                         /* Find the 'FREF' BundleType record in the BNDL resource. */ 
 848                                         error 
= FindTypeInBundle(kFREFResType
, theBndl
, &theBundleType
); 
 849                                         if ( error 
== noErr 
) 
 851                                                 /* Find the local ID in the 'FREF' resource with the specified fileType */ 
 852                                                 error 
= GetLocalIDFromFREF(theBundleType
, fileType
, &iconLocalID
); 
 853                                                 if ( error 
== noErr 
) 
 855                                                         /* Find the 'ICN#' BundleType record in the BNDL resource. */ 
 856                                                         error 
= FindTypeInBundle(kIconFamResType
, theBndl
, &theBundleType
); 
 857                                                         if ( error 
== noErr 
) 
 859                                                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */ 
 860                                                                 error 
= GetIconRsrcIDFromLocalID(theBundleType
, iconLocalID
, &iconRsrcID
); 
 861                                                                 if ( error 
== noErr 
) 
 863                                                                         /* Map Desktop Manager icon type to resource type */ 
 864                                                                         iconRsrcType 
= DTIconToResIcon(iconType
); 
 866                                                                         if ( iconRsrcType 
!= (OSType
)0 ) 
 869                                                                                 returnIconHandle 
= Get1Resource(iconRsrcType
, iconRsrcID
); 
 870                                                                                 if ( returnIconHandle 
!= NULL 
) 
 872                                                                                         /* Copy the resource handle, and return the copy */ 
 873                                                                                         HandToHand(&returnIconHandle
); 
 874                                                                                         if ( MemError() == noErr 
) 
 876                                                                                                 *iconHandle 
= returnIconHandle
; 
 880                                                                                                 error 
= afpItemNotFound
; 
 885                                                                                         error 
= afpItemNotFound
; 
 892                                         /* Restore the state of the BNDL resource */  
 893                                         HSetState((Handle
)theBndl
, bndlState
); 
 895                                 /* Restore the resource chain and close the Desktop file */ 
 896                                 UseResFile(savedResFile
); 
 897                                 CloseResFile(dfRefNum
); 
 901                                 error 
= ResError(); /* could not open Desktop file */ 
 904                 if ( (error 
!= noErr
) && (error 
!= memFullErr
) ) 
 906                         error 
= afpItemNotFound
;        /* force an error we should return */ 
 913 /*****************************************************************************/ 
 915 pascal  OSErr   
DTGetIcon(ConstStr255Param volName
, 
 925         Boolean newDTDatabase
; 
 929         error 
= DTOpen(volName
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
 930         if ( error 
== noErr 
) 
 932                 /* there was a desktop database and it's now open */ 
 934                 if ( !newDTDatabase 
)   /* don't bother to look in a new (empty) database */ 
 936                         /* get the buffer size for the requested icon type */ 
 940                                         bufferSize 
= kLargeIconSize
; 
 943                                         bufferSize 
= kLarge4BitIconSize
; 
 946                                         bufferSize 
= kLarge8BitIconSize
; 
 949                                         bufferSize 
= kSmallIconSize
; 
 952                                         bufferSize 
= kSmall4BitIconSize
; 
 955                                         bufferSize 
= kSmall8BitIconSize
; 
 962                         if ( bufferSize 
!= 0 ) 
 964                                 *iconHandle 
= NewHandle(bufferSize
); 
 965                                 if ( *iconHandle 
!= NULL 
) 
 969                                         pb
.ioDTRefNum 
= dtRefNum
; 
 971                                         pb
.ioDTBuffer 
= **iconHandle
; 
 972                                         pb
.ioDTReqCount 
= bufferSize
; 
 973                                         pb
.ioIconType 
= iconType
; 
 974                                         pb
.ioFileCreator 
= fileCreator
; 
 975                                         pb
.ioFileType 
= fileType
; 
 976                                         error 
= PBDTGetIconSync(&pb
); 
 978                                         HUnlock(*iconHandle
); 
 980                                         if ( error 
!= noErr 
) 
 982                                                 DisposeHandle(*iconHandle
);     /* dispose of the allocated memory */ 
 988                                         error 
= memFullErr
;     /* handle could not be allocated */ 
 993                                 error 
= paramErr
;       /* unknown icon type requested */ 
 998                         error 
= afpItemNotFound
;        /* the desktop database was empty - nothing to return */ 
1003                 /* There is no desktop database - try the Desktop file */ 
1005                 error 
= GetIconFromDesktopFile(volName
, vRefNum
, iconType
, 
1006                                                                                 fileCreator
, fileType
, iconHandle
); 
1012 /*****************************************************************************/ 
1014 pascal  OSErr   
DTSetComment(short vRefNum
, 
1016                                                          ConstStr255Param name
, 
1017                                                          ConstStr255Param comment
) 
1022         Boolean newDTDatabase
; 
1024         error 
= DTOpen(name
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
1025         if ( error 
== noErr 
) 
1027                 pb
.ioDTRefNum 
= dtRefNum
; 
1028                 pb
.ioNamePtr 
= (StringPtr
)name
; 
1030                 pb
.ioDTBuffer 
= (Ptr
)&comment
[1]; 
1031                 /* Truncate the comment to 200 characters just in case */ 
1032                 /* some file system doesn't range check */ 
1033                 if ( comment
[0] <= 200 ) 
1035                         pb
.ioDTReqCount 
= comment
[0]; 
1039                         pb
.ioDTReqCount 
= 200; 
1041                 error 
= PBDTSetCommentSync(&pb
); 
1046 /*****************************************************************************/ 
1048 pascal  OSErr   
FSpDTSetComment(const FSSpec 
*spec
, 
1049                                                           ConstStr255Param comment
) 
1051         return (DTSetComment(spec
->vRefNum
, spec
->parID
, spec
->name
, comment
)); 
1054 /*****************************************************************************/ 
1059 **      Get the comment ID number for the Desktop file's 'FCMT' resource ID from 
1060 **      the file or folders fdComment (frComment) field. 
1062 static  OSErr   
GetCommentID(short vRefNum
, 
1064                                                          ConstStr255Param name
, 
1070         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1071         *commentID 
= pb
.hFileInfo
.ioFlXFndrInfo
.fdComment
; 
1075 /*****************************************************************************/ 
1078 **      GetCommentFromDesktopFile 
1080 **      Get a file or directory's Finder comment field (if any) from the 
1081 **      Desktop file's 'FCMT' resources. 
1083 static  OSErr   
GetCommentFromDesktopFile(short vRefNum
, 
1085                                                                                   ConstStr255Param name
, 
1094         StringHandle commentHandle
; 
1096         /* Get the comment ID number */ 
1097         error 
= GetCommentID(vRefNum
, dirID
, name
, &commentID
); 
1098         if ( error 
== noErr 
) 
1100                 if ( commentID 
!= 0 )   /* commentID == 0 means there's no comment */ 
1102                         error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1103                         if ( error 
== noErr 
) 
1105                                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
1106                                 if ( error 
== noErr 
) 
1108                                         savedResFile 
= CurResFile(); 
1110                                         **      Open the 'Desktop' file in the root directory. (because 
1111                                         **      opening the resource file could preload unwanted resources, 
1112                                         **      bracket the call with SetResLoad(s)) 
1115                                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
1118                                         if ( dfRefNum 
!= -1) 
1120                                                 /* Get the comment resource */ 
1121                                                 commentHandle 
= (StringHandle
)Get1Resource(kFCMTResType
,commentID
); 
1122                                                 if ( commentHandle 
!= NULL 
) 
1124                                                         if ( GetHandleSize((Handle
)commentHandle
) > 0 ) 
1126                                                                 BlockMoveData(*commentHandle
, comment
, *commentHandle
[0] + 1); 
1130                                                                 error 
= afpItemNotFound
;        /* no comment available */ 
1135                                                         error 
= afpItemNotFound
;        /* no comment available */ 
1138                                                 /* restore the resource chain and close the Desktop file */ 
1139                                                 UseResFile(savedResFile
); 
1140                                                 CloseResFile(dfRefNum
); 
1144                                                 error 
= afpItemNotFound
; 
1149                                         error 
= afpItemNotFound
; 
1155                         error 
= afpItemNotFound
;        /* no comment available */ 
1162 /*****************************************************************************/ 
1164 pascal  OSErr   
DTGetComment(short vRefNum
, 
1166                                                          ConstStr255Param name
, 
1172         Boolean newDTDatabase
; 
1174         if (comment 
!= NULL
) 
1176                 comment
[0] = 0; /* return nothing by default */ 
1178                 /* attempt to open the desktop database */ 
1179                 error 
= DTOpen(name
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
1180                 if ( error 
== noErr 
) 
1182                         /* There was a desktop database and it's now open */ 
1184                         if ( !newDTDatabase 
) 
1186                                 pb
.ioDTRefNum 
= dtRefNum
; 
1187                                 pb
.ioNamePtr 
= (StringPtr
)name
; 
1189                                 pb
.ioDTBuffer 
= (Ptr
)&comment
[1]; 
1191                                 **      IMPORTANT NOTE #1: Inside Macintosh says that comments 
1192                                 **      are up to 200 characters. While that may be correct for 
1193                                 **      the HFS file system's Desktop Manager, other file 
1194                                 **      systems (such as Apple Photo Access) return up to 
1195                                 **      255 characters. Make sure the comment buffer is a Str255 
1196                                 **      or you'll regret it. 
1198                                 **      IMPORTANT NOTE #2: Although Inside Macintosh doesn't 
1199                                 **      mention it, ioDTReqCount is a input field to 
1200                                 **      PBDTGetCommentSync. Some file systems (like HFS) ignore 
1201                                 **      ioDTReqCount and always return the full comment -- 
1202                                 **      others (like AppleShare) respect ioDTReqCount and only 
1203                                 **      return up to ioDTReqCount characters of the comment. 
1205                                 pb
.ioDTReqCount 
= sizeof(Str255
) - 1; 
1206                                 error 
= PBDTGetCommentSync(&pb
); 
1209                                         comment
[0] = (unsigned char)pb
.ioDTActCount
; 
1215                         /* There is no desktop database - try the Desktop file */ 
1216                         error 
= GetCommentFromDesktopFile(vRefNum
, dirID
, name
, comment
); 
1217                         if ( error 
!= noErr 
) 
1219                                 error 
= afpItemNotFound
;        /* return an expected error */ 
1231 /*****************************************************************************/ 
1233 pascal  OSErr   
FSpDTGetComment(const FSSpec 
*spec
, 
1236         return (DTGetComment(spec
->vRefNum
, spec
->parID
, spec
->name
, comment
)); 
1239 /*****************************************************************************/ 
1241 pascal  OSErr   
DTCopyComment(short srcVRefNum
, 
1243                                                           ConstStr255Param srcName
, 
1246                                                           ConstStr255Param dstName
) 
1247 /* The destination volume must support the Desktop Manager for this to work */ 
1252         error 
= DTGetComment(srcVRefNum
, srcDirID
, srcName
, comment
); 
1253         if ( (error 
== noErr
) && (comment
[0] > 0) ) 
1255                 error 
= DTSetComment(dstVRefNum
, dstDirID
, dstName
, comment
); 
1260 /*****************************************************************************/ 
1262 pascal  OSErr   
FSpDTCopyComment(const FSSpec 
*srcSpec
, 
1263                                                            const FSSpec 
*dstSpec
) 
1264 /* The destination volume must support the Desktop Manager for this to work */ 
1266         return (DTCopyComment(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
1267                                                 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
)); 
1270 /*****************************************************************************/