2 **      Apple Macintosh Developer Technical Support 
   4 **      A collection of useful high-level Desktop Manager routines. 
   5 **      If the Desktop Manager isn't available, use the Desktop file 
   6 **      for 'read' operations. 
   8 **      We do more because we can... 
  10 **      by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti 
  12 **      File:   MoreDesktopMgr.c 
  14 **      Copyright © 1992-1998 Apple Computer, Inc. 
  15 **      All rights reserved. 
  17 **      You may incorporate this sample code into your applications without 
  18 **      restriction, though the sample code has been provided "AS IS" and the 
  19 **      responsibility for its operation is 100% yours.  However, what you are 
  20 **      not permitted to do is to redistribute the source as "DSC Sample Code" 
  21 **      after having made changes. If you're going to re-distribute the source, 
  22 **      we require that you make it clear in the source that the code was 
  23 **      descended from Apple Sample Code, but that you've made changes. 
  30 #include <Resources.h> 
  33 #define __COMPILINGMOREFILES 
  40 /*****************************************************************************/ 
  42 /*      Desktop file notes: 
  44 **      ¥      The Desktop file is owned by the Finder and is normally open by the 
  45 **              Finder. That means that we only have read-only access to the Desktop 
  47 **      ¥      Since the Resource Manager doesn't support shared access to resource 
  48 **              files and we're using read-only access, we don't ever leave the 
  49 **              Desktop file open.  We open a path to it, get the data we want out 
  50 **              of it, and then close the open path. This is the only safe way to 
  51 **              open a resource file with read-only access since some other program 
  52 **              could have it open with write access. 
  53 **      ¥      The bundle related resources in the Desktop file are normally 
  54 **              purgable, so when we're looking through them, we don't bother to 
  55 **              release resources we're done looking at - closing the resource file 
  56 **              (which we always do) will release them. 
  57 **      ¥      Since we can't assume the Desktop file is named "Desktop" 
  58 **              (it probably is everywhere but France), we get the Desktop 
  59 **              file's name by searching the volume's root directory for a file 
  60 **              with fileType == 'FNDR' and creator == 'ERIK'. The only problem with 
  61 **              this scheme is that someone could create another file with that type 
  62 **              and creator in the root directory and we'd find the wrong file. 
  63 **              The chances of this are very slim. 
  66 /*****************************************************************************/ 
  72         kBNDLResType    
= 'BNDL', 
  73         kFREFResType    
= 'FREF', 
  74         kIconFamResType 
= 'ICN#', 
  75         kFCMTResType    
= 'FCMT', 
  79 /*****************************************************************************/ 
  81 /* local data structures */ 
  83 #if PRAGMA_ALIGN_SUPPORTED 
  84 #pragma options align=mac68k 
  92 typedef struct IDRec IDRec
; 
  93 typedef IDRec 
*IDRecPtr
; 
  97         OSType          type
;                   /* 'ICN#' or 'FREF' */ 
  98         short           count
;                  /* number of IDRecs - 1 */ 
 101 typedef struct BundleType BundleType
; 
 102 typedef BundleType 
*BundleTypePtr
; 
 106         OSType          signature
;              /* creator type signature */ 
 107         short           versionID
;              /* version - should always be 0 */ 
 108         short           numTypes
;               /* number of elements in typeArray - 1 */ 
 109         BundleType      typeArray
[1]; 
 111 typedef struct BNDLRec BNDLRec
; 
 112 typedef BNDLRec 
**BNDLRecHandle
; 
 116         OSType          fileType
;               /* file type */ 
 117         short           iconID
;                 /* icon local ID */ 
 118         Str255          fileName
;               /* file name */ 
 120 typedef struct FREFRec FREFRec
; 
 121 typedef FREFRec 
**FREFRecHandle
; 
 125         OSType          creator
;                /* creator type signature */ 
 126         long            parID
;                  /* parent directory ID */ 
 127         Str255          applName
;               /* application name */ 
 129 typedef struct APPLRec APPLRec
; 
 130 typedef APPLRec 
*APPLRecPtr
; 
 132 #if PRAGMA_ALIGN_SUPPORTED 
 133 #pragma options align=reset 
 136 /*****************************************************************************/ 
 138 /* static prototypes */ 
 140 static  OSErr   
GetDesktopFileName(short vRefNum
, 
 143 static  OSErr   
GetAPPLFromDesktopFile(ConstStr255Param volName
, 
 150 static  OSErr   
FindBundleGivenCreator(OSType creator
, 
 151                                                                            BNDLRecHandle 
*returnBndl
); 
 153 static  OSErr   
FindTypeInBundle(OSType typeToFind
, 
 154                                                                  BNDLRecHandle theBndl
, 
 155                                                                  BundleTypePtr 
*returnBundleType
); 
 157 static  OSErr   
GetLocalIDFromFREF(BundleTypePtr theBundleType
, 
 161 static  OSErr   
GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType
, 
 165 static  OSType  
DTIconToResIcon(short iconType
); 
 167 static  OSErr   
GetIconFromDesktopFile(ConstStr255Param volName
, 
 174 static  OSErr   
GetCommentID(short vRefNum
, 
 176                                                          ConstStr255Param name
, 
 179 static  OSErr   
GetCommentFromDesktopFile(short vRefNum
, 
 181                                                                                   ConstStr255Param name
, 
 184 /*****************************************************************************/ 
 187 **      GetDesktopFileName 
 189 **      Get the name of the Desktop file. 
 191 static  OSErr   
GetDesktopFileName(short vRefNum
, 
 199         pb
.fileParam
.ioNamePtr 
= desktopName
; 
 200         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
 201         pb
.fileParam
.ioFVersNum 
= 0; 
 206                 pb
.fileParam
.ioDirID 
= fsRtDirID
; 
 207                 pb
.fileParam
.ioFDirIndex 
= index
; 
 208                 error 
= PBHGetFInfoSync(&pb
); 
 209                 if ( error 
== noErr 
) 
 211                         if ( (pb
.fileParam
.ioFlFndrInfo
.fdType 
== 'FNDR') && 
 212                                  (pb
.fileParam
.ioFlFndrInfo
.fdCreator 
== 'ERIK') ) 
 218         } while ( (error 
== noErr
) && !found 
); 
 223 /*****************************************************************************/ 
 225 pascal  OSErr   
DTOpen(ConstStr255Param volName
, 
 228                                            Boolean 
*newDTDatabase
) 
 231         GetVolParmsInfoBuffer volParmsInfo
; 
 235         /* Check for volume Desktop Manager support before calling */ 
 236         infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
 237         error 
= HGetVolParms(volName
, vRefNum
, &volParmsInfo
, &infoSize
); 
 238         if ( error 
== noErr 
) 
 240                 if ( hasDesktopMgr(volParmsInfo
) ) 
 242                         pb
.ioNamePtr 
= (StringPtr
)volName
; 
 243                         pb
.ioVRefNum 
= vRefNum
; 
 244                         error 
= PBDTOpenInform(&pb
); 
 245                         /* PBDTOpenInform informs us if the desktop was just created */ 
 246                         /* by leaving the low bit of ioTagInfo clear (0) */ 
 247                         *newDTDatabase 
= ((pb
.ioTagInfo 
& 1L) == 0); 
 248                         if ( error 
== paramErr 
) 
 250                                 error 
= PBDTGetPath(&pb
); 
 251                                 /* PBDTGetPath doesn't tell us if the database is new */ 
 252                                 /* so assume it is not new */ 
 253                                 *newDTDatabase 
= false; 
 255                         *dtRefNum 
= pb
.ioDTRefNum
; 
 265 /*****************************************************************************/ 
 268 **      GetAPPLFromDesktopFile 
 270 **      Get a application's location from the 
 271 **      Desktop file's 'APPL' resources. 
 273 static  OSErr   
GetAPPLFromDesktopFile(ConstStr255Param volName
, 
 285         Handle applResHandle
; 
 286         Boolean foundCreator
; 
 290         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 291         if ( error 
== noErr 
) 
 293                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
 294                 if ( error 
== noErr 
) 
 296                         savedResFile 
= CurResFile(); 
 298                         **      Open the 'Desktop' file in the root directory. (because 
 299                         **      opening the resource file could preload unwanted resources, 
 300                         **      bracket the call with SetResLoad(s)) 
 303                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
 308                                 /* Get 'APPL' resource ID 0 */ 
 309                                 applResHandle 
= Get1Resource(kAPPLResType
, 0); 
 310                                 if ( applResHandle 
!= NULL 
) 
 312                                         applSize 
= InlineGetHandleSize((Handle
)applResHandle
); 
 313                                         if ( applSize 
!= 0 )    /* make sure the APPL resource isn't empty */ 
 315                                                 foundCreator 
= false; 
 316                                                 applPtr 
= *applResHandle
; 
 318                                                 /* APPL's don't have a count so I have to use the size as the bounds */ 
 319                                                 while ( (foundCreator 
== false) && 
 320                                                                 (applPtr 
< (*applResHandle 
+ applSize
)) ) 
 322                                                         if ( ((APPLRecPtr
)applPtr
)->creator 
== creator 
) 
 328                                                                 /* fun with pointer math... */ 
 329                                                                 applPtr 
+= sizeof(OSType
) + 
 331                                                                                    ((APPLRecPtr
)applPtr
)->applName
[0] + 1; 
 332                                                                 /* application mappings are word aligned within the resource */ 
 333                                                                 if ( ((unsigned long)applPtr 
% 2) != 0 ) 
 339                                                 if ( foundCreator 
== true ) 
 341                                                         *applVRefNum 
= realVRefNum
; 
 342                                                         *applParID 
= ((APPLRecPtr
)applPtr
)->parID
; 
 343                                                         BlockMoveData(((APPLRecPtr
)applPtr
)->applName
, 
 345                                                                                   ((APPLRecPtr
)applPtr
)->applName
[0] + 1); 
 346                                                         /* error is already noErr */ 
 350                                                         error 
= afpItemNotFound
;        /* didn't find a creator match */ 
 355                                                 error 
= afpItemNotFound
;        /* no APPL mapping available */ 
 360                                         error 
= afpItemNotFound
;        /* no APPL mapping available */ 
 363                                 /* restore the resource chain and close the Desktop file */ 
 364                                 UseResFile(savedResFile
); 
 365                                 CloseResFile(dfRefNum
); 
 369                                 error 
= afpItemNotFound
; 
 377 /*****************************************************************************/ 
 379 pascal  OSErr   
DTXGetAPPL(ConstStr255Param volName
, 
 382                                                    Boolean searchCatalog
, 
 390         Boolean newDTDatabase
; 
 397         /* get the real vRefNum */ 
 398         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 399         if ( error 
== noErr 
) 
 401                 error 
= DTOpen(volName
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
 402                 if ( error 
== noErr 
) 
 404                         if ( !newDTDatabase 
) 
 410                                         pb
.dtPB
.ioNamePtr 
= applName
; 
 411                                         pb
.dtPB
.ioDTRefNum 
= dtRefNum
; 
 412                                         pb
.dtPB
.ioIndex 
= index
; 
 413                                         pb
.dtPB
.ioFileCreator 
= creator
; 
 414                                         error 
= PBDTGetAPPLSync(&pb
.dtPB
); 
 415                                         if ( error 
== noErr 
) 
 417                                                 /* got a match - see if it is valid */ 
 419                                                 *applVRefNum 
= realVRefNum
; /* get the vRefNum now */ 
 420                                                 *applParID 
= pb
.dtPB
.ioAPPLParID
; /* get the parent ID now */ 
 422                                                 /* pb.hPB.fileParam.ioNamePtr is already set */ 
 423                                                 pb
.hPB
.fileParam
.ioVRefNum 
= realVRefNum
; 
 424                                                 pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
 425                                                 pb
.hPB
.fileParam
.ioDirID 
= *applParID
; 
 426                                                 pb
.hPB
.fileParam
.ioFDirIndex 
= 0;       /* use ioNamePtr and ioDirID */ 
 427                                                 if ( PBHGetFInfoSync(&pb
.hPB
) == noErr 
) 
 429                                                         if ( (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdCreator 
== creator
) && 
 430                                                                  (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdType 
== 'APPL') ) 
 437                                 } while ( (error 
== noErr
) && !applFound 
); 
 438                                 if ( error 
!= noErr 
) 
 440                                         error 
= afpItemNotFound
; 
 445                                 /* Desktop database is empty (new), set error to try CatSearch */ 
 446                                 error 
= afpItemNotFound
; 
 449                 /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */ 
 450                 if ( error 
== paramErr 
) 
 452                         /* if paramErr, the volume didn't support the Desktop Manager */ 
 453                         /* try the Desktop file */ 
 455                         error 
= GetAPPLFromDesktopFile(volName
, vRefNum
, creator
, 
 456                                                                                         applVRefNum
, applParID
, applName
); 
 457                         if ( error 
== noErr 
) 
 459                                 /* got a match - see if it is valid */ 
 461                                 pb
.hPB
.fileParam
.ioNamePtr 
= applName
; 
 462                                 pb
.hPB
.fileParam
.ioVRefNum 
= *applVRefNum
; 
 463                                 pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
 464                                 pb
.hPB
.fileParam
.ioDirID 
= *applParID
; 
 465                                 pb
.hPB
.fileParam
.ioFDirIndex 
= 0;       /* use ioNamePtr and ioDirID */ 
 466                                 if ( PBHGetFInfoSync(&pb
.hPB
) == noErr 
) 
 468                                         if ( (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdCreator 
!= creator
) || 
 469                                                  (pb
.hPB
.fileParam
.ioFlFndrInfo
.fdType 
!= 'APPL') ) 
 471                                                 error 
= afpItemNotFound
; 
 474                                 else if ( error 
== fnfErr 
) 
 476                                         error 
= afpItemNotFound
; 
 480                 /* acceptable error from DesktopFile code to continue is afpItemNotFound */ 
 481                 if ( (error 
== afpItemNotFound
) && searchCatalog
) 
 483                         /* Couldn't be found in the Desktop file either, */ 
 484                         /* try searching with CatSearch if requested */ 
 486                         error 
= CreatorTypeFileSearch(NULL
, realVRefNum
, creator
, kAPPLResType
, &spec
, 1, 
 487                                                                                         &actMatchCount
, true); 
 488                         if ( (error 
== noErr
) || (error 
== eofErr
) ) 
 490                                 if ( actMatchCount 
> 0 ) 
 492                                         *applVRefNum 
= spec
.vRefNum
; 
 493                                         *applParID 
= spec
.parID
; 
 494                                         BlockMoveData(spec
.name
, applName
, spec
.name
[0] + 1); 
 498                                         error 
= afpItemNotFound
; 
 507 /*****************************************************************************/ 
 509 pascal  OSErr   
FSpDTXGetAPPL(ConstStr255Param volName
, 
 512                                                           Boolean searchCatalog
, 
 515         return ( DTXGetAPPL(volName
, vRefNum
, creator
, searchCatalog
, 
 516                                                 &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
 519 /*****************************************************************************/ 
 521 pascal  OSErr   
DTGetAPPL(ConstStr255Param volName
, 
 528         /* Call DTXGetAPPL with the "searchCatalog" parameter true */  
 529         return ( DTXGetAPPL(volName
, vRefNum
, creator
, true, 
 530                                                 applVRefNum
, applParID
, applName
) ); 
 533 /*****************************************************************************/ 
 535 pascal  OSErr   
FSpDTGetAPPL(ConstStr255Param volName
, 
 540         /* Call DTXGetAPPL with the "searchCatalog" parameter true */  
 541         return ( DTXGetAPPL(volName
, vRefNum
, creator
, true, 
 542                                                 &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
 545 /*****************************************************************************/ 
 548 **      FindBundleGivenCreator 
 550 **      Search the current resource file for the 'BNDL' resource with the given 
 551 **      creator and return a handle to it. 
 553 static  OSErr   
FindBundleGivenCreator(OSType creator
, 
 554                                                                            BNDLRecHandle 
*returnBndl
) 
 559         BNDLRecHandle   theBndl
; 
 561         error 
= afpItemNotFound
;        /* default to not found */ 
 563         /* Search each BNDL resource until we find the one with a matching creator. */ 
 565         numOfBundles 
= Count1Resources(kBNDLResType
); 
 569         while ( (index 
<= numOfBundles
) && (*returnBndl 
== NULL
) ) 
 571                 theBndl 
= (BNDLRecHandle
)Get1IndResource(kBNDLResType
, index
); 
 573                 if ( theBndl 
!= NULL 
) 
 575                         if ( (*theBndl
)->signature 
== creator 
) 
 577                                 /* numTypes and typeArray->count will always be the actual count minus 1, */ 
 578                                 /* so 0 in both fields is valid. */ 
 579                                 if ( ((*theBndl
)->numTypes 
>= 0) && ((*theBndl
)->typeArray
->count 
>= 0) ) 
 582                                         *returnBndl 
= theBndl
; 
 594 /*****************************************************************************/ 
 599 **      Given a Handle to a BNDL return a pointer to the desired type 
 600 **      in it. If the type is not found, or if the type's count < 0, 
 601 **      return afpItemNotFound. 
 603 static  OSErr   
FindTypeInBundle(OSType typeToFind
, 
 604                                                                  BNDLRecHandle theBndl
, 
 605                                                                  BundleTypePtr 
*returnBundleType
) 
 609         Ptr                             ptrIterator
;    /* use a Ptr so we can do ugly pointer math */ 
 611         error 
= afpItemNotFound
;        /* default to not found */ 
 613         ptrIterator 
= (Ptr
)((*theBndl
)->typeArray
); 
 615         *returnBundleType 
= NULL
; 
 617         while ( (index 
< ((*theBndl
)->numTypes 
+ 1)) && 
 618                         (*returnBundleType 
== NULL
) ) 
 620                 if ( (((BundleTypePtr
)ptrIterator
)->type 
== typeToFind
) && 
 621                          (((BundleTypePtr
)ptrIterator
)->count 
>= 0) ) 
 623                                 *returnBundleType 
= (BundleTypePtr
)ptrIterator
; 
 628                         ptrIterator 
+= ( sizeof(OSType
) + 
 630                                                          ( sizeof(IDRec
) * (((BundleTypePtr
)ptrIterator
)->count 
+ 1) ) ); 
 638 /*****************************************************************************/ 
 641 **      GetLocalIDFromFREF 
 643 **      Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource 
 644 **      looking for a matching fileType. If a matching fileType is found, return 
 645 **      its icon local ID. If no match is found, return afpItemNotFound as the 
 648 static  OSErr   
GetLocalIDFromFREF(BundleTypePtr theBundleType
, 
 655         FREFRecHandle   theFref
; 
 657         error 
= afpItemNotFound
;        /* default to not found */ 
 659         /* For each localID in this type, get the FREF resource looking for fileType */ 
 661         idIterator 
= &theBundleType
->idArray
[0]; 
 664         while ( (index 
<= theBundleType
->count
) && (*iconLocalID 
== 0) ) 
 666                 theFref 
= (FREFRecHandle
)Get1Resource(kFREFResType
, idIterator
->rsrcID
); 
 667                 if ( theFref 
!= NULL 
) 
 669                         if ( (*theFref
)->fileType 
== fileType 
) 
 671                                 *iconLocalID 
= (*theFref
)->iconID
; 
 683 /*****************************************************************************/ 
 686 **      GetIconRsrcIDFromLocalID 
 688 **      Given a pointer to a 'ICN#' BundleType record, look for the IDRec with 
 689 **      the localID that matches iconLocalID. If a matching IDRec is found, 
 690 **      return the IDRec's rsrcID field value. If no match is found, return 
 691 **      afpItemNotFound as the function result. 
 693 static  OSErr   
GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType
, 
 701         error 
= afpItemNotFound
;        /* default to not found */ 
 703         /* Find the rsrcID of the icon family type, given the localID */ 
 705         idIterator 
= &theBundleType
->idArray
[0]; 
 708         while ( (index 
<= theBundleType
->count
) && (*iconRsrcID 
== 0) ) 
 710                 if ( idIterator
->localID 
== iconLocalID 
) 
 712                         *iconRsrcID 
= idIterator
->rsrcID
; 
 723 /*****************************************************************************/ 
 728 **      Map a Desktop Manager icon type to the corresponding resource type. 
 729 **      Return (OSType)0 if there is no corresponding resource type. 
 731 static  OSType  
DTIconToResIcon(short iconType
) 
 738                         resType 
= large1BitMask
; 
 741                         resType 
= large4BitData
; 
 744                         resType 
= large8BitData
; 
 747                         resType 
= small1BitMask
; 
 750                         resType 
= small4BitData
; 
 753                         resType 
= small8BitData
; 
 763 /*****************************************************************************/ 
 766 **      GetIconFromDesktopFile 
 768 **      INPUT a pointer to a non-existent Handle, because we'll allocate one 
 770 **      search each BNDL resource for the right fileCreator and once we get it 
 771 **              find the 'FREF' type in BNDL 
 772 **              for each localID in the type, open the FREF resource 
 773 **                      if the FREF is the desired fileType 
 774 **                              get its icon localID 
 775 **                              get the ICN# type in BNDL 
 776 **                              get the icon resource number from the icon localID 
 777 **                              get the icon resource type from the desktop mgr's iconType 
 778 **                              get the icon of that type and number 
 780 static  OSErr   
GetIconFromDesktopFile(ConstStr255Param volName
, 
 792         BNDLRecHandle   theBndl 
= NULL
; 
 793         BundleTypePtr   theBundleType
; 
 797         Handle                  returnIconHandle
;        
 802         error 
= DetermineVRefNum(volName
, vRefNum
, &realVRefNum
); 
 803         if ( error 
== noErr 
) 
 805                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
 806                 if ( error 
== noErr 
) 
 808                         savedResFile 
= CurResFile(); 
 811                         **      Open the 'Desktop' file in the root directory. (because 
 812                         **      opening the resource file could preload unwanted resources, 
 813                         **      bracket the call with SetResLoad(s)) 
 816                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
 819                         if ( dfRefNum 
!= -1 ) 
 822                                 **      Find the BNDL resource with the specified creator. 
 824                                 error 
= FindBundleGivenCreator(fileCreator
, &theBndl
); 
 825                                 if ( error 
== noErr 
) 
 827                                         /* Lock the BNDL resource so it won't be purged when other resources are loaded */ 
 828                                         bndlState 
= HGetState((Handle
)theBndl
); 
 829                                         HLock((Handle
)theBndl
); 
 831                                         /* Find the 'FREF' BundleType record in the BNDL resource. */ 
 832                                         error 
= FindTypeInBundle(kFREFResType
, theBndl
, &theBundleType
); 
 833                                         if ( error 
== noErr 
) 
 835                                                 /* Find the local ID in the 'FREF' resource with the specified fileType */ 
 836                                                 error 
= GetLocalIDFromFREF(theBundleType
, fileType
, &iconLocalID
); 
 837                                                 if ( error 
== noErr 
) 
 839                                                         /* Find the 'ICN#' BundleType record in the BNDL resource. */ 
 840                                                         error 
= FindTypeInBundle(kIconFamResType
, theBndl
, &theBundleType
); 
 841                                                         if ( error 
== noErr 
) 
 843                                                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */ 
 844                                                                 error 
= GetIconRsrcIDFromLocalID(theBundleType
, iconLocalID
, &iconRsrcID
); 
 845                                                                 if ( error 
== noErr 
) 
 847                                                                         /* Map Desktop Manager icon type to resource type */ 
 848                                                                         iconRsrcType 
= DTIconToResIcon(iconType
); 
 850                                                                         if ( iconRsrcType 
!= (OSType
)0 ) 
 853                                                                                 returnIconHandle 
= Get1Resource(iconRsrcType
, iconRsrcID
); 
 854                                                                                 if ( returnIconHandle 
!= NULL 
) 
 856                                                                                         /* Copy the resource handle, and return the copy */ 
 857                                                                                         HandToHand(&returnIconHandle
); 
 858                                                                                         if ( MemError() == noErr 
) 
 860                                                                                                 *iconHandle 
= returnIconHandle
; 
 864                                                                                                 error 
= afpItemNotFound
; 
 869                                                                                         error 
= afpItemNotFound
; 
 876                                         /* Restore the state of the BNDL resource */  
 877                                         HSetState((Handle
)theBndl
, bndlState
); 
 879                                 /* Restore the resource chain and close the Desktop file */ 
 880                                 UseResFile(savedResFile
); 
 881                                 CloseResFile(dfRefNum
); 
 885                                 error 
= ResError(); /* could not open Desktop file */ 
 888                 if ( (error 
!= noErr
) && (error 
!= memFullErr
) ) 
 890                         error 
= afpItemNotFound
;        /* force an error we should return */ 
 897 /*****************************************************************************/ 
 899 pascal  OSErr   
DTGetIcon(ConstStr255Param volName
, 
 909         Boolean newDTDatabase
; 
 913         error 
= DTOpen(volName
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
 914         if ( error 
== noErr 
) 
 916                 /* there was a desktop database and it's now open */ 
 918                 if ( !newDTDatabase 
)   /* don't bother to look in a new (empty) database */ 
 920                         /* get the buffer size for the requested icon type */ 
 924                                         bufferSize 
= kLargeIconSize
; 
 927                                         bufferSize 
= kLarge4BitIconSize
; 
 930                                         bufferSize 
= kLarge8BitIconSize
; 
 933                                         bufferSize 
= kSmallIconSize
; 
 936                                         bufferSize 
= kSmall4BitIconSize
; 
 939                                         bufferSize 
= kSmall8BitIconSize
; 
 946                         if ( bufferSize 
!= 0 ) 
 948                                 *iconHandle 
= NewHandle(bufferSize
); 
 949                                 if ( *iconHandle 
!= NULL 
) 
 953                                         pb
.ioDTRefNum 
= dtRefNum
; 
 955                                         pb
.ioDTBuffer 
= **iconHandle
; 
 956                                         pb
.ioDTReqCount 
= bufferSize
; 
 957                                         pb
.ioIconType 
= iconType
; 
 958                                         pb
.ioFileCreator 
= fileCreator
; 
 959                                         pb
.ioFileType 
= fileType
; 
 960                                         error 
= PBDTGetIconSync(&pb
); 
 962                                         HUnlock(*iconHandle
); 
 964                                         if ( error 
!= noErr 
) 
 966                                                 DisposeHandle(*iconHandle
);     /* dispose of the allocated memory */ 
 972                                         error 
= memFullErr
;     /* handle could not be allocated */ 
 977                                 error 
= paramErr
;       /* unknown icon type requested */ 
 982                         error 
= afpItemNotFound
;        /* the desktop database was empty - nothing to return */ 
 987                 /* There is no desktop database - try the Desktop file */ 
 989                 error 
= GetIconFromDesktopFile(volName
, vRefNum
, iconType
, 
 990                                                                                 fileCreator
, fileType
, iconHandle
); 
 996 /*****************************************************************************/ 
 998 pascal  OSErr   
DTSetComment(short vRefNum
, 
1000                                                          ConstStr255Param name
, 
1001                                                          ConstStr255Param comment
) 
1006         Boolean newDTDatabase
; 
1008         error 
= DTOpen(name
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
1009         if ( error 
== noErr 
) 
1011                 pb
.ioDTRefNum 
= dtRefNum
; 
1012                 pb
.ioNamePtr 
= (StringPtr
)name
; 
1014                 pb
.ioDTBuffer 
= (Ptr
)&comment
[1]; 
1015                 /* Truncate the comment to 200 characters just in case */ 
1016                 /* some file system doesn't range check */ 
1017                 if ( comment
[0] <= 200 ) 
1019                         pb
.ioDTReqCount 
= comment
[0]; 
1023                         pb
.ioDTReqCount 
= 200; 
1025                 error 
= PBDTSetCommentSync(&pb
); 
1030 /*****************************************************************************/ 
1032 pascal  OSErr   
FSpDTSetComment(const FSSpec 
*spec
, 
1033                                                           ConstStr255Param comment
) 
1035         return (DTSetComment(spec
->vRefNum
, spec
->parID
, spec
->name
, comment
)); 
1038 /*****************************************************************************/ 
1043 **      Get the comment ID number for the Desktop file's 'FCMT' resource ID from 
1044 **      the file or folders fdComment (frComment) field. 
1046 static  OSErr   
GetCommentID(short vRefNum
, 
1048                                                          ConstStr255Param name
, 
1054         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1055         *commentID 
= pb
.hFileInfo
.ioFlXFndrInfo
.fdComment
; 
1059 /*****************************************************************************/ 
1062 **      GetCommentFromDesktopFile 
1064 **      Get a file or directory's Finder comment field (if any) from the 
1065 **      Desktop file's 'FCMT' resources. 
1067 static  OSErr   
GetCommentFromDesktopFile(short vRefNum
, 
1069                                                                                   ConstStr255Param name
, 
1078         StringHandle commentHandle
; 
1080         /* Get the comment ID number */ 
1081         error 
= GetCommentID(vRefNum
, dirID
, name
, &commentID
); 
1082         if ( error 
== noErr 
) 
1084                 if ( commentID 
!= 0 )   /* commentID == 0 means there's no comment */ 
1086                         error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1087                         if ( error 
== noErr 
) 
1089                                 error 
= GetDesktopFileName(realVRefNum
, desktopName
); 
1090                                 if ( error 
== noErr 
) 
1092                                         savedResFile 
= CurResFile(); 
1094                                         **      Open the 'Desktop' file in the root directory. (because 
1095                                         **      opening the resource file could preload unwanted resources, 
1096                                         **      bracket the call with SetResLoad(s)) 
1099                                         dfRefNum 
= HOpenResFile(realVRefNum
, fsRtDirID
, desktopName
, fsRdPerm
); 
1102                                         if ( dfRefNum 
!= -1) 
1104                                                 /* Get the comment resource */ 
1105                                                 commentHandle 
= (StringHandle
)Get1Resource(kFCMTResType
,commentID
); 
1106                                                 if ( commentHandle 
!= NULL 
) 
1108                                                         if ( InlineGetHandleSize((Handle
)commentHandle
) > 0 ) 
1110                                                                 BlockMoveData(*commentHandle
, comment
, *commentHandle
[0] + 1); 
1114                                                                 error 
= afpItemNotFound
;        /* no comment available */ 
1119                                                         error 
= afpItemNotFound
;        /* no comment available */ 
1122                                                 /* restore the resource chain and close the Desktop file */ 
1123                                                 UseResFile(savedResFile
); 
1124                                                 CloseResFile(dfRefNum
); 
1128                                                 error 
= afpItemNotFound
; 
1133                                         error 
= afpItemNotFound
; 
1139                         error 
= afpItemNotFound
;        /* no comment available */ 
1146 /*****************************************************************************/ 
1148 pascal  OSErr   
DTGetComment(short vRefNum
, 
1150                                                          ConstStr255Param name
, 
1156         Boolean newDTDatabase
; 
1158         if (comment 
!= NULL
) 
1160                 comment
[0] = 0; /* return nothing by default */ 
1162                 /* attempt to open the desktop database */ 
1163                 error 
= DTOpen(name
, vRefNum
, &dtRefNum
, &newDTDatabase
); 
1164                 if ( error 
== noErr 
) 
1166                         /* There was a desktop database and it's now open */ 
1168                         if ( !newDTDatabase 
) 
1170                                 pb
.ioDTRefNum 
= dtRefNum
; 
1171                                 pb
.ioNamePtr 
= (StringPtr
)name
; 
1173                                 pb
.ioDTBuffer 
= (Ptr
)&comment
[1]; 
1175                                 **      IMPORTANT NOTE #1: Inside Macintosh says that comments 
1176                                 **      are up to 200 characters. While that may be correct for 
1177                                 **      the HFS file system's Desktop Manager, other file 
1178                                 **      systems (such as Apple Photo Access) return up to 
1179                                 **      255 characters. Make sure the comment buffer is a Str255 
1180                                 **      or you'll regret it. 
1182                                 **      IMPORTANT NOTE #2: Although Inside Macintosh doesn't 
1183                                 **      mention it, ioDTReqCount is a input field to 
1184                                 **      PBDTGetCommentSync. Some file systems (like HFS) ignore 
1185                                 **      ioDTReqCount and always return the full comment -- 
1186                                 **      others (like AppleShare) respect ioDTReqCount and only 
1187                                 **      return up to ioDTReqCount characters of the comment. 
1189                                 pb
.ioDTReqCount 
= sizeof(Str255
) - 1; 
1190                                 error 
= PBDTGetCommentSync(&pb
); 
1193                                         comment
[0] = (unsigned char)pb
.ioDTActCount
; 
1199                         /* There is no desktop database - try the Desktop file */ 
1200                         error 
= GetCommentFromDesktopFile(vRefNum
, dirID
, name
, comment
); 
1201                         if ( error 
!= noErr 
) 
1203                                 error 
= afpItemNotFound
;        /* return an expected error */ 
1215 /*****************************************************************************/ 
1217 pascal  OSErr   
FSpDTGetComment(const FSSpec 
*spec
, 
1220         return (DTGetComment(spec
->vRefNum
, spec
->parID
, spec
->name
, comment
)); 
1223 /*****************************************************************************/ 
1225 pascal  OSErr   
DTCopyComment(short srcVRefNum
, 
1227                                                           ConstStr255Param srcName
, 
1230                                                           ConstStr255Param dstName
) 
1231 /* The destination volume must support the Desktop Manager for this to work */ 
1236         error 
= DTGetComment(srcVRefNum
, srcDirID
, srcName
, comment
); 
1237         if ( (error 
== noErr
) && (comment
[0] > 0) ) 
1239                 error 
= DTSetComment(dstVRefNum
, dstDirID
, dstName
, comment
); 
1244 /*****************************************************************************/ 
1246 pascal  OSErr   
FSpDTCopyComment(const FSSpec 
*srcSpec
, 
1247                                                            const FSSpec 
*dstSpec
) 
1248 /* The destination volume must support the Desktop Manager for this to work */ 
1250         return (DTCopyComment(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
1251                                                 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
)); 
1254 /*****************************************************************************/