Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
SnapshotSample.c
/* |
File: SnapshotSample.c |
Contains: Code for saving and restoring desktop icons. |
This sample, when run the first time, creates a |
snapshot file in the Preferences folder which contains a list |
of the names and locations fo the items on the |
desktop. |
Running the sample again will read the snapshot |
file and tell the Finder to position the items |
at the locations read from the snapshot file. |
Sample does not read/set location of Trash, |
nor of mounted volumes. |
Sample is provided as is... I didn't get much |
chance to test beyond the standard, "oh, this |
works!" stage. |
The original Pascal version was written by |
Quinn "The Eskimo!" and released as a Freeware |
utility. This DTS sample was created by |
Deborah Grits. This version was tidied up |
and released by Quinn "The Eskimo!". |
Oh what a tangled web we weave... |
Written by: Quinn "The Eskimo!" |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/21/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include <AppleEvents.h> |
#include <Errors.h> |
#include <Events.h> |
#include <Fonts.h> |
#include <Gestalt.h> |
#include <Memory.h> |
#include <Menus.h> |
#include <OSUtils.h> |
#include <QDOffscreen.h> |
#include <QuickDraw.h> |
#include <Resources.h> |
#include <Script.h> |
#include <ToolUtils.h> |
#include <Windows.h> |
#include <AEPackObject.h> |
#include <AERegistry.h> |
#include <AEObjects.h> |
#include <Folders.h> |
#include <TextEdit.h> |
#include <Dialogs.h> |
////////////////////////////////////////////////////////////////////////// |
// Basic Utilities |
static OSErr FindProcessByTypeAndCreator(OSType typeToFind, OSType creatorToFind, ProcessSerialNumber *processSN) |
// Runs through the process list looking for the indicated application. |
{ |
OSErr err; |
ProcessInfoRec infoRecToFill; |
err = noErr; |
processSN->lowLongOfPSN = kNoProcess; |
processSN->highLongOfPSN = kNoProcess; |
infoRecToFill.processInfoLength = sizeof(ProcessInfoRec); |
infoRecToFill.processName = nil; |
infoRecToFill.processAppSpec = nil; |
do { |
err = GetNextProcess(processSN); |
if (err == noErr) { |
GetProcessInformation(processSN, &infoRecToFill); |
} |
} while ((infoRecToFill.processSignature != creatorToFind || infoRecToFill.processType != typeToFind) || |
err != noErr); |
return(err); |
} |
////////////////////////////////////////////////////////////////////////// |
// Global Types |
// The snapshot file is made up of records of SnapRecord type. |
// An empty record (ie with name == "") is used to indicate |
// the end of the file. |
typedef struct |
{ |
Str63 name; |
Point loc; |
} SnapRecord, *SnapRecordPtr, **SnapRecordHandle; |
////////////////////////////////////////////////////////////////////////// |
// Global Variables |
// Used to tell the main event loop to quit. |
static Boolean gQuit = false; |
// An empty AppleEvent Descriptor. |
const static AEDesc gNullDesc = {typeNull, nil}; |
////////////////////////////////////////////////////////////////////////// |
// Restoring Snapshots |
static OSErr SetItemPosition(Str255 fname, Point dest, AEDesc *setDataEvent) |
// Sends an AppleEvent to the targetDesc (which should target the Finder) |
// to set the position of the item whose name is fname to the position dest. |
{ |
OSErr err; |
AEDesc fileNameDesc = gNullDesc; |
AEDesc rootDesc = gNullDesc; |
AEDesc propertyDescriptor = gNullDesc; |
AEDesc objParentDesc = gNullDesc; |
AEDesc objDesc = gNullDesc; |
AEDesc reply = gNullDesc; |
AEDesc newData = gNullDesc; |
DescType procDescData = 'posn'; |
err = AECreateDesc(typeChar, &fname[1], fname[0], &fileNameDesc); |
// Create objParentDesc to specify the parent object, ie item "xxxx" of application |
if (err == noErr) { |
err = CreateObjSpecifier(cObject, &rootDesc, formName, &fileNameDesc, false, &objParentDesc); |
} |
// Create propertyDescriptor to hold the property specifier, ie position |
if (err == noErr) { |
err = AECreateDesc(typeType, &procDescData, sizeof(procDescData), &propertyDescriptor); |
} |
// Create objDesc to reference the data to set, ie position of item "xxx" of application |
if (err == noErr) { |
err = CreateObjSpecifier(cProperty, &objParentDesc, formPropertyID, &propertyDescriptor, false, &objDesc); |
} |
// Create on descriptor to hold the new data, ie the new icon position. |
if (err == noErr) { |
err = AECreateDesc(typeQDPoint, (void*)&dest, sizeof(dest), &newData); |
} |
// Fill out the parameters, putting the objDesc into the direct object and the new data |
// into the data parameter. |
if (err == noErr) { |
err = AEPutParamDesc(setDataEvent, keyDirectObject, &objDesc); |
} |
if (err == noErr) { |
err = AEPutParamDesc(setDataEvent, keyAEData, &newData); |
} |
// Send the event. |
if (err == noErr) { |
err = AESend(setDataEvent, &reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); |
// Some code that I enable when I'm debugging. |
if (false) { |
long errNum; |
Str255 errStr; |
DescType junkType; |
Size realSize; |
err = AEGetParamPtr(&reply, keyErrorNumber, typeInteger, &junkType, &errNum, sizeof(errNum), &realSize); |
err = AEGetParamPtr(&reply, keyErrorString, typeChar, &junkType, &errStr[1], 255, &realSize); |
errStr[0] = realSize; |
} |
} |
// Clean up all those messy descriptors. Don't you just love AppleEvents (-: |
AEDisposeDesc(&rootDesc); |
AEDisposeDesc(&fileNameDesc); |
AEDisposeDesc(&objParentDesc); |
AEDisposeDesc(&propertyDescriptor); |
AEDisposeDesc(&objDesc); |
AEDisposeDesc(&newData); |
AEDisposeDesc(&reply); |
return err; |
} |
static OSErr RestoreSnapshot (FSSpec snapFss) |
// Restore the snapshot file specified by snapFss. |
{ |
OSErr err; |
ProcessSerialNumber finderPSN; |
AEDesc targetDesc = gNullDesc; |
AEDesc setDataEvent = gNullDesc; |
short snapFileRef; |
Boolean done; |
SnapRecord aSnapRecord; |
long byteCount; |
snapFileRef = 0; |
// Find the Finder's ProcessSerialNumber and create the targetDesc for it. |
err = FindProcessByTypeAndCreator('FNDR', 'MACS', &finderPSN); |
if (err == noErr) { |
err = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(finderPSN), &targetDesc); |
} |
// Create the AppleEvent. |
if (err == noErr) { |
err = AECreateAppleEvent(kAECoreSuite, kAESetData, &targetDesc, |
kAutoGenerateReturnID, kAnyTransactionID, &setDataEvent); |
} |
// Open the file. |
if (err == noErr) { |
err = FSpOpenDF(&snapFss, fsRdPerm, &snapFileRef); |
} |
if (err == noErr) { |
// Read the records in the file, repositioning the icons as we go. |
done = false; |
do { |
byteCount = sizeof(SnapRecord); |
err = FSRead(snapFileRef, &byteCount, (void*) &aSnapRecord); |
if (err == noErr) { |
// We're done if we hit the empty string. |
done = (aSnapRecord.name[0] == 0); |
if (!done) { |
// Reposition the icon. |
err = SetItemPosition(aSnapRecord.name, aSnapRecord.loc, &setDataEvent); |
} |
} |
} while (!done); |
} |
if (err == eofErr) { |
err = noErr; |
} |
// clean up |
if (snapFileRef != 0) { |
(void) FSClose(snapFileRef); |
} |
AEDisposeDesc(&setDataEvent); |
AEDisposeDesc(&targetDesc); |
return err; |
} |
////////////////////////////////////////////////////////////////////////// |
// Creating Snapshots |
static OSErr WriteFileRecord(short snapFileRef, Str63 itemName, Point itemPosition) |
// Add a new record to the snapshot file. |
{ |
OSErr err; |
SnapRecord aSnapRecord; |
long byteCount; |
BlockMoveData(itemName, aSnapRecord.name, sizeof(aSnapRecord.name)); |
aSnapRecord.loc = itemPosition; |
byteCount = sizeof(SnapRecord); |
err = FSWrite(snapFileRef, &byteCount, (void*) &aSnapRecord); |
return err; |
} |
static OSErr CreateSnapshotFile(FSSpec snapFss) |
// Add the positions for the icons on the desktop to the snapshot file snapFss. |
{ |
OSErr err; |
short snapFileRef; |
short deskVRefNum; |
long deskDirID; |
CInfoPBRec pb; |
short fileIndex; |
Point folderOrigin; |
Point itemPosition; |
Str63 itemName; |
UInt32 systemVersion; |
snapFileRef = 0; |
// Find the desktop folder. |
err = FindFolder(kOnSystemDisk, kDesktopFolderType, true, &deskVRefNum, &deskDirID); |
// Get the origin for the desktop folder. |
pb.dirInfo.ioNamePtr = nil; |
pb.dirInfo.ioDrDirID = deskDirID; |
pb.dirInfo.ioVRefNum = deskVRefNum; |
pb.dirInfo.ioFDirIndex = -1; // get information about ioDirID |
err = PBGetCatInfoSync(&pb); |
if (err == noErr) { |
folderOrigin.h = 0; |
folderOrigin.v = 0; |
if (Gestalt(gestaltSystemVersion, (long *) &systemVersion) != noErr || systemVersion < 0x0800) { |
// Evil fudge factor is needed for Finder 7.x. Finder 8.0 does not fudge. |
folderOrigin.v = folderOrigin.v - 20; |
} |
} |
// Open up the snapshot file. |
if (err == noErr) { |
err = FSpOpenDF(&snapFss, fsRdWrPerm, &snapFileRef); |
} |
// Loop through each file in the folder, adding it to the snapshot file. |
if (err == noErr) { |
fileIndex = 1; |
do { |
pb.dirInfo.ioNamePtr = (StringPtr) itemName; |
pb.dirInfo.ioDrDirID = deskDirID; |
pb.dirInfo.ioVRefNum = deskVRefNum; |
pb.dirInfo.ioFDirIndex = fileIndex; |
err = PBGetCatInfoSync(&pb); |
if (err == noErr) { |
itemPosition = pb.hFileInfo.ioFlFndrInfo.fdLocation; |
SubPt(folderOrigin, &itemPosition); |
err = WriteFileRecord(snapFileRef, itemName, itemPosition); |
} |
fileIndex += 1; |
} while (err == noErr); |
// Write the sentinel to the end of the file. |
if (err == fnfErr) { |
itemName[0] = 0; |
itemPosition.h = 0; |
itemPosition.v = 0; |
err = WriteFileRecord(snapFileRef, itemName, itemPosition); |
} |
} |
// Clean up. |
if (snapFileRef != 0) { |
(void) FSClose(snapFileRef); |
} |
return err; |
} |
////////////////////////////////////////////////////////////////////////// |
// Main Line |
static void InitToolbox() |
// Standard Macintosh toolbox init. |
{ |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
MaxApplZone(); |
MoreMasters(); |
MoreMasters(); |
MoreMasters(); |
InitCursor(); |
FlushEvents(0, everyEvent); |
} |
void main(void) |
// The application's main entry point. |
{ |
OSErr err; |
FSSpec snapFss; |
long gestaltResponse; |
// First, a quick check to make sure we have Scriptable Finder. If we don't |
// we bail quickly. |
if ((Gestalt(gestaltFinderAttr, &gestaltResponse) != noErr) || ((gestaltResponse & (1 << gestaltOSLCompliantFinder)) == 0)) { |
DebugStr("\pWhoops, no Scriptable Finder."); |
ExitToShell(); |
} |
// Now bring up the standard Mac toolbox. |
InitToolbox(); |
// Find the Preferences folder. |
err = FindFolder(kOnSystemDisk, kPreferencesFolderType, false, &(snapFss.vRefNum), &(snapFss.parID)); |
if (err == noErr) { |
// Open the snapshot file in the Preferences folder. |
// Should get this from a resource, of course. |
(void) FSMakeFSSpec(snapFss.vRefNum, snapFss.parID, "\pDesktop Snap", &snapFss); |
err = FSpCreate(&snapFss, 'FR¿G', 'FR¿G', 0); |
if (err == dupFNErr) { // If we already have a snapshot file, |
err = RestoreSnapshot(snapFss); // restore icon positions, |
} else if (err == noErr) { // otherwise make a snapshot file. |
// Create the snapshot file for the desktop |
err = CreateSnapshotFile(snapFss); |
} |
} |
if (err != noErr) { |
DebugStr("\pSnapshotter failed."); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-17