ADC Home > Reference Library > Technical Notes > Carbon > User Experience >
|
Introducing
|
Note: This can be especially confusing when an
application promises In this Technote, I make an effort to avoid using the word "promise" in more than one sense at a time; nevertheless, read carefully. |
Important: The situation may even be worse. This document came into existence several years after the release of the Drag Manager. As a result, it's been difficult for early adopters of the Drag Manager to implement these flavors properly. And there may be applications which aren't as conscientious as yours. You should be extra careful to check error return values and build assertions into your code, so that your app is ready to cope with other apps which unexpectedly deviate from the conventions documented in this Note. |
Using flavorTypeHFS
In theory, usingflavorTypeHFS
data appears
simple, but in practice there are a few tricks you need to
know. The following sections document a few of those tricks
for you. For quick reference, here's a copy of the HFSFlavor
declaration from <Drag.h
>:
struct HFSFlavor { OSType fileType; // file type OSType fileCreator; // file creator unsigned short fdFlags; // Finder flags FSSpec fileSpec; // file system specification }; typedef struct HFSFlavor HFSFlavor; |
Sending flavorTypeHFS
To originate a drag containing flavorTypeHFS
data, you must first declare an HFSFlavor
record. This
record contains an FSSpec
and a few other fields which allow
some potential drag receivers to avoid calling FSpGetFInfo
.
The next step is to initialize the fileSpec
field
appropriately, then decide whether the data refers to a
file. If so, simply set the fileType
, fileCreator
, and
fdFlags
fields to match the appropriate information for the
file. If the flavorTypeHFS
data refers to a directory or
volume, set the fileType
and fileCreator
fields in the
HFSFlavor
record according to Table 1:
Table 1. The fileType
and fileCreator
fields
for the HFSFlavor
record
entity type |
|
|
directory (folder) |
|
|
volume (disk) |
|
|
These values are a hint to potential drag receivers that they are dealing with something other than a file. They are the same as the ones you would use in your application's bundle resource to let Finder know your app will accept folders and disks dropped onto your application's icon.
pascal OSErr MakeHFSFlavor (short vRefNum, long dirID, ConstStr255Param path, HFSFlavor register *hfsFlavorP) { OSErr err = noErr; if (!(err = FSMakeFSSpec (vRefNum,dirID,path,&(hfsFlavorP->fileSpec)))) { CInfoPBPtr cipbp = (CInfoPBPtr) NewPtrClear (sizeof (*cipbp)); if (!(err = MemError ( ))) { cipbp->hFileInfo.ioVRefNum = hfsFlavorP->fileSpec.vRefNum; cipbp->hFileInfo.ioDirID = hfsFlavorP->fileSpec.parID; cipbp->hFileInfo.ioNamePtr = hfsFlavorP->fileSpec.name; if (!(err = PBGetCatInfoSync (cipbp))) { hfsFlavorP->fdFlags = cipbp->hFileInfo.ioFlFndrInfo.fdFlags; if (hfsFlavorP->fileSpec.parID == fsRtParID) { hfsFlavorP->fileCreator = 'MACS'; hfsFlavorP->fileType = 'disk'; } else if (cipbp->hFileInfo.ioFlAttrib & ioDirMask) { hfsFlavorP->fileCreator = 'MACS'; hfsFlavorP->fileType = 'fold'; } else { hfsFlavorP->fileCreator = cipbp->hFileInfo.ioFlFndrInfo.fdCreator; hfsFlavorP->fileType = cipbp->hFileInfo.ioFlFndrInfo.fdType; } } DisposePtr ((Ptr) cipbp); if (!err) err = MemError ( ); } } return err; } |
Snippet 1. Deciding how to set the |
Coping with Finder Bugs
Dragging flavorTypeHFS
data from your
application to Finder has always supposed to have been
possible. However, Finder bugs have prevented most
applications from successfully using this feature.
From Finder's perspective, there are two cases for
receiving flavorTypeHFS
data. The second case
is more interesting.
- If the drop location is on the same volume as the
flavorTypeHFS
data, Finder simply moves the file to the drop location. - If the the drop location is on a different volume, Finder needs to copy the file to the new volume.
Finder is AppleEvent-intensive. It sends itself
AppleEvents to order itself to do all sorts of things,
including displaying the progress window for copying files.
However, Finder's drag-receiving code mistakenly sends these
particular AppleEvents to the front process instead of the
current process. The front process is generally the
application which originated the drag. Since the application
does not have handlers for these events, AppleEvent Manager
returns an error to Finder's AESend
call and Finder cancels
the entire operation.
Until this bug is fixed, your application can work around the problem by "handling" these AppleEvents. On systems under which Finder has been fixed, the handler will simply lie dormant in your app, because the AppleEvents will be sent to Finder, not your app. Unfortunately, it doesn't do any good to "reflect" these events back to the Finder; trust us, we've tried. This means you'll have to do without the progress dialog, but this is better than abject failure.
pascal OSErr BogusFinderEventHandler (const AppleEvent *, AppleEvent *, long) { return noErr; // just drop that bad boy on the floor } pascal OSErr InstallBogusFinderEventHandler (void) { OSErr err = noErr; static AEEventHandlerUPP bogusFinderEventHandlerUPP; if (!bogusFinderEventHandlerUPP) { bogusFinderEventHandlerUPP = NewAEEventHandlerProc (BogusFinderEventHandler); if (!bogusFinderEventHandlerUPP) err = nilHandleErr; else { err = AEInstallEventHandler ('cwin','****',bogusFinderEventHandlerUPP,0,false); if (err) { DisposeRoutineDescriptor (bogusFinderEventHandlerUPP); bogusFinderEventHandlerUPP = nil; } } } return err; } |
Snippet 2. Receiving bogus AppleEvents from Finder |
Receiving flavorTypeHFS
Receiving flavorTypeHFS
, often from Finder,
is much like receiving any other flavor of data. However, be
aware that some applications will offer you a truncated
record; they do not provide the unused bytes at the end of
the name field of the fileSpec
field of the HFSFlavor
record. (This is a bug in the sending application, but if
it's not your app, you probably don't have an opportunity to fix it.)
static pascal Size MinimumBytesForFSSpec (const FSSpec *fss) { // callers can and do assume this does not move memory return sizeof (*fss) - sizeof (fss->name) + *(fss->name) + 1; } |
Snippet 3. Calculating minimum bytes for
(called from snippets #4 , #6, and #14) |
pascal OSErr GetHFSFlavorFromDragReference (DragReference dragRef, ItemReference itemRef, HFSFlavor *hfsFlavor) { OSErr err = noErr; Size size = sizeof (*hfsFlavor); err = GetFlavorData (dragRef,itemRef,flavorTypeHFS,hfsFlavor,&size,0); if (!err) { Size minSize = sizeof (*hfsFlavor) - sizeof (hfsFlavor->fileSpec); minSize += MinimumBytesForFSSpec (&(hfsFlavor->fileSpec)); // see snippet 3 for MinimumBytesForFSSpec if (size < minSize) err = cantGetFlavorErr; } return err; } |
Snippet 4. Extracting |
Using flavorTypePromiseHFS
Using flavorTypePromiseHFS
data is significantly more
complicated than using flavorTypeHFS
data. The chief area of
confusion is centered on the multi-part nature of
flavorTypePromiseHFS
data. For quick reference, here's a
copy of the PromiseHFSFlavor
declaration from
<Drag.h
>:
struct PromiseHFSFlavor { OSType fileType; // file type OSType fileCreator; // file creator unsigned short fdFlags; // Finder flags FlavorType promisedFlavor; // promised flavor }; typedef struct PromiseHFSFlavor PromiseHFSFlavor; |
Sending flavorTypePromiseHFS
Promising to Create a File
Before calling TrackDrag
, your application
should call AddDragItemFlavor
twice, passing
the same ItemReference
value both times, once
for each part of the data.
For the first call, declare a record of type
PromiseHFSFlavor
and put 'fssP'
(0x66737350) in the promisedFlavor
field. The
Drag Manager Programmer's Guide tells you to
put any value you like into promisedFlavor
, but
we're now recommending this specific value. (Details can be
found below; if your application already uses something
else, don't worry too much right now unless it's
'rWm1'
.) Fill in the other fields of the
PromiseHFSFlavor
record appropriately and add
the record to the DragReference
, passing
flavorTypePromiseHFS
for the
FlavorType
parameter.
With the second call to AddDragItemFlavor
,
pass 'fssP'
for the FlavorType
parameter. Pass 0 for the dataPtr
and
dataSize
parameters to set up a promise to be
kept later.
pascal OSErr AddDragItemFlavorTypePromiseHFS (DragReference dragRef, ItemReference itemRef, OSType fileType, OSType fileCreator, UInt16 fdFlags, FlavorType promisedFlavor) { OSErr err = noErr; PromiseHFSFlavor phfs; phfs.fileType = fileType; phfs.fileCreator = fileCreator; phfs.fdFlags = fdFlags; phfs.promisedFlavor = promisedFlavor; if (!(err = AddDragItemFlavor (dragRef,itemRef,flavorTypePromiseHFS, &phfs,sizeof(phfs),flavorNotSaved))) { err = AddDragItemFlavor (dragRef,itemRef,promisedFlavor,nil,0,flavorNotSaved); } return err; } |
Snippet 5. Adding |
Important: |
Note: |
Add any other flavors you might want to
provide in this DragReference
, and you're ready
to call TrackDrag
.
Keeping the Promise
When Drag Manager requests a FlavorType
equal to the
promisedFlavor
field of your flavorTypePromiseHFS
data, it's
your cue to keep your promise by delivering the
file. Keeping the promise involves finding out where the
drag receiver wants the file to end up, deciding where to
create the file, and creating the file. You'll do this in
your DragSendDataProc
associated with the DragReference
.
Getting the Drop Location
First, your DragSendDataProc
will need to find out where
the drag receiver wants the file. You'll need to call
GetDropLocation
, which will produce an AEDesc
record. The type of the data found in this record is defined
by the drag receiver. Finder, for example, provides typeAlias
data. To convert this data to an
FSSpec
, coerce its type to typeFSS
and copy the FSSpec
data
out of the resulting descriptor.
pascal OSErr GetDropDirectory (DragReference dragRef, FSSpecPtr fssOut) { OSErr err = noErr; AEDesc dropLocAlias = { typeNull, nil }; if (!(err = GetDropLocation (dragRef,&dropLocAlias))) { if (dropLocAlias.descriptorType != typeAlias) err = paramErr; else { AEDesc dropLocFSS = { typeNull, nil }; if (!(err = AECoerceDesc (&dropLocAlias,typeFSS,&dropLocFSS))) { // assume MinimumBytesForFSSpec does not move memory FSSpecPtr fss = (FSSpecPtr) *(dropLocFSS.dataHandle); BlockMoveData (fss,fssOut,MinimumBytesForFSSpec(fss)); // see snippet 3 for MinimumBytesForFSSpec err = AEDisposeDesc (&dropLocFSS); } } if (dropLocAlias.dataHandle) { OSErr err2 = AEDisposeDesc (&dropLocAlias); if (!err) err = err2; } } return err; } |
Snippet 6. Extracting the drop folder |
Note: |
If the drop location data is not of typeAlias
, the call to
AECoerceDesc
will fail.
Your DragSendDataProc
will probably want to provide no data
and return an error in this situation. However, be aware
that applications other than Finder are free to provide a
drop location of typeAlias
(and some even do), so don't rely
on typeAlias
signifying that Finder is the drop receiver.
Note: |
Note: |
Creating the File
Once you've decided where to put the file, you can create it by calling a function like this one:
pascal OSErr CreatePromisedFileOrFolder (const PromiseHFSFlavor *phfs, const FSSpec *fss, ScriptCode scriptTag) { OSErr err = noErr; if (phfs->promisedFlavor == kPromisedFlavorFindFile) err = paramErr; else if (phfs->fileType == 'disk') err = paramErr; else if (phfs->fileType == 'fold') err = CreatePromisedFolder (phfs,fss,scriptTag); // see Snippet 9 else err = CreatePromisedFile (phfs,fss,scriptTag); // see Snippet 8 return err; } |
Snippet 7. Creating the promised file or folder |
static pascal CreatePromisedFile (const PromiseHFSFlavor *phfs, const FSSpec *fss, ScriptCode scriptTag) { OSErr err = noErr; if (!(err = FSpCreate (fss,phfs->fileCreator,phfs->fileType,scriptTag))) { if (phfs->fdFlags) { FInfo finderInfo; if (!(err = FSpGetFInfo (fss,&finderInfo))) { finderInfo.fdFlags = phfs->fdFlags; err = FSpSetFInfo (fss,&finderInfo); } } } return err; } |
Snippet 8. Called by snippet #7 |
static pascal CreatePromisedFolder (const PromiseHFSFlavor *phfs, const FSSpec *fss, ScriptCode scriptTag) { OSErr err = noErr; long newDirID; // scratch if (!(err = FSpDirCreate (fss,scriptTag,&newDirID))) { if (phfs->fdFlags) { DInfo finderInfo; // see Appendix B for FSpGetDInfo and FSpSetDInfo if (!(err = FSpGetDInfo (fss,&finderInfo))) { finderInfo.frFlags = phfs->fdFlags; err = FSpSetDInfo (fss,&finderInfo); } } } return err; } |
Snippet 9. Called by Snippet #7 |
Deferring Writing the File
Once the file is created, you may or may not want to
write its contents in your DragSendDataProc
. If the file is
large or your app needs some time to generate the data that
will be in the file, you may want to defer writing the file.
Since Process Manager context switches are disabled during Drag
Manager callbacks, other applications would get no execution
time if you were to spend time writing the file, even if it
were safe to periodically call WaitNextEvent
, which it is
not.
In this situation, you'll want to open the file in your
DragSendDataProc
and leave it open. In addition, set a
flag to tell another part of your
application it needs to write the file. After TrackDrag
returns, have that part of your app write the file with
periodic calls to WaitNextEvent
.
Finishing the Drag
Once (and only if) the file has been successfully
created, you should let the drag receiver know what the
filename was and where the file was created. To do this,
call SetItemFlavorData
. For the FlavorType
parameter, pass
the value of the promisedFlavor
field of the
PromiseHFSFlavor
record. For the flavor data, pass an FSSpec
record describing the name and location of the file. The
promisedFlavor
data should always be an FSSpec
, not an
HFSFlavor
. This snippet consists of simple glue which adds
the data correctly:
pascal OSErr SetPromisedHFSFlavorData (DragReference dragRef, ItemReference itemRef, const PromiseHFSFlavor *phfs, const FSSpec *fss) { return SetDragItemFlavorData (dragRef,itemRef,phfs->promisedFlavor,fss,sizeof(*fss),0); } |
Snippet 10. Adding the promised |
Impersonating Find File
If you need to provide a DragReference
which refers to an
existing file or files, then if at all possible you should
be sending flavorTypeHFS
. But if you discover a compelling
reason to send flavorTypePromiseHFS
instead, make sure you:
- Set the
promisedFlavor
field of yourPromiseHFSFlavor
record to 'rWm1
' (0x72576D31). - When Drag Manager asks your
DragSendDataProc
for'rWm1'
data andGetDropLocation
produces anAEDesc
whosedescriptorType
field containstypeNull
, provide the original location of the file. - If
GetDropLocation
produces anAEDesc
whosedescriptorType
field containstypeAlias
, copy the file into the drop location.'rWm1'
is only a hint to the drag receiver, and the drag receiver may not take the hint.
Important: |
The section Coping with Find File elsewhere in this Note details why these steps are necessary. The following snippet implements a decision tree which tells its caller whether to copy a file the caller is dropping:
pascal OSErr ShouldCopyToDropLoc (DragReference dragRef, FlavorType promisedFlavor, Boolean *shouldCopy) { OSErr err = noErr; AEDesc dropLoc = { typeNull, nil }; *shouldCopy = false; if (!(err = GetDropLocation (dragRef,&dropLoc))) { if (dropLoc.descriptorType == typeAlias) { // no hint or receiver missed it *shouldCopy = true; } else if (dropLoc.descriptorType != typeNull) { // unknown drop location descriptor type err = paramErr; } else if (promisedFlavor != kPromisedFlavorFindFile) { // null descriptor but no hint intended (DragPeeker) err = dirNFErr; } if (dropLoc.dataHandle) { OSErr err2 = AEDisposeDesc (&dropLoc); if (!err) err = err2; } } return err; } |
Snippet 11. Deciding whether to copy a dropped file |
Receiving flavorTypePromiseHFS
Most applications have no need to receive
flavorTypePromiseHFS
data; flavorTypeHFS
should suffice for
most needs. More senders provide flavorTypeHFS
, although
there is at least one important application (Find File)
which provides flavorTypePromiseHFS
. In any case, seriously
consider flavorTypeHFS
before investing effort in
flavorTypePromiseHFS
.
Getting the Two Flavors
In your drag tracking handler, you may retrieve the
flavorTypePromiseHFS
data, which is a PromiseHFSFlavor
, but
don't try to retrieve the promisedFlavor
data. Your drag
tracking handler can't know whether a given window in your
application will be the ultimate receiver of the data
- the ultimate receiver might be another window in
your app or one of the windows of another app. If your drag
tracking handler were to ask for the promisedFlavor
data, Drag Manager would call the sender's SendDataProc
, and
the data would thereafter be cached in the DragReference
.
Consequently, other potential receivers would get the
cached data and the sender would not have a chance to adjust
it according to the receiver's drop location.
In your drag receive handler, it's safe to retrieve both
the flavorTypePromiseHFS
data and the promisedFlavor
data.
Before requesting the promisedFlavor
data, however, make
sure to call SetDropLocation
. The next snippet is a function
which administrates this process. Note that the folder
parameter can be NIL
; this means the caller
supports Find File; we'll explain how this works and why
you'd want to do it a little later.
pascal OSErr ReceivePromisedFile (DragReference dragRef, ItemReference itemRef, HFSFlavor *hfsFlavor, const FSSpec *folder) { OSErr err = noErr; if (folder) // see Snippet 13 for SetDropFolder err = SetDropFolder (dragRef,folder); if (!err) { // we'll explain 'isSupposedlyFromFindFile' later Boolean isSupposedlyFromFindFile = (folder == nil); err = GetHFSFlavorFromPromise // see snippet 14 (dragRef, itemRef, hfsFlavor, isSupposedlyFromFindFile); } return err; } |
Snippet 12. Receiving |
Setting the Drop Location
This part of receiving flavorTypePromiseHFS
is relatively easy. First, create an alias to the drop
location, which for flavorTypePromiseHFS
should
always be a directory. Next, copy the alias into an
AEDesc
. Finally, call
SetDropLocation
. This procedure is demonstrated
in the next snippet.
static pascal OSErr SetDropFolder (DragReference dragRef, const FSSpec *folder) { OSErr err = noErr; AliasHandle aliasH; if (!(err = NewAliasMinimal (folder,&aliasH))) { HLockHi ((Handle) aliasH); if (!(err = MemError ( ))) { Size size = GetHandleSize ((Handle) aliasH); if (!(err = MemError ( ))) { AEDesc dropLoc; if (!(err = AECreateDesc (typeAlias,*aliasH,size,&dropLoc))) { OSErr err2; err = SetDropLocation (dragRef,&dropLoc); err2 = AEDisposeDesc (&dropLoc); if (!err) err = err2; } } } DisposeHandle ((Handle) aliasH); if (!err) err = MemError ( ); } return err; } |
Snippet 13. Called by Snippet #12 |
Coping with Find File
Many drag receivers would like to be able to receive data
dragged from a Find File results window. The first flavor
most developers would look for in the DragReference
would be
flavorTypeHFS
. However, Find File provides
flavorTypePromiseHFS
instead, in an attempt to work around
Finder bugs mentioned elsewhere in this Technote.
The True Nature of Find File's Evil: A Sidebar
Find File's workaround works pretty well within
the scope of Finder, but it doesn't work very well
with many other applications which receive
flavorTypePromiseHFS
. You'll remember that
flavorTypePromiseHFS
is a promise to create a file
which doesn't exist yet, but Find File's results
window contains only existing files. Right away
there's semantic conflict. Let's look at a concrete
example to see how this conflict can cause
problems:
If an email application were to accept
flavorTypePromiseHFS
as an enclosure to a message
and assumed that the drag sender were honoring the
semantics of flavorTypePromiseHFS
as documented in
this Technote, the email app would probably want to
set the drop location to its outgoing spool folder
and delete the file when the associated message
were successfully sent. After all, the semantics of
flavorTypePromiseHFS
are to create a file expressly
for the exclusive use of the receiving app.
However, if instead Find File were merely to move a pre-existing file into that spool folder, the email app might well be deleting the user's only copy of that data, and at the very least Find File would be moving a file to a place the user isn't likely to expect or understand. This is in fact what Find File does.
Why? Well, since Finder is buggy, Find File
convinces Finder a drop has occurred and then
proceeds to delete the dropped file and send
AppleEvents to Finder to induce it to do what it
should have done with flavorTypeHFS
on its own.
The only data Find
File really wants from Finder is the drop location.
Regardless of any of the background information in this sidebar, your application should conform as strictly as possible to the rest of this Technote.
Working Around Find File
The Find File engineers didn't just bludgeon the Finder into working the way they wanted; they also provided a way for other applications to receive HFS-related drags sensibly. It just hasn't been documented until now.
In your drag tracking handler, retrieve the
flavorTypePromiseHFS
data and compare its promisedFlavor
field to 'rWm1'
(0x72576D31). This is the value which Find
File always uses. If promisedFlavor
has this value, set a
flag to remind you not to call SetDropLocation
later.
In your drag receive handler, you'd normally call
SetDropLocation
before asking for the promisedFlavor
data.
However, if you're receiving flavorTypePromiseHFS
data from
Find File, skip this step before asking the Drag Manager for
the promisedFlavor
data (and, of course, in this case
promisedFlavor
will always have the value 'rWm1'
).
This will
produce FSSpec
data without inducing Find File to move or
copy the file.
And now we can see why the value of promisedFlavor
is
important; if it's 'rWm1'
, the data comes from Find File,
and if the value is anything else (we've recommended 'fssP'
[0x66737350]; but if your program already uses
something else, don't worry about it), the data comes from
some other application. Applications other than Find File
should conform to the semantics of
flavorTypePromiseHFS
as documented in this Technote.
The next snippet shows how to retrieve both flavors, with some extra checking thrown in to make sure nobody is confused about Find File.
static pascal OSErr GetHFSFlavorFromPromise (DragReference dragRef, ItemReference itemRef, HFSFlavor *hfs, Boolean isSupposedlyFromFindFile) { OSErr err = noErr; PromiseHFSFlavor phfs; Size size = sizeof (phfs); err = GetFlavorData (dragRef,itemRef,flavorTypePromiseHFS,&phfs,&size,0); if (!err) { if (size != sizeof (phfs)) err = cantGetFlavorErr; else { Boolean isFromFindFile = phfs.promisedFlavor == kPromisedFlavorFindFile; if (isSupposedlyFromFindFile != isFromFindFile) err = paramErr; else { size = sizeof (hfs->fileSpec); err = GetFlavorData (dragRef,itemRef,phfs.promisedFlavor, &(hfs->fileSpec),&size,0); if (!err) { Size minSize = MinimumBytesForFSSpec (&(hfs->fileSpec)); // see snippet 3 for MinimumBytesForFSSpec if (size < minSize) err = cantGetFlavorErr; else { hfs->fileType = phfs.fileType; hfs->fileCreator = phfs.fileCreator; hfs->fdFlags = phfs.fdFlags; } } } } } return err; } |
Snippet 14. Called by Snippet #12 |
Summary
There are two file system-oriented flavor types
associated with the Drag Manager. One,
flavorTypeHFS
, is a relatively simple flavor
which can be handled like most others except for some simple
workarounds for bugs in Finder. The other,
flavorTypePromiseHFS
, is probably the most
complex flavor type developers will encounter and requires a
high degree of care, attention to detail, and tolerance for
intrusive workarounds to implement correctly.
Here are some important lessons worth repeating:
- For existing files, use
flavorTypeHFS
. For files which don't yet exist but you're willing to create, useflavorTypePromiseHFS
. - Don't confuse the Drag Manager's concept of promising
flavor data with
flavorTypePromiseHFS
. They're both promises, but they are significantly different kinds of promises. - Check all error codes and build assertions into your code to avoid being surprised by applications which don't conform to the behavior you expect.
GetDropLocation
andSetDropLocation
are your friends.- When receiving
flavorTypePromiseHFS
for a file you plan to delete, make sure you do the right thing with Find File to avoid destroying data the user wanted to keep.
References
The Drag Manager Programmer's Guide, available on the Developer CD Series Mac OS SDK disc. In addition, you can download it here.
AEDesc
is an AppleEvent Manager data
structure documented starting on page 3-12 of
Inside Macintosh: Interapplication Communication.
Appendices
The Appendices to this Technote contain code snippets which are necessary for a full understanding of other snippets in the Technote but would have obstructed the flow of the main text stream.
Appendix A
This is a utility function called by the functions in
Appendices B and C. It allocates and populates a
CInfoPBRec
so that it contains information on
the given directory. The caller is expected to dispose the
CInfoPBRec
if the function does not return an error.
static pascal OSErr FSpGetDirInfo (const FSSpec *spec, CInfoPBPtr *cipbpp) { OSErr err = noErr; CInfoPBPtr pbp = (CInfoPBPtr) NewPtrClear (sizeof (*pbp)); *cipbpp = nil; if (!(err = MemError ( ))) { pbp->dirInfo.ioVRefNum = spec->vRefNum; pbp->dirInfo.ioDrDirID = spec->parID; pbp->dirInfo.ioNamePtr = (StringPtr) spec->name; err = PBGetCatInfoSync (pbp); if (!err && !(pbp->hFileInfo.ioFlAttrib & ioDirMask)) err = dirNFErr; if (err) DisposePtr ((Ptr) pbp); else *cipbpp = pbp; } return err; } |
Appendix B
These functions are intended to follow the same API as
FSpGetFinfo
and FSpSetFInfo
. They both call
FSpGetDirInfo
, which can be found in Appendix
A.
static pascal OSErr FSpGetDInfo (const FSSpec *spec, DInfo *fndrInfo) { OSErr err = noErr; CInfoPBPtr cipbp; if (!(err = FSpGetDirInfo (spec,&cipbp))) { *fndrInfo = cipbp->dirInfo.ioDrUsrWds; DisposePtr ((Ptr) cipbp); if (!err) err = MemError ( ); } return err; } static pascal OSErr FSpSetDInfo (const FSSpec *spec, const DInfo *fndrInfo) { OSErr err = noErr; CInfoPBPtr cipbp; if (!(err = FSpGetDirInfo (spec,&cipbp))) { cipbp->dirInfo.ioDrUsrWds = *fndrInfo; cipbp->dirInfo.ioDrDirID = spec->parID; err = PBSetCatInfoSync (cipbp); DisposePtr ((Ptr) cipbp); if (!err) err = MemError ( ); } return err; } |
Appendix C
This function returns the directory ID of a given folder.
It calls FSpGetDirInfo
, which can be found in Appendix A.
pascal OSErr GetDirectoryID (const FSSpec *spec, long *dirID) { OSErr err = noErr; CInfoPBPtr cipbp; if (!(err = FSpGetDirInfo (spec,&cipbp))) { *dirID = cipbp->dirInfo.ioDrDirID; DisposePtr ((Ptr) cipbp); if (!err) err = MemError ( ); } return err; } |
Downloadables
Acrobat version of this Note (92K). |
||
Acrobat version of Drag Manager Programmer's Guide (378K) |
||
Binhexed FinderDragPro Metrowerks Project (220K) |