Re: Objective-C and AppleScript
Re: Objective-C and AppleScript
- Subject: Re: Objective-C and AppleScript
- From: Mike Fischer <email@hidden>
- Date: Tue, 02 Sep 2008 04:06:04 +0200
Am 01.09.2008 um 22:49 schrieb John Love <email@hidden>:
I am trying to convert as much as I can of my former Studio code over
to Obj-C and thanks to this Mailing List I have been successful so
far .. but here's a stumper or two:
Here are 2 AppleScript statements that work in Studio:
-- #1 works in Obj-C, so my question is = isn't there a more
*direct*
Obj-C call to do the same thing,
-- rather than call NSAppleScript's executeAndReturnError method?
It
just seems that a one or two
-- system calls should effect the same result?
1) tell application "System Events" to return (name of every
application process contains "Microsoft Excel") -- see ExcelAppActive
below
You could use something like this:
NSArray *result = [[[[NSWorkspace sharedWorkspace]
launchedApplications] filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"%K contains %@", @"NSApplicationName",
@"Microsoft Excel"]] valueForKey:@"NSApplicationName"];
Or even better (assuming Excel has the bundle ID "com.microsoft.excel"):
NSArray *result = [[[[NSWorkspace sharedWorkspace]
launchedApplications] filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"%K = %@", @"NSApplicationBundleIdentifier",
@"com.microsoft.excel"]] valueForKey:@"NSApplicationName"];
Both result in an array of running application names matching the
criteria just like the AppleScript code above.
(Typed in Mail.app)
=====
-- If I hard-code the actual name of the file
stringByAppendingString:@"some title" (see theWorkbookActive method
below),
-- everything works dandy.
--
-- But ... this name is actually a instance parameter, NSString*
itsFileName, defined in my .h file, and dynamically set in my .m file.
-- So, I type stringByAppendingString:itsFileName -- but then my app
crashes.
Sounds like a memory management problem. How are you defining and
initializing itsFileName exactly?
2) tell application "Microsoft Excel" to return (name of every window
contains "some title")
Here is the standard (I believe) method to execute the passed Script:
- (NSAppleEventDescriptor*) ExecAppleScript:(NSString*)theScript {
NSAppleScript *scriptObject;
NSDictionary *errorInfo;
NSAppleEventDescriptor *execResult;
scriptObject = [[NSAppleScript alloc] initWithSource:theScript];
errorInfo = [[NSDictionary alloc] init];
You don't allocate any errorInfo object here. That is done for you if
an error occurs. Your code would leak the NSDictionary. In any case
an NSDictionary would do no good as it isn't mutable. You might want
to initialize errorInfo to nil though.
execResult = [scriptObject executeAndReturnError:&errorInfo];
Where are you releasing scriptObject? You're not? That's a memory leak!
return execResult; // success = (execResult != nil)
}
- (BOOL) ExcelAppActive {
BOOL ExcelActive = FALSE;
Cocoa uses YES and NO as constants for the BOOL type.
NSAppleEventDescriptor *execResult;
NSArray *ExcelActiveScriptArray = [NSArray arrayWithObjects:
@"tell application \"System Events\"",
@"return (name of every application process contains
\"Microsoft Excel\")",
@"end tell",
nil];
No AppleScript necessary, see above.
And AppleScript allows this syntax: tell application "xyz" to blah
Instead of: tell application "xyz"
blah
end tell
That would have saved you the trouble of assembling a string fron an
array. Or you could have used \n to assemble the string in one go
like this:
NSString *ExcelActiveScriptString = @"tell application
\"System Events\"\n"
"return (name of every application process contains
\"Microsoft Excel\")\n"
"end tell";
NSString *ExcelActiveScriptString =
[ExcelActiveScriptArray componentsJoinedByString:@"\n"];
/*
tell application "System Events"
return (name of every application process contains "Microsoft Excel")
end tell
*/
execResult = [self ExecAppleScript:ExcelActiveScriptString];
if (execResult != nil) { // success
ExcelActive = [execResult booleanValue];
}
If you use the pure Cocoa method described above you would check the
result array for count > 0 like this:
ExcelActive = ([result count] > 0) ? YES : NO;
if (!ExcelActive) {
// do something here
}
return ExcelActive;
}
- (BOOL) theWorkbookActive {
BOOL wbActive = FALSE;
NSAppleEventDescriptor *execResult;
if ([self ExcelAppActive]) {
NSString *WorkbookActiveScript =
@"tell application \"Microsoft Excel\" to return (name of every
window contains \"";
WorkbookActiveScript = [WorkbookActiveScript
stringByAppendingString:itsFileName];
WorkbookActiveScript = [WorkbookActiveScript
stringByAppendingString:@"\")"];
This would be a bit easier using +stringWithFormat: like this:
NSString *WorkbookActiveScript = [NSString
stringWithFormat:@"tell application \"Microsoft Excel\" to return
(name of every window contains \"%@\")", itsFileName];
/*
tell application "Microsoft Excel" to return (name of every window
contains "some title")
*/
NSLog(WorkbookActiveScript);
execResult = [self ExecAppleScript:WorkbookActiveScript];
if (execResult != nil) { // success
wbActive = [execResult booleanValue];
}
if (!wbActive) {
// do something here
}
}
else {
// [self ExcelAppActive] sets and displays Error
}
return wbActive;
}
John Love
HTH
Mike
--
Mike Fischer Softwareentwicklung, EDV-Beratung
Schulung, Vertrieb
Note: I read this list in digest mode!
Send me a private copy for faster responses.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden