Xcode Object C App -> Execute Applescript

Hi there,

i have a pure ObjectC app written with Xcode.
No i’d like to execute an applescript in the sourceBundle with parameters.

I have this solution and it works for
script “testscript.scpt”
handler “test_message”
parameter message

 NSString* path = [[NSBundle mainBundle] pathForResource:@"testscript" ofType:@"scpt"];
    NSURL* url = [NSURL fileURLWithPath:path];
    NSAppleScript* theScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:nil];
    NSDictionary* theErrorDictionary = nil;
    
    // build Apple event to invoke user-defined handler in script
    NSAppleEventDescriptor* event = [NSAppleEventDescriptor appleEventWithEventClass: kASAppleScriptSuite
                                                     eventID: kASSubroutineEvent
                                            targetDescriptor: NSAppleEventDescriptor.nullDescriptor
                                                    returnID: kAutoGenerateReturnID
                                               transactionID: kAnyTransactionID];
    
    
    // Add positional parameters
    NSAppleEventDescriptor* params = [NSAppleEventDescriptor listDescriptor];
    [params insertDescriptor: [NSAppleEventDescriptor descriptorWithString:@"I am a message"] atIndex: 1];
    
    // Add Subroutine
    [event setDescriptor: [NSAppleEventDescriptor descriptorWithString: @"test_message"]
              forKeyword: keyASSubroutineName];
    [event setDescriptor: params
              forKeyword: keyDirectObject];
    
    NSAppleEventDescriptor* theResult = [theScript executeAppleEvent:event error:&theErrorDictionary];
    NSLog( @"Got result: %@", theResult  );

This is the applescript

on test_message(message)
	display dialog message
end test_message

No i’d like to pass a dictionary (ASrecord) to applescript, but NSAppleEventdescriptors do not support dictionaries or arrays. Any ideas on how to call an applescript handler with a dictionary parameter?

Hi,

they do support dictionaries (record) and arrays (list), you are using one ([NSAppleEventDescriptor listDescriptor])

Consider to write a bridge to AppleScriptObjC, the framework provides to run scripts without the event descriptor dance.

The bridge solution sounds good.

Any good starting point for that? Never done before.

Please search on MacScripter for loadAppleScriptObjectiveCScripts.

There are a few related topics.

Thank you!

I now tried a lot of stuff, but basically this line would not work - throws exception

    [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];

Full code from main file

#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>

int main(int argc, const char * argv[]) {
    
    [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
    
    return NSApplicationMain(argc, argv);
}

Exception:

[NSBundle loadAppleScriptObjectiveCScripts]: unrecognized selector sent to instance 0x6000000818b0
2016-11-06 00:16:56.850566 MyApp[2717:77340] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSBundle loadAppleScriptObjectiveCScripts]: unrecognized selector sent to instance 0x6000000818b0'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fffa92147bb __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x00007fffbd981a2a objc_exception_throw + 48
	2   CoreFoundation                      0x00007fffa9294d84 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
	3   CoreFoundation                      0x00007fffa9187fc3 ___forwarding___ + 1059
	4   CoreFoundation                      0x00007fffa9187b18 _CF_forwarding_prep_0 + 120
	5   MyApp                         0x000000010000efea main + 74
	6   libdyld.dylib                       0x00007fffbe25d255 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Using Xcode 8, OSX 10.12

OK solved that one. Forgot the binary/framework include.

Thank you for pointing it out!

Add-On:

While the above mentioned way works great for text script files (*.applescript), is there also a possibility to send handler calls (with parameters) to precompiled *.scpt files and return a result?

They’re compiled to .scpt files as part of the build process – starting out as .applescript is irrelevant.

When -loadAppleScriptObjectiveCScripts is called, it attempts to load all the .scpt files in a bundle. But you obviously need a script name and parent defined to be able to use them.

Great! Thank you!