Re: Objective-C and AppleScript

2008-09-01 Thread Mike Fischer


Am 01.09.2008 um 22:49 schrieb John Love <[EMAIL PROTECTED]>:


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 \"";
WorkbookActive

Re: Objective-C and AppleScript

2008-09-01 Thread has

John Love wrote:

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


If you use objc-appscript (I won't suggest the sdef/sdp/Scripting  
Bridge toolchain as an alternative as I know it has problems with  
Excel), you can check if Excel is running by calling the MEApplication  
object's -isRunning method:


// To create glue:  osaglue  -o MEGlue  -p ME  Microsoft\ Excel

	MEApplication *microsoftExcel = [MEApplication  
applicationWithBundleID: @"com.microsoft.excel"];

if ([microsoftExcel isRunning]) {
// do stuff here...
}

-- 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.


Code generation is fundamentally evil; if you need to pass values to a  
script, pack them into an NSAppleEventDescriptor and pass them to a  
handler in a compiled script via -[NSAppleScript  
executeAppleEvent:error:].


That said, appscript should suffice for general Apple event IPC, so  
the only time you should need to mess about with NSAppleScript is if  
you need to execute user-supplied scripts (appscript is pretty handy  
for that too, btw).




2) tell application "Microsoft Excel" to return (name of every  
window contains "some title")



I would suggest doing:

	tell application "Microsoft Excel" to return (exists window "some  
title")


as it's a bit clearer in meaning. The objc-appscript equivalent would  
be:


MEReference *ref = [[microsoftExcel windows] byName: @"some title"];
id result = [[ref exists] send];
BOOL windowExists = [result boolValue];

The ASTranslate tool on the appscript website is very handy if you  
need help translating application commands from AppleScript to ObjC  
syntax; there's also ASDictionary for exporting application  
dictionaries in appscript format.


HTH

has
--
Control AppleScriptable applications from Python, Ruby and ObjC:
http://appscript.sourceforge.net

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Objective-C and AppleScript

2008-09-01 Thread John Love
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


=

-- 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.


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];
execResult = [scriptObject executeAndReturnError:&errorInfo];

return execResult;   // success = (execResult != nil)

}


- (BOOL) ExcelAppActive {

BOOL ExcelActive = FALSE;
NSAppleEventDescriptor *execResult;

NSArray *ExcelActiveScriptArray = [NSArray arrayWithObjects:
@"tell application \"System Events\"",
	@"return (name of every application process contains  
\"Microsoft Excel\")",

@"end tell",
nil];
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 (!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:@"\")"];

 /*
		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


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]