Re: path name from Apple Event
Re: path name from Apple Event
- Subject: Re: path name from Apple Event
- From: Bill Monk <email@hidden>
- Date: Tue, 16 Aug 2005 12:33:08 -0500
they always work as long as one is using the proper - cat-specific
- way of accessing them.
This code seems to work:
if ( we run on Tiger )
{
// Panther would return nil for coerceToDescriptorType:
typeFileURL
NSAppleEventDescriptor *urlDesc = [ aliasED
coerceToDescriptorType: typeFileURL];
}
else // we run on Panther
{
// Tiger would return paramErr for FSResolveAliasWithMountFlags
FSResolveAliasWithMountFlags()
};
Well, the reason why ResolveAlias is failing here is that you're
handing it what used to be called a "fake handle" (there was a Tech
Note on the subject back in the deeps of time). Unfortunately when
you dig very deep into Apple Events, you enter the Carbon world, and
its rules apply. A Handle is not just a pointer to a pointer cobbled
together with a bit of C...
This code:
void *bytes = malloc( len );
[ data getBytes: bytes ];
AliasPtr aliasPtr = bytes ;
AliasHandle aliasHandle = &aliasPtr ;
won't work. That is the very definition of a fake handle, and if it
works on Panther, it's an accident and not to be depended upon. Tiger
is evidently more strict, hence the paramErr. (FWIW, Carbon paramErrs
always mean exactly that - in my experience, they are *always* my
fault.)
A second problem in the code is this:
NSAppleEventDescriptor *dirctObj = [ event descriptorForKeyword:
keyDirectObject ];
NSAppleEventDescriptor *aliasED = [ dirctObj descriptorAtIndex: 1 ];
NSData *data = [ aliasED data ];
This assumes the direct object will be a 'list' descriptor containing
'alis' descriptors. But it doesn't have to be that way. For a single
file, the direct object may just be an 'alis'; there doesn't have to
be a list at all. If this happens, and it will, the above code tries
to get the data from the wrong place.
I haven't verified it, but I'll bet this is why
coerceToDescriptorType: isn't working for you under Panther. Either
Panther (or more likely, the version of Xcode running there, since
your app gets these events from Xcode) is passing a single alias as
the direct object, not as the list of aliases your code expects. If
so, descriptorAtIndex: then hands you a typeNull descriptor when you
ask for item 1 of the list. typeNull obviously can't coerce to
typeFileURL, so it appears not to work on Panther.
In Xcode 2.x, (and who knows why, but there doesn't have to be a
reason why, both ways are valid) single aliases are evidently passed
as a one-item list of aliases within the direct object, and not *as*
the direct object. In this case, your NSData code would work, but
then the fake handle would cause Tiger's more strict ResolveAlias()
to fail, and so it seems ResolveAlias() isn't working on Tiger.
I'm guessing the problems are not actually OS-related, but simply due
to different Xcode versions and how they send 'odoc' events, along
with a Carbon-era gotcha and a fairly obscure Apple Event detail.
Here's some code. It's going to wrap horribly. But it should help:
- (void)handleODOCEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
{
OSErr myErr = noErr;
NSAppleEventDescriptor *dirObj = [event
descriptorForKeyword:keyDirectObject];
DescType dirObjType = [dirObj descriptorType];
NSData *data;
FSRef fsRef;
Boolean wasChanged;
AliasHandle aliasHandle;
if ( dirObjType == 'alis' ) { // open one file
data = [dirObj data];
aliasHandle = (AliasHandle)NewHandle( [data length] ); //
get a real Handle
if ( NULL != aliasHandle ) {
[data getBytes: *aliasHandle];
myErr = FSResolveAliasWithMountFlags(NULL, aliasHandle,
&fsRef, &wasChanged, kResolveAliasFileNoUI);
DisposeHandle( (Handle)aliasHandle );
CFURLRef resolvedUrl = CFURLCreateFromFSRef(NULL, &fsRef);
NSString *resolvedPath = (NSString*)
CFURLCopyFileSystemPath( resolvedUrl, kCFURLPOSIXPathStyle);
CFRelease(resolvedUrl);
NSLog( @"Path: %@", resolvedPath );
// do whatever with resolvedPath
}
} else if ( dirObjType == 'list' ) { // open many files
aliasHandle = (AliasHandle)NewHandle( 0L ); // get a real
Handle; we'll resize as needed.
if ( NULL != aliasHandle ) {
int numItems = [dirObj numberOfItems];
int i;
for ( i = 1; i <= numItems; i++ ) {
NSAppleEventDescriptor *thisAlias = [dirObj
descriptorAtIndex:i];
data = [thisAlias data];
SetHandleSize( (Handle)aliasHandle, [data length] );
myErr = MemError();
if ( noErr == myErr ) {
[data getBytes: *aliasHandle];
myErr = FSResolveAliasWithMountFlags(NULL,
aliasHandle, &fsRef, &wasChanged, kResolveAliasFileNoUI);
if ( noErr == myErr ) {
CFURLRef resolvedUrl = CFURLCreateFromFSRef
(NULL, &fsRef);
NSString *resolvedPath = (NSString*)
CFURLCopyFileSystemPath(resolvedUrl, kCFURLPOSIXPathStyle);
CFRelease(resolvedUrl);
NSLog( @"Path: %@", resolvedPath );
// do whatever with resolvedPath
}
}
}
DisposeHandle( (Handle)aliasHandle );
}
}
// Would need more logic to decide whether to fill in an error
reply;
// for example, if one alias out of a long list failed to
resolve, we
// probably would not complain.
if ( (noErr != myErr) && ([replyEvent descriptorType] !=
typeNull) ) {
NSAppleEventDescriptor *errNumDesc = [NSAppleEventDescriptor
descriptorWithInt32:myErr];
[replyEvent setParamDescriptor:errNumDesc
forKeyword:keyErrorNumber];
NSAppleEventDescriptor *errStrDesc = [NSAppleEventDescriptor
descriptorWithString:@"Complain."];
[replyEvent setParamDescriptor:errStrDesc
forKeyword:keyErrorString];
}
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden