Re: Adding AppleScript Studio Support to a Cocoa Application
Re: Adding AppleScript Studio Support to a Cocoa Application
- Subject: Re: Adding AppleScript Studio Support to a Cocoa Application
- From: Jeffrey Mattox <email@hidden>
- Date: Mon, 3 Mar 2003 00:47:38 -0600
At 8:00 PM -0800 3/2/03, matt neuburg wrote:
On Sun, 2 Mar 2003 09:23:25 -0800, Chuck Rice <email@hidden> said:
I think I have completed the steps in
"Adding AppleScript Studio Support to Your Cocoa Application"
From the "Building Applications With AppleScript Studio" doc.
Good, although it's much easier to let PB do this by creating your project
as a studio project to start with.
But I do not understand how to communicate calls and parameters back
and forth between Objective-C and my script handlers. What do I need
to search-for/read?
Calling into Objective-C code from AppleScript, at least, is
straightforward. Read up on call method. There is a good example (the
multi-lingual example) on your hard drive. Sending a message to a class is
trivial. The main trick is when you want to send a message to an instance;
this is why people often put code in the application delegate, since this
is an instance you can readily get hold of from AppleScript. You can then
springboard off of this to get at any instance you want.
Going the other way (calling into Appplescript from Objective-C) is quite
tricky. Personally I find it easiest to have Cocoa "press" a hidden button
that has an Applescript handler, but of course you have to play some
additional games to pass parameters. If a script consists of just top
level commands you can execute it through the NSAppleScript class. At the
other extreme, you can execute a specific handler in a specific script
with executeEvent, and pass any parameters you like, but it's a pain the
butt (check the archives for code, I know there's been some). I really
think Apple ought to provide an easier way to cross the bridge in this
direction. m.
I've been using the following code to call AppleScript handlers by
name from Cocoa. This logic assumes the AS handler returns a boolean
true/false. It could be changed to return other types, or the AS
handler could use "call method" to pass any number of things back to
cocoa before returning true/false.
Usage example (don't you wish all the doc had these :-):
OSStatus theResult;
// CallAppleSCriptHandler(@"as_handler_name_lowercase", int_1, int_2);
theRet = CallAppleSCriptHandler(@"ashandler", 101, 102);
if ( theRet ) {
// "ashandler" handler returned "true"
} else {
// "ashandler" handler returned "false"
}
Cocoa: The basis of this was posted by Brian Webster in January
("Re: Calling AppleScript from Cocoa"). I've added some debugging
code and generalized it. You call it with an argument naming the
handler (which must be all lower case), and two integer values.
Passing more arguments is easy, but all of your handlers must have
the same number and type of args. Here, the two arguments are
assumed to be integers -- that can be changed, too. Change
"myPgmName" to your program bundle name.
BOOL CallAppleSCriptHandler(NSString *theHandler, int argument1,
int argument2)
{
// Reference:
//
http://lists.apple.com/archives/cocoa-dev/2003/Jan/21/callingapplescriptfromco.001.txt
SAppleScript* myScript;
NSAppleEventDescriptor* event;
NSAppleEventDescriptor* targetAddress;
NSAppleEventDescriptor* subroutineDescriptor;
NSAppleEventDescriptor* arguments;
NSAppleEventDescriptor* result;
NSDictionary* myErrorDict = nil;
int pid = [[NSProcessInfo processInfo] processIdentifier];
// NSLog(@"pid = %d\n",pid);
NSString *theCompiledScript;
// NSLog(@"mainBundle %@\n",[NSBundle mainBundle]);
theCompiledScript = [[NSBundle mainBundle] pathForResource:@"myPgmName"
ofType:@"scpt" inDirectory:@"Scripts"];
// NSLog(@"FtheCompiledScript %@\n",theCompiledScript);
NSDictionary *theError = [NSDictionary dictionary];
NSURL *theURL = [[NSURL alloc] initFileURLWithPath:theCompiledScript];
myScript = [[NSAppleScript alloc] initWithContentsOfURL:theURL
error:&theError];
// describes the target application (self)...
targetAddress = [[NSAppleEventDescriptor alloc]
initWithDescriptorType:typeKernelProcessID
bytes:&pid length:sizeof(pid)];
event = [[NSAppleEventDescriptor alloc]
initWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:targetAddress
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
// theHandler must be lower case
subroutineDescriptor = [NSAppleEventDescriptor
descriptorWithString:theHandler];
[event setParamDescriptor:subroutineDescriptor
forKeyword:keyASSubroutineName];
arguments = [[NSAppleEventDescriptor alloc] initListDescriptor];
// add stuff to your arguments list
[arguments insertDescriptor:[NSAppleEventDescriptor
descriptorWithInt32:argument1] atIndex:0 ];
[arguments insertDescriptor:[NSAppleEventDescriptor
descriptorWithInt32:argument2] atIndex:0 ];
// [arguments insertDescriptor:[NSAppleEventDescriptor
descriptorWithInt32:argument3] atIndex:0 ];
// NSLog(@"calling arguments %@\n",arguments);
// NSLog(@"calling myScript %@\n",myScript);
// NSLog(@"calling subroutineDescriptor %@\n",subroutineDescriptor);
[event setParamDescriptor:arguments forKeyword:keyDirectObject];
// Here we go!!! Execute the AS handler...
result = [myScript executeAppleEvent:event error:&myErrorDict];
// NSLog(@"done, result=%@\n",result);
// NSLog(@"done, return=%d\n",[result booleanValue]);
if ( myErrorDict ) { // AS error, debug...
NSLog(@"error, myErrorDict=%@\n",myErrorDict);
}
[theURL release];
[targetAddress release];
[myScript release];
[event release];
[arguments release];
return([result booleanValue]);
}
Enjoy. Improve.
Jeff
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.