//************************************************************************************** // Filename: CMUtils.cp // Part of Contextual Menu Workshop by Abracode Inc. // http://free.abracode.com/cmworkshop/ // // Copyright © 2002-2003 Abracode, Inc. All rights reserved. // // Description: static utilities for Contextual Menu Plugins // // TODO: split into several separate smaller files because the linker in ProjectBuilder // is not able to optimize the ouput binary and links all functions, even those unused (sic!) // // //************************************************************************************** #include "CMUtils.h" #include "MoreFilesExtras.h" #include "CFObjDel.h" #include "MoreFilesX.h" #include #include "AStdArrayNew.h" #include "DebugSettings.h" #include "StAEDesc.h" #if UNIVERSAL_INTERFACES_VERSION < 0x0342 //these enums used to be present in ContextualMenuPlugins.h, now they are defined in Menus.h enum { keyContextualMenuCommandID = 'cmcd', keyContextualMenuSubmenu = 'cmsb' }; #endif //res file must be open for this function //this function reads command string from STR# resource OSStatus CMUtils::AddResCommand( AEDescList* ioCommands, short stringsID, short strIndex, SInt32 inCommandID, MenuItemAttributes attributes /*= 0*/, UInt32 modifiers /*= kMenuNoModifiers*/) { Str255 commandString; ::GetIndString(commandString, stringsID, strIndex); if( commandString[0] > 0) return CMUtils::AddCommandToAEDescList(commandString, inCommandID, ioCommands, attributes, modifiers); return resNotFound; } // --------------------------------------------------------------------------- // AddCommandToAEDescList // --------------------------------------------------------------------------- OSStatus CMUtils::AddCommandToAEDescList( ConstStr255Param inCommandString, SInt32 inCommandID, AEDescList* ioCommandList, MenuItemAttributes attributes /*= 0*/, UInt32 modifiers /*= kMenuNoModifiers*/) { if( (inCommandString == NULL) || (ioCommandList == NULL) ) return paramErr; TRACE_STR( "\pCMUtils. AddCommandToAEDescList with Str255" ); OSStatus err = noErr; StAEDesc theCommandRecord;//AERecord // create an apple event record for our command err = ::AECreateList(NULL, 0, true, theCommandRecord); if (err != noErr) return err; // stick the command text into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuName /*keyAEName*/, typeChar, &inCommandString[1], inCommandString[0]); if (err != noErr) return err; // stick the command ID into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuCommandID, typeLongInteger, &inCommandID, sizeof (inCommandID)); if (err != noErr) return err; //stick menu attributes into AERecord if(attributes != 0) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuAttributes, typeLongInteger, &attributes, sizeof (attributes)); if (err != noErr) return err; } //stick menu modifiers into AERecord if(modifiers != kMenuNoModifiers) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuModifiers, typeLongInteger, &modifiers, sizeof (UInt32)); if (err != noErr) return err; } // stick this record into the list of commands that we are passing back to CMM err = ::AEPutDesc( ioCommandList, // the list we're putting our command into 0, // stick this command onto the end of our list theCommandRecord); // the command I'm putting into the list return err; } OSStatus CMUtils::AddCommandToAEDescList( const UniChar *inCommandString, UniCharCount inCount, SInt32 inCommandID, AEDescList* ioCommandList, MenuItemAttributes attributes /*= 0*/, UInt32 modifiers /*= kMenuNoModifiers*/) { if( (inCommandString == NULL) || (ioCommandList == NULL) ) return paramErr; TRACE_STR( "\pCMUtils. AddCommandToAEDescList with Unicode characters" ); OSStatus err = noErr; StAEDesc theCommandRecord;//AERecord // create an apple event record for our command err = ::AECreateList(NULL, 0, true, theCommandRecord); if (err != noErr) return err; // stick the command text into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuName /*keyAEName*/, typeUnicodeText, inCommandString, inCount*sizeof(UniChar)); if (err != noErr) return err; // stick the command ID into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuCommandID, typeLongInteger, &inCommandID, sizeof (inCommandID)); if (err != noErr) return err; //stick menu attributes into AERecord if(attributes != 0) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuAttributes, typeLongInteger, &attributes, sizeof (attributes)); if (err != noErr) return err; } //stick menu modifiers into AERecord if(modifiers != kMenuNoModifiers) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuModifiers, typeLongInteger, &modifiers, sizeof (UInt32)); if (err != noErr) return err; } // stick this record into the list of commands that we are passing back to CMM err = ::AEPutDesc( ioCommandList, // the list we're putting our command into 0, // stick this command onto the end of our list theCommandRecord); // the command I'm putting into the list return err; } OSStatus CMUtils::AddCommandToAEDescList( CFStringRef inCommandString, SInt32 inCommandID, Boolean putCFString, //available starting with OS 10.2 AEDescList* ioCommandList, MenuItemAttributes attributes /*= 0*/, UInt32 modifiers /*= kMenuNoModifiers*/) { if(putCFString == false) return AddCommandToAEDescList_Compatible( inCommandString, inCommandID, ioCommandList, attributes, modifiers ); if( (inCommandString == NULL) || (ioCommandList == NULL) ) return paramErr; TRACE_STR( "\pCMUtils. AddCommandToAEDescList with CFString" ); OSStatus err = noErr; StAEDesc theCommandRecord;//AERecord // create an apple event record for our command err = ::AECreateList(NULL, 0, true, theCommandRecord); if (err != noErr) return err; /* Apple documentation says: * If you provide data as typeCFStringRef, the Contextual Menu Manager will * automatically release the CFStringRef once the menu has been * displayed. If you need the CFStringRef to have a longer timetime, * your plugin should retain the CFStringRef before inserting it into * the AERecord. */ //_tk_ comment //it is not said explicitly if Contextual Menu Manager retains the CFString. //However, a little bit of experimenting (and crashing) shows that //IT DOES NOT RETAIN the CFString, it takes onwership of the string without retaining it //We do not "own" the string here so we must retain it //to balance the release which will be done by Contextual Menu Manager ::CFRetain(inCommandString); // stick the command text into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuName, typeCFStringRef, &inCommandString, sizeof(CFStringRef)); if (err != noErr) return err; // stick the command ID into the AERecord err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuCommandID, typeLongInteger, &inCommandID, sizeof (inCommandID)); if (err != noErr) return err; //stick menu attributes into AERecord if(attributes != 0) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuAttributes, typeLongInteger, &attributes, sizeof(attributes)); if (err != noErr) return err; } //stick menu modifiers into AERecord if(modifiers != kMenuNoModifiers) { err = ::AEPutKeyPtr( theCommandRecord, keyContextualMenuModifiers, typeLongInteger, &modifiers, sizeof (UInt32)); if (err != noErr) return err; } // stick this record into the list of commands that we are passing back to CMM err = ::AEPutDesc( ioCommandList, // the list we're putting our command into 0, // stick this command onto the end of our list theCommandRecord); // the command I'm putting into the list return err; } //This method is compatible with 10.1.x OSStatus CMUtils::AddCommandToAEDescList_Compatible( CFStringRef inCommandString, SInt32 inCommandID, AEDescList* ioCommandList, MenuItemAttributes attributes /*= 0*/, UInt32 modifiers /*= kMenuNoModifiers*/ ) { if( inCommandString == NULL ) return paramErr; TRACE_STR( "\pCMUtils. AddCommandToAEDescList with CFString" ); CFIndex uniCount = ::CFStringGetLength(inCommandString); const UniChar *uniString = ::CFStringGetCharactersPtr(inCommandString); if( uniString != NULL ) return CMUtils::AddCommandToAEDescList( uniString, uniCount, inCommandID, ioCommandList, attributes, modifiers ); //CFStringGetCharactersPtr failed and we must copy the string UniChar *newString = new UniChar[uniCount]; AStdArrayNew theDel(newString); CFRange theRange; theRange.location = 0; theRange.length = uniCount; ::CFStringGetCharacters( inCommandString, theRange, newString); OSStatus outErr = CMUtils::AddCommandToAEDescList( newString, uniCount, inCommandID, ioCommandList, attributes, modifiers ); // delete [] newString; return outErr; } //based on SampleCMPlugin.c OSStatus CMUtils::AddSubmenu( AEDescList* ioCommands, short stringsID, short superStrIndex, AEDescList &inSubList ) { TRACE_STR( "\pCMUtils. AddSubmenu with name from resources" ); Str255 commandString; commandString[0] = 0; ::GetIndString(commandString, stringsID, superStrIndex); if( commandString[0] == 0) return resNotFound; StAEDesc theSupercommand; //AERecord // create an apple event record for our supercommand OSStatus err = ::AECreateList( NULL, 0, true, theSupercommand ); if (err != noErr) return err; // stick the command text into the AERecord err = ::AEPutKeyPtr( theSupercommand, keyContextualMenuName /*keyAEName*/, typeChar, &commandString[1], commandString[0] ); if (err != noErr) return err; // stick the subcommands into into the AERecord err = ::AEPutKeyDesc( theSupercommand, keyContextualMenuSubmenu, &inSubList ); if (err != noErr) return err; // stick the supercommand into the list of commands that we are passing back to the CMM err = ::AEPutDesc( ioCommands, // the list we're putting our command into 0, // stick this command onto the end of our list theSupercommand ); // the command I'm putting into the list return err; } OSStatus CMUtils::AddSubmenu( AEDescList* ioCommands, CFStringRef inName, AEDescList &inSubList ) { if( inName == NULL ) return paramErr; TRACE_STR( "\pCMUtils. AddSubmenu with CFString" ); CFIndex uniCount = ::CFStringGetLength(inName); const UniChar *uniString = ::CFStringGetCharactersPtr(inName); if( uniString != NULL ) return CMUtils::AddSubmenu( ioCommands, uniString, uniCount, inSubList ); //CFStringGetCharactersPtr failed and we must copy the string UniChar *newString = new UniChar[uniCount]; CFRange theRange; theRange.location = 0; theRange.length = uniCount; ::CFStringGetCharacters( inName, theRange, newString); OSStatus outErr = CMUtils::AddSubmenu( ioCommands, newString, uniCount, inSubList ); delete [] newString; return outErr; } OSStatus CMUtils::AddSubmenu( AEDescList* ioCommands, const UniChar *inName, UniCharCount inCount, AEDescList &inSubList ) { if( (inName == NULL) || (ioCommands == NULL) ) return paramErr; TRACE_STR( "\pCMUtils. AddSubmenu with Unicode characters" ); StAEDesc theSupercommand; //AERecord // create an apple event record for our supercommand OSStatus err = ::AECreateList( NULL, 0, true, theSupercommand ); if (err != noErr) return err; // stick the command text into the AERecord err = ::AEPutKeyPtr( theSupercommand, keyContextualMenuName /*keyAEName*/, typeUnicodeText, inName, inCount*sizeof(UniChar) ); if (err != noErr) return err; // stick the subcommands into into the AERecord err = ::AEPutKeyDesc( theSupercommand, keyContextualMenuSubmenu, &inSubList ); if (err != noErr) return err; // stick the supercommand into the list of commands that we are passing back to the CMM err = ::AEPutDesc( ioCommands, // the list we're putting our command into 0, // stick this command onto the end of our list theSupercommand ); // the command I'm putting into the list return err; } #pragma mark - // --------------------------------------------------------------------------- // FSSpecProcessObjectList // --------------------------------------------------------------------------- /* generic file list processing loop caller must supply non-nil processing procedure of the prototype: OSStatus (*FSSpecHandlerProc)( FSSpec *inSpec, void *inData ); in flags pass: kProcBreakOnFirst is a directive to break on first item processed successfully on output you may receive flags: kListOutMultipleObjects when more than one object is present in list */ Boolean CMUtils::ProcessObjectList( const AEDescList *fileList, UInt32 &ioFlags, FSSpecHandlerProc inProcPtr, void *inProcData /*=NULL*/) { Boolean outOK = false; ioFlags &= ~kListOutFlagsMask; if( (fileList == NULL) || (inProcPtr == NULL) ) return false; OSStatus err = noErr; FSSpec fileSpec; SInt32 listItemsCount = 0; if( ::AECountItems(fileList, &listItemsCount) == noErr ) { if(listItemsCount > 1) ioFlags |= kListOutMultipleObjects; for (int i = 1; i <= listItemsCount; i++) { // Get ith item in the object list StAEDesc file; AEKeyword theKeyword; err = ::AEGetNthDesc(fileList, i, typeWildCard, &theKeyword, file); if (err == noErr) { if( GetFSSpec(file, fileSpec) == noErr ) { err = (*inProcPtr)( &fileSpec, inProcData ); if(err == noErr) { outOK = true; if( (ioFlags & kProcBreakOnFirst) != 0) break; } } } } } return outOK; } // --------------------------------------------------------------------------- // FSRefProcessObjectList // --------------------------------------------------------------------------- /* generic file list processing loop caller must supply non-nil processing procedure of the prototype: OSStatus (*FSRefHandlerProc)( FSRef *inRef, void *inData ); in flags pass: kProcBreakOnFirst is a directive to break on first item processed successfully on output you may receive flags: kListOutMultipleObjects when more than one object is present in list */ Boolean CMUtils::ProcessObjectList( const AEDescList *fileList, UInt32 &ioFlags, FSRefHandlerProc inProcPtr, void *inProcData /*=NULL*/) { Boolean outOK = false; ioFlags &= ~kListOutFlagsMask; if( (fileList == NULL) || (inProcPtr == NULL) ) return false; OSStatus err = noErr; FSRef fileRef; SInt32 listItemsCount = 0; if( ::AECountItems(fileList, &listItemsCount) == noErr ) { if(listItemsCount > 1) ioFlags |= kListOutMultipleObjects; for (int i = 1; i <= listItemsCount; i++) { // Get ith item in the object list StAEDesc file; AEKeyword theKeyword; err = ::AEGetNthDesc(fileList, i, typeWildCard, &theKeyword, file); if (err == noErr) { if( GetFSRef(file, fileRef) == noErr ) { err = (*inProcPtr)( &fileRef, inProcData ); if(err == noErr) { outOK = true; if( (ioFlags & kProcBreakOnFirst) != 0) break; } } } } } return outOK; } #pragma mark - OSErr CMUtils::GetFSSpec(const AEDesc &inDesc, FSSpec &outSpec) { OSErr err = noErr; if( inDesc.descriptorType == typeFSS ) {//no need to coerce err = ::AEGetDescData( &inDesc, &outSpec, sizeof(FSSpec) ); } else { StAEDesc coercedSpec; err = ::AECoerceDesc( &inDesc, typeFSS, coercedSpec ); if(err == noErr) { err = ::AEGetDescData( coercedSpec, &outSpec, sizeof(FSSpec) ); } else { DEBUG_STR( "\p\tUnable to coerce to FSSpec..." ); } } return err; } OSErr CMUtils::GetFSRef(const AEDesc &inDesc, FSRef &outRef) { OSErr err = noErr; if( inDesc.descriptorType == typeFSRef ) {//no need to coerce TRACE_STR( "\p\tCMUtils::FSRefGetRef without coercing..." ); err = ::AEGetDescData( &inDesc, &outRef, sizeof(FSRef) ); } else { StAEDesc coercedRef; err = ::AECoerceDesc( &inDesc, typeFSRef, coercedRef ); if(err == noErr) { TRACE_STR( "\p\tCMUtils::FSRefGetRef with coercing..." ); err = ::AEGetDescData( coercedRef, &outRef, sizeof(FSRef) ); } else {// Cannot get an FSRef. Try getting an FSSpec and make an FSRef out of it. FSSpec theSpec; err = CMUtils::GetFSSpec(inDesc, theSpec); if(err == noErr) { err = ::FSpMakeFSRef( &theSpec, &outRef ); } else { DEBUG_STR( "\p\tUnable to coerce to FSRef..." ); } } } return err; } #pragma mark - //copy name to output buffer. just for parity with FSRef version OSStatus CMUtils::GetPStringName(const FSSpec *inSpec, Str255 outName) { if(inSpec == NULL) return paramErr; ::BlockMoveData( inSpec->name, outName, inSpec->name[0] + 1); return noErr; } OSStatus CMUtils::GetPStringName(const FSRef *inRef, Str255 outName) { if(inRef == NULL) return paramErr; OSStatus err = noErr; FSCatalogInfo theFileInfo; FSCatalogInfoBitmap whichInfo = kFSCatInfoTextEncoding; HFSUniStr255 uniFileName; err = ::FSGetCatalogInfo( inRef, whichInfo, &theFileInfo, &uniFileName, NULL, NULL); if( err == noErr ) { if( theFileInfo.textEncodingHint == kTextEncodingUnknown) theFileInfo.textEncodingHint = ::CFStringGetSystemEncoding(); CFStringRef theStrRef = ::CFStringCreateWithCharacters( kCFAllocatorDefault, uniFileName.unicode, uniFileName.length ); if(theStrRef != NULL) { CFObjDel strDel(theStrRef); Boolean isOK = ::CFStringGetPascalString(theStrRef, outName, sizeof(outName), theFileInfo.textEncodingHint); err = isOK ? noErr : -1; } } return err; } //caller is responsible for deleting the output string CFStringRef CMUtils::CreateCFStringNameFromFSRef(const FSRef *inRef) { if(inRef == NULL) return NULL; FSCatalogInfo theFileInfo; FSCatalogInfoBitmap whichInfo = kFSCatInfoNone; HFSUniStr255 uniFileName; OSStatus err = ::FSGetCatalogInfo( inRef, whichInfo, &theFileInfo, &uniFileName, NULL, NULL); if( err == noErr ) return ::CFStringCreateWithCharacters( kCFAllocatorDefault, uniFileName.unicode, uniFileName.length ); return NULL; } #pragma mark - //ripped off MoreAEObjects.c OSErr CMUtils::CreateAliasDesc( const AliasHandle inAliasH, AEDesc *outAliasAEDesc ) { OSErr err = noErr; char handleState = ::HGetState( (Handle)inAliasH ); ::HLock( (Handle)inAliasH ); err = ::AECreateDesc( typeAlias, *inAliasH, ::GetHandleSize( (Handle)inAliasH ), outAliasAEDesc ); ::HSetState( (Handle)inAliasH, handleState ); return err; } OSErr CMUtils::CreateAliasDesc( const FSSpec *inFSSpec, AEDesc *outAliasAEDesc ) { OSErr err = noErr; AliasHandle aliasHandle; err = ::NewAlias( NULL, inFSSpec, &aliasHandle); if( (err == noErr) && (aliasHandle == NULL) ) { err = paramErr; } if( err == noErr ) { err = CMUtils::CreateAliasDesc( aliasHandle, outAliasAEDesc ); ::DisposeHandle( (Handle)aliasHandle ); } return err; } OSErr CMUtils::CreateAliasDesc( const FSRef *inFSRef, AEDesc *outAliasAEDesc ) { OSErr err = noErr; AliasHandle aliasHandle; err = ::FSNewAlias( NULL, inFSRef, &aliasHandle ); if( (err == noErr) && (aliasHandle == NULL) ) { err = paramErr; } if( err == noErr ) { err = CMUtils::CreateAliasDesc( aliasHandle, outAliasAEDesc ); ::DisposeHandle( (Handle)aliasHandle ); } return err; } OSErr CMUtils::CreateAliasDesc( const CFURLRef inURL, AEDesc *outAliasAEDesc ) { if(inURL == NULL) return fnfErr; FSRef fileRef; if( ::CFURLGetFSRef(inURL, &fileRef) ) return CreateAliasDesc( &fileRef, outAliasAEDesc ); return fnfErr; } #pragma mark - OSErr CMUtils::IsFolder(const FSSpec *inSpec, Boolean &outIsFolder) { outIsFolder = false; if(inSpec == NULL) return paramErr; CInfoPBRec pb; OSErr err = GetCatInfoNoName(inSpec->vRefNum, inSpec->parID, inSpec->name, &pb); if ( err == noErr ) { if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) { outIsFolder = true; } } return err; } OSErr CMUtils::IsFolder(const FSRef *inRef, Boolean &outIsFolder) { outIsFolder = false; if(inRef == NULL) return paramErr; FSCatalogInfo theInfo; OSErr err = ::FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags, &theInfo, NULL, NULL, NULL); if ( err == noErr ) { if( (theInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) { outIsFolder = true; } } return err; } #pragma mark - //send simple event with direct param to Finder //if you need something more complicated, use the following code as a starting point and stick required descriptions //into the appleEvent //if the function returns noErr it does not mean the Finder will process your event //it just means that the event was sent successfully OSErr CMUtils::SendAppleEventToFinder( AEEventClass theAEEventClass, AEEventID theAEEventID, const AEDesc &directObjectDesc, Boolean waitForReply /*=false*/, Boolean toSelf /*=false*/) { if(toSelf) return CMUtils::SendAppleEventToSelf(theAEEventClass, theAEEventID, directObjectDesc); return CMUtils::SendAppleEventToRunningApplication( 'MACS', theAEEventClass, theAEEventID, directObjectDesc, waitForReply ); } OSErr CMUtils::SendAEWithTwoObjToFinder( AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo, Boolean waitForReply /*=false*/, Boolean toSelf /*=false*/ ) { if(toSelf) return CMUtils::SendAEWithTwoObjToSelf(theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo); return CMUtils::SendAEWithTwoObjToRunningApp( 'MACS', theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo, waitForReply ); } OSErr CMUtils::SendAEWithThreeObjToFinder( AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo, AEKeyword keyThree, const AEDesc &objThree, Boolean waitForReply /*=false*/, Boolean toSelf /*=false*/ ) { if(toSelf) return CMUtils::SendAEWithThreeObjToSelf(theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo, keyThree, objThree); return CMUtils::SendAEWithThreeObjToRunningApp( 'MACS', theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo, keyThree, objThree, waitForReply ); } /* pascal Boolean AEIdleProc( EventRecord* inMacEvent, SInt32* outSleepTime, RgnHandle* outMouseRgn) { *outSleepTime = 6; *outMouseRgn = nil; EventTimeout theTimeout = kEventDurationSecond; ::RunCurrentEventLoop(theTimeout); return false; } */ OSErr CMUtils::SendAppleEventToRunningApplication( FourCharCode appSig, AEEventClass theAEEventClass, AEEventID theAEEventID, const AEDesc &directObjectDesc, Boolean waitForReply /*=false*/ ) { return CMUtils::SendAEWithObjToRunningApp( appSig, theAEEventClass, theAEEventID, keyDirectObject, directObjectDesc, waitForReply); } OSErr CMUtils::SendAEWithObjToRunningApp( FourCharCode appSig, AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, Boolean waitForReply /*=false*/ ) { AEDesc emptyDesc; return CMUtils::SendAEWithThreeObjToRunningApp( appSig, theAEEventClass, theAEEventID, keyOne, objOne, 0, emptyDesc, 0, emptyDesc, waitForReply); } OSErr CMUtils::SendAEWithTwoObjToRunningApp( FourCharCode appSig, AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo, Boolean waitForReply /*=false*/ ) { AEDesc emptyDesc; return CMUtils::SendAEWithThreeObjToRunningApp( appSig, theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo, 0, emptyDesc, waitForReply); } OSErr CMUtils::SendAEWithThreeObjToRunningApp( FourCharCode appSig, AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo, AEKeyword keyThree, const AEDesc &objThree, Boolean waitForReply /*=false*/ ) { OSErr theErr = noErr; StAEDesc appAddress; theErr = ::AECreateDesc(typeApplSignature, &appSig, sizeof(FourCharCode), appAddress); if(theErr == noErr) { StAEDesc appleEvent; theErr = ::AECreateAppleEvent(theAEEventClass, theAEEventID, appAddress, kAutoGenerateReturnID, kAnyTransactionID, appleEvent); if(theErr == noErr) { if(keyOne != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyOne, &objOne); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. AEPutKeyDesc (keyOne) failed" ); return theErr; } if(keyTwo != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyTwo, &objTwo); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. AEPutKeyDesc (keyTwo) failed" ); return theErr; } if(keyThree != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyThree, &objThree); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. AEPutKeyDesc (keyTwo) failed" ); return theErr; } AESendMode theMode = kAENoReply; AEIdleUPP theUpp = NULL; if(waitForReply) { theMode = kAEWaitReply; //theUpp = NewAEIdleUPP(AEIdleProc); } StAEDesc theAEReply; theErr = ::AESend( appleEvent, theAEReply, theMode, kAENormalPriority, kAEDefaultTimeout, theUpp, NULL); if(theUpp != NULL) { ::DisposeAEIdleUPP(theUpp); } if(theErr == connectionInvalid) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. Application is not running" ); } else if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. AESend failed" ); } } else { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. AECreateAppleEvent failed" ); } } else { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToRunningApp. Application address not found" ); } return theErr; } OSErr CMUtils::SendAppleEventToSelf(AEEventClass theAEEventClass, AEEventID theAEEventID, const AEDesc &directObjectDesc) { return CMUtils::SendAppleEventWithObjToSelf( theAEEventClass, theAEEventID, keyDirectObject, directObjectDesc ); } OSErr CMUtils::SendAppleEventWithObjToSelf(AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne) { AEDesc emptyDesc; return CMUtils::SendAEWithThreeObjToSelf(theAEEventClass, theAEEventID, keyOne, objOne, 0, emptyDesc, 0, emptyDesc); } OSErr CMUtils::SendAEWithTwoObjToSelf(AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo) { AEDesc emptyDesc; return CMUtils::SendAEWithThreeObjToSelf(theAEEventClass, theAEEventID, keyOne, objOne, keyTwo, objTwo, 0, emptyDesc); } OSErr CMUtils::SendAEWithThreeObjToSelf(AEEventClass theAEEventClass, AEEventID theAEEventID, AEKeyword keyOne, const AEDesc &objOne, AEKeyword keyTwo, const AEDesc &objTwo, AEKeyword keyThree, const AEDesc &objThree) { OSErr theErr = noErr; StAEDesc appAddress; ProcessSerialNumber processNum = { 0, kCurrentProcess }; theErr = ::AECreateDesc(typeProcessSerialNumber, &processNum, sizeof(ProcessSerialNumber), appAddress); if(theErr == noErr) { StAEDesc appleEvent; theErr = ::AECreateAppleEvent(theAEEventClass, theAEEventID, appAddress, kAutoGenerateReturnID, kAnyTransactionID, appleEvent); if(theErr == noErr) { if(keyOne != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyOne, &objOne); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. AEPutKeyDesc (keyOne) failed" ); return theErr; } if(keyTwo != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyTwo, &objTwo); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. AEPutKeyDesc (keyTwo) failed" ); return theErr; } if(keyThree != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyThree, &objThree); } if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. AEPutKeyDesc (keyThree) failed" ); return theErr; } AESendMode theMode = kAEWaitReply; StAEDesc theAEReply; theErr = ::AESend( appleEvent, theAEReply, theMode, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); if( (theErr == connectionInvalid) || (theErr == procNotFound) ) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. Application is not running" ); } else if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. AESend failed" ); #if _DEBUG_ { Str255 hexString; ByteCount destLen = sizeof(Str255); CMUtils::BufToHex( (const unsigned char *)&theErr, (char *)hexString, sizeof(theErr), destLen ); ::CopyCStringToPascal( (char *)hexString, hexString); DEBUG_STR( "\p\tError code is: " ); DEBUG_STR(hexString); } #endif //_DEBUG_ } } else { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. AECreateAppleEvent failed" ); } } else { DEBUG_STR( "\pCMUtils::SendAEWithThreeObjToSelf. Application address not found" ); } return theErr; } OSErr CMUtils::SendAppleEventWithObjToSelfWithReply(AEEventClass theAEEventClass, AEEventID theAEEventID, AEDesc &outReply, AEKeyword keyOne, const AEDesc &objOne) { OSErr theErr = noErr; StAEDesc appAddress; ProcessSerialNumber processNum = { 0, kCurrentProcess }; theErr = ::AECreateDesc(typeProcessSerialNumber, &processNum, sizeof(ProcessSerialNumber), appAddress); if(theErr == noErr) { StAEDesc appleEvent; theErr = ::AECreateAppleEvent(theAEEventClass, theAEEventID, appAddress, kAutoGenerateReturnID, kAnyTransactionID, appleEvent); if(theErr == noErr) { if(keyOne != 0)//if key is zero we understand that caller does not want to put an object { theErr = ::AEPutKeyDesc( appleEvent, keyOne, &objOne); } if(theErr == noErr) { AESendMode theMode = kAEWaitReply; theErr = ::AESend( appleEvent, &outReply, theMode, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); if( (theErr == connectionInvalid) || (theErr == procNotFound) ) { DEBUG_STR( "\pCMUtils::SendAppleEventWithObjToSelf. Application is not running" ); } else if(theErr != noErr) { DEBUG_STR( "\pCMUtils::SendAppleEventWithObjToSelf. AESend failed" ); #if _DEBUG_ { Str255 hexString; ByteCount destLen = sizeof(Str255); CMUtils::BufToHex( (const unsigned char *)&theErr, (char *)hexString, sizeof(theErr), destLen ); ::CopyCStringToPascal( (char *)hexString, hexString); DEBUG_STR( "\p\tError code is: " ); DEBUG_STR(hexString); } #endif //_DEBUG_ } } else { DEBUG_STR( "\pCMUtils::SendAppleEventWithObjToSelf. AEPutKeyDesc failed" ); } } else { DEBUG_STR( "\pCMUtils::SendAppleEventWithObjToSelf. AECreateAppleEvent failed" ); } } else { DEBUG_STR( "\pCMUtils::SendAppleEventWithObjToSelf. Application address not found" ); } return theErr; } /* OSErr CMUtils::SendServicesQueryToSelf() { OSErr theErr = noErr; OSStatus stat = noErr; EventTargetRef theAppTarget = ::GetApplicationEventTarget(); // StAEDesc appAddress; // ProcessSerialNumber processNum = { 0, kCurrentProcess }; // theErr = ::AECreateDesc(typeProcessSerialNumber, &processNum, // sizeof(ProcessSerialNumber), appAddress); if(theAppTarget != NULL) { EventRef carbonEvent = NULL; stat = ::MacCreateEvent(kCFAllocatorDefault, kEventClassService, kEventServiceGetTypes, ::GetCurrentEventTime(), kEventAttributeNone, &carbonEvent); //StAEDesc appleEvent; //theErr = ::AECreateAppleEvent(kEventClassService, kEventServiceGetTypes, // appAddress, // kAutoGenerateReturnID, // kAnyTransactionID, // appleEvent); if(stat == noErr) { CFMutableArrayRef mutableArr = ::CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); if(mutableArr != NULL) { CFObjDel arrDel(mutableArr); stat = ::SetEventParameter( carbonEvent, kEventParamServiceCopyTypes, typeCFMutableArrayRef, sizeof(CFMutableArrayRef), &mutableArr); //theErr = ::AEPutParamPtr( appleEvent, // kEventParamServiceCopyTypes, // typeCFMutableArrayRef, // &mutableArr, // sizeof(CFMutableArrayRef) ); if(stat == noErr) { // AESendMode theMode = kAEWaitReply; // StAEDesc theAEReply; // theErr = ::AESend( appleEvent, theAEReply, theMode, // kAENormalPriority, kAEDefaultTimeout, NULL, NULL); // if( (theErr == connectionInvalid) || (theErr == procNotFound) ) // { // DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. Application is not running" ); // } stat = ::SendEventToEventTarget(carbonEvent, theAppTarget); if(stat != noErr) { //DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. SendEventToEventTarget failed" ); #if _DEBUG_ { Str255 hexString; ByteCount destLen = sizeof(Str255); CMUtils::BufToHex( (const unsigned char *)&stat, (char *)hexString, sizeof(stat), destLen ); ::CopyCStringToPascal( (char *)hexString, hexString); DEBUG_STR( "\p\tSendEventToEventTarget failed. Error code is: " ); DEBUG_STR(hexString); } #endif //_DEBUG_ } else {//success CFIndex theCount = ::CFArrayGetCount(mutableArr); #if _DEBUG_ { Str255 hexString; ByteCount destLen = sizeof(Str255); CMUtils::BufToHex( (const unsigned char *)&theCount, (char *)hexString, sizeof(theCount), destLen ); ::CopyCStringToPascal( (char *)hexString, hexString); DEBUG_STR( "\p\tArray with copy types count is: " ); DEBUG_STR(hexString); } #endif //_DEBUG_ } } else { DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. SetEventParameter failed" ); } } else { DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. Could not create mutable array" ); } } else { DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. MacCreateEvent failed" ); } } else { DEBUG_STR( "\pCMUtils::SendServicesQueryToSelf. GetApplicationEventTarget failed" ); } return theErr; } */ //this function returns the name of the application currently executing the contextual menu plug-in OSErr CMUtils::GetHostName(Str255 outName) { outName[0] = 0; ProcessSerialNumber psn = { 0, kCurrentProcess }; ProcessInfoRec info; info.processInfoLength = sizeof(ProcessInfoRec); info.processName = outName; info.processAppSpec = NULL; return ::GetProcessInformation( &psn, &info ); } #pragma mark - void CMUtils::PutFinderObjectToTrash(const AEDesc &directObjectDesc, Boolean waitForReply, Boolean toSelf ) { CMUtils::SendAppleEventToFinder( kAEFinderSuite, kAESync, directObjectDesc, waitForReply, toSelf ); } void CMUtils::PutFinderObjectToTrash(const FSSpec *inSpec, Boolean waitForReply, Boolean toSelf) { if(inSpec != NULL) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inSpec, fileDesc ); if(err == noErr) { CMUtils::PutFinderObjectToTrash(fileDesc, waitForReply, toSelf ); } } } void CMUtils::PutFinderObjectToTrash(const FSRef *inRef, Boolean waitForReply, Boolean toSelf) { if(inRef != NULL) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inRef, fileDesc ); if(err == noErr) { CMUtils::PutFinderObjectToTrash(fileDesc, waitForReply, toSelf ); } } } #pragma mark - void CMUtils::UpdateFinderObject(const AEDesc &directObjectDesc, Boolean waitForReply, Boolean toSelf ) { CMUtils::SendAppleEventToFinder( kAEFinderSuite, kAESync, directObjectDesc, waitForReply, toSelf ); } void CMUtils::UpdateFinderObject(const FSRef *inRef, Boolean waitForReply, Boolean toSelf ) { if(inRef != NULL) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inRef, fileDesc ); if(err == noErr) { CMUtils::UpdateFinderObject( fileDesc, waitForReply, toSelf ); } } } void CMUtils::UpdateFinderObject(const FSSpec *inSpec, Boolean waitForReply, Boolean toSelf ) { if(inSpec != NULL) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inSpec, fileDesc ); if(err == noErr) { CMUtils::UpdateFinderObject( fileDesc, waitForReply, toSelf ); } } } #pragma mark - void CMUtils::MoveFinderObjectToFolder(const AEDesc &directObjectDesc, const FSRef *inFolderRef, Boolean waitForReply, Boolean toSelf ) { if( inFolderRef != NULL ) { StAEDesc folderDesc; OSErr err = CMUtils::CreateAliasDesc( inFolderRef, folderDesc ); if(err == noErr) { CMUtils::SendAEWithTwoObjToFinder( kAECoreSuite, kAEMove, keyDirectObject, directObjectDesc, keyAEDestination, folderDesc, waitForReply, toSelf ); } } } void CMUtils::MoveFinderObjectToFolder(const AEDesc &directObjectDesc, const FSSpec *inFolderSpec, Boolean waitForReply, Boolean toSelf ) { if( inFolderSpec != NULL ) { StAEDesc folderDesc; OSErr err = CMUtils::CreateAliasDesc( inFolderSpec, folderDesc ); if(err == noErr) { CMUtils::SendAEWithTwoObjToFinder( kAECoreSuite, kAEMove, keyDirectObject, directObjectDesc, keyAEDestination, folderDesc, waitForReply, toSelf ); } } } void CMUtils::MoveFinderObjectToFolder(const FSRef *inFileRef, const FSRef *inFolderRef, Boolean waitForReply, Boolean toSelf ) { if( (inFileRef != NULL) && (inFolderRef != NULL) ) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inFileRef, fileDesc ); if(err == noErr) { CMUtils::MoveFinderObjectToFolder(fileDesc, inFolderRef, waitForReply, toSelf ); } } } void CMUtils::MoveFinderObjectToFolder(const FSSpec *inFileSpec, const FSSpec *inFolderSpec, Boolean waitForReply, Boolean toSelf ) { if( inFileSpec != NULL ) { StAEDesc fileDesc; OSErr err = CMUtils::CreateAliasDesc( inFileSpec, fileDesc ); if(err == noErr) { CMUtils::MoveFinderObjectToFolder(fileDesc, inFolderSpec, waitForReply, toSelf ); } } } #pragma mark - //this one is based on FSDeleteContainer from MoreFilesX //but is modified to delete any item - it may be a non-empty folder or it may be a file OSErr CMUtils::DeleteObject(const FSRef *inRef) { if(inRef == NULL) return paramErr; FSCatalogInfo catalogInfo; OSErr result = FSGetCatalogInfo(inRef, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL, NULL); if( result != noErr) return result; if( 0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) ) { /* delete container's contents */ result = ::FSDeleteContainerContents(inRef); if( result != noErr) return result; } /* is container locked? */ if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) { /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ catalogInfo.nodeFlags &= ~kFSNodeLockedMask; (void) ::FSSetCatalogInfo(inRef, kFSCatInfoNodeFlags, &catalogInfo); } /* delete the container */ result = ::FSDeleteObject(inRef); return result; } //this one is based on DeleteDirectory from MoreFiles //but is modified to delete any item - it may be a non-empty folder or it may be a file OSErr CMUtils::DeleteObject(const FSSpec *inSpec) { if(inSpec == NULL) return paramErr; OSErr error; Boolean isFolder = false; error = CMUtils::IsFolder(inSpec, isFolder); if( (error == noErr) && isFolder) { /* Make sure a directory was specified and then delete its contents */ error = ::DeleteDirectoryContents(inSpec->vRefNum, inSpec->parID, inSpec->name); } if ( error == noErr ) { error = ::HDelete(inSpec->vRefNum, inSpec->parID, inSpec->name); if ( error == fLckdErr ) { (void) ::HRstFLock(inSpec->vRefNum, inSpec->parID, inSpec->name); /* unlock the directory locked by AppleShare */ error = ::HDelete(inSpec->vRefNum, inSpec->parID, inSpec->name); /* and try again */ } } return ( error ); } #pragma mark - Boolean CMUtils::AEDescHasTextData(const AEDesc &inDesc) { #if _DEBUG_ Str31 debugStr; DEBUG_STR( "\pAEDescHasTextData: data type is:" ); UInt8 *descPtr = (UInt8 *)&inDesc.descriptorType; debugStr[0] = 4; debugStr[1] = descPtr[0]; debugStr[2] = descPtr[1]; debugStr[3] = descPtr[2]; debugStr[4] = descPtr[3]; DEBUG_STR( debugStr ); #endif if( (inDesc.descriptorType == typeChar) || (inDesc.descriptorType == typeUnicodeText) ) {//try without coercing first if( inDesc.dataHandle != NULL ) return (::AEGetDescDataSize( &inDesc ) > 0); return false; } StAEDesc textDesc; if( ::AECoerceDesc(&inDesc, typeUnicodeText, textDesc) == noErr) { if( textDesc.GetDescriptorType() == typeUnicodeText ) if( textDesc.GetDataStorage() != NULL ) return (::AEGetDescDataSize(textDesc) > 0); } else if( ::AECoerceDesc(&inDesc, typeChar, textDesc) == noErr ) { if( textDesc.GetDescriptorType() == typeChar ) if( textDesc.GetDataStorage() != NULL ) return (::AEGetDescDataSize(textDesc) > 0); } return false; } //returns null if descriptior does not contain text CFStringRef CMUtils::CreateCFStringFromAEDesc(const AEDesc &inDesc) { TRACE_STR( "\pCMUtils::CreateCFStringFromAEDesc" ); CFStringRef outString = NULL; if( inDesc.descriptorType == typeUnicodeText ) { if( inDesc.dataHandle != NULL ) { Size byteCount = ::AEGetDescDataSize( &inDesc ); UniChar *newBuffer = (UniChar *)::NewPtrClear(byteCount); if(newBuffer != NULL) { if( ::AEGetDescData( &inDesc, newBuffer, byteCount ) == noErr) { outString = ::CFStringCreateWithCharacters(kCFAllocatorDefault, newBuffer, byteCount/sizeof(UniChar) ); } ::DisposePtr( (Ptr)newBuffer ); } } } else if(inDesc.descriptorType == typeChar) { if( inDesc.dataHandle != NULL ) { Size byteCount = ::AEGetDescDataSize( &inDesc ); char *newBuffer = ::NewPtrClear(byteCount); if(newBuffer != NULL) { if( ::AEGetDescData( &inDesc, newBuffer, byteCount ) == noErr) { outString = ::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)newBuffer, byteCount, CFStringGetSystemEncoding(), true); } ::DisposePtr( (Ptr)newBuffer ); } } } else { StAEDesc textDesc; if( ::AECoerceDesc(&inDesc, typeUnicodeText, textDesc) == noErr) { if(textDesc.GetDescriptorType() == typeUnicodeText) if(textDesc.GetDataStorage() != NULL) { Size byteCount = ::AEGetDescDataSize( textDesc ); UniChar *newBuffer = (UniChar *)::NewPtrClear(byteCount); if(newBuffer != NULL) { if( ::AEGetDescData( textDesc, newBuffer, byteCount ) == noErr) { outString = ::CFStringCreateWithCharacters(kCFAllocatorDefault, newBuffer, byteCount/sizeof(UniChar) ); } ::DisposePtr( (Ptr)newBuffer ); } } } else if( ::AECoerceDesc(&inDesc, typeChar, textDesc) == noErr) { if(textDesc.GetDescriptorType() == typeChar) if(textDesc.GetDataStorage() != NULL) { Size byteCount = ::AEGetDescDataSize( textDesc ); char *newBuffer = ::NewPtrClear(byteCount); if(newBuffer != NULL) { if( ::AEGetDescData( textDesc, newBuffer, byteCount ) == noErr) { outString = ::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)newBuffer, byteCount, CFStringGetSystemEncoding(), true); } ::DisposePtr( (Ptr)newBuffer ); } } } } if(outString == NULL) { DEBUG_STR( "\pCMUtils::CreateCFStringFromAEDesc: NULL string returned" ); } return outString; } #pragma mark - short CMUtils::OpenBundleResourceMap( CFBundleRef inBundleRef ) { short outFileRefNum = -1; if (inBundleRef != NULL) { outFileRefNum = ::CFBundleOpenBundleResourceMap(inBundleRef); } return outFileRefNum; } void CMUtils::CloseBundleResourceMap( SInt16 &ioFileRefNum, CFBundleRef inBundleRef ) { if ( (ioFileRefNum != -1) && (inBundleRef != NULL) ) ::CFBundleCloseBundleResourceMap(inBundleRef, ioFileRefNum); ioFileRefNum = -1; } #pragma mark - // --------------------------------------------------------------------------------- // ¥ BufToHex // --------------------------------------------------------------------------------- void CMUtils::BufToHex( const unsigned char* src, char *dest, ByteCount srcLen, ByteCount &destLen, UInt8 clumpSize /*=0*/) { static unsigned char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; UInt8 tempClumpSize = clumpSize; destLen=0; while(srcLen--) { *dest++ = *( hex + ((*src&0xF0)>>4) ); *dest++ = *( hex + ( *src&0x0F ) ); destLen+=2; if( clumpSize != 0 ) { if( --tempClumpSize == 0 ) { *dest++ = ' '; tempClumpSize = clumpSize; destLen++; } } src++; } *dest = 0; } #pragma mark - CFStringRef CMUtils::CreateCFStringFromResourceText(short stringsID, short strIndex) { Str255 theString; ::GetIndString(theString, stringsID, strIndex); if( theString[0] == 0) return NULL; CFStringEncoding systemEnc = ::CFStringGetSystemEncoding(); return ::CFStringCreateWithPascalString( kCFAllocatorDefault, theString, systemEnc); } #pragma mark - StResOpen::StResOpen( const FSSpec *inFile, SignedByte permission ) { mRefNum = ::FSpOpenResFile(inFile, permission); } StResOpen::StResOpen( const FSRef *inRef, SInt8 permission ) { mRefNum = ::FSOpenResFile(inRef, permission); } StResOpen::~StResOpen() { if( mRefNum != -1 ) ::CloseResFile(mRefNum); } #pragma mark - StBundleResOpen::StBundleResOpen( CFBundleRef inBundleRef ) : mBundleRef(inBundleRef) { mRefNum = CMUtils::OpenBundleResourceMap( mBundleRef ); } StBundleResOpen::~StBundleResOpen() { CMUtils::CloseBundleResourceMap( mRefNum, mBundleRef ); }