Proper way to execute an AppleScript?

I need to dynamically generate an AppleScript… dynamically in that the “code” will remain constant, but the values used will change.

Right now I build the script as a string, and use SHELL and the OSASCRIPT command to execute it…

Is there a “better” way

AppleScriptMBS or NSAppleScriptMBS classes in our plugins maybe?

And there is a ExecuteAppleScript command build into xojo, I think.

do you mean something like this?
AppleScript

In your applescript, you would code the run handler parameters like this:

on run {Parameter1, Parameter2, etc…}

Save your script file, and add it to the Xojo project. Then in XOJO, you pass the parameters after the script name:

MyApplescript (Parameter1, Parameter2, etc...)

Can find such a command.

And I’m looking to execute a script from a string without using a Shell…

It might be possible that a huge portion would be creating at run time, not design time… so dragging a pre-made script into the IDE would not be an option.

I do this in my Evaluator classes, but I do it with the MBS plugins.

I’m looking at MacOSLib to see of there is something similar now…

Nothing obvious in MacOSLib, but there is this:

https://developer.apple.com/library/mac/technotes/tn2084/_index.html

Short of that, it looks like your method or a plugin.

The reference for NSAppleScript (something I should add to MacOSLib, I guess):

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSAppleScript_Class/Reference/Reference.html#//apple_ref/doc/uid/20000697-BAJIGBDB

not sure how to convert this to declares/Xojo but it looks good :slight_smile:

void        doAppleScript    (NSString* ASString)    
{
    NSAppleScript* script = [[NSAppleScript alloc] initWithSource:ASString];
    NSDictionary* errorInfo = [NSDictionary dictionary];
    NSAppleEventDescriptor* descriptor = [script executeAndReturnError:&errorInfo];
    [script release];
    if (descriptor == nil) { // there was a compile error
        NSString* error = [errorInfo objectForKey:NSAppleScriptErrorMessage];
        NSLog(@"doAppleScript error = %@", error); NSBeep();
    }else{ // script compiled and ran with no errors 
        NSLog(@"doAppleScript successful with script = %@", ASString);
    }
}

You need to declare each of the individual functions. The good news is that NSString and CFString are interchangeable, so you can use the native CFStringRef and skip those declarations.

How soon do you need this Dave? And are you open to using MacOSLib?

Not in a huge rush… and yeah I can deal with MacOsLIb I think :slight_smile:
Rather have just the specific snippet… but I will see what comes out…

Unless you have (or know of) specific XOJO (or MacOSlib) (or Declares) to read/write/update iCal database

If I put it in MacOSLib (a huge “if” right now since I have a lot of other things going on at the moment), I’d include an example window to illustrate its usage. That should give you the “snippet” you’re looking for.

I had a free moment…. (and I may need this too)

[code] soft declare function NSClassFromString lib “Cocoa” (classname as CFStringRef) as ptr
soft declare function initWithSource lib “Cocoa” selector “initWithSource:” (obj as ptr,source as CFStringRef) as ptr
soft declare function executeAndReturnError lib “Cocoa” selector “executeAndReturnError:” (obj as ptr,byref error as ptr) as ptr
soft declare function alloc lib “Cocoa” selector “alloc” (classRef as Ptr) as Ptr
soft declare function stringValue lib “Cocoa” selector “stringValue” (classRef as Ptr) as CFStringRef

dim nsscript As ptr=initWithSource(alloc(NSClassFromString(“NSAppleScript”)),TextArea1.Text)
dim err As ptr
dim descriptor As ptr=executeAndReturnError(nsscript,err)
if err<> nil then
MsgBox “An error occured”
else
MsgBox stringValue(descriptor)
end if[/code]

Doesn’t look at the error data or anything fancy, but should be a good start

Nice…

So “nsascript” is a string containing the content of the AppleScript code to execute
and
“descriptor” is any returned value(s) from the script?

No, the TextArea1.Text contains the AppleScript. There are no other placeholders in his code.

…better as a function

[code]Function ExecuteAppleScript(TheScript as String) As String
#if TargetMacOS
soft declare function NSClassFromString lib “Foundation” (classname as CFStringRef) as ptr
soft declare function initWithSource lib “Cocoa” selector “initWithSource:” (obj as ptr,source as CFStringRef) as ptr
soft declare function executeAndReturnError lib “Cocoa” selector “executeAndReturnError:” (obj as ptr,byref error as ptr) as ptr
soft declare function alloc lib “Cocoa” selector “alloc” (classRef as Ptr) as Ptr
soft declare function stringValue lib “Cocoa” selector “stringValue” (classRef as Ptr) as CFStringRef

dim nsscript As ptr=initWithSource(alloc(NSClassFromString("NSAppleScript")),TheScript)
dim err As ptr
dim descriptor As ptr=executeAndReturnError(nsscript,err)
if err<> nil then
  MsgBox "An error occured"
else
  Return stringValue(descriptor)
end if

#endif
End Function
[/code]

I’d throw an Exception rather than using a MsgBox. You are also responsible for releasing some of these objects, like the error.

Ok… I saw the TextArea piece…
Not sure how to return certain things however…

Tell application "iCal"
   set theCalendarNames to title of every calendar
   return theCalendarNames
end tell

runs, but doesn’t return anything useful (null string)

Code I have now gets this information by reading actual OSX files directly… which I do not wish to do… .
I want to interact with iCal as “cleanly” as possible

Try this:

Set the text item delimiters to “/” // Use whatever delimiter you wish here
Tell application “iCal”
set theCalendarNames to title of every calendar As String
return theCalendarNames
end tell