Tuesday, September 26, 2017

#1 2016-07-30 06:33:29 am

Jonathan Engelhardt
Member
Registered: 2010-06-11
Posts: 57

Load Applescript from Object-C for accessing external software

hi there,

im trying to load an applescript from within my Cocoa-Applescript application.
It basically works, i just can't pass the errors dictionary:

From Apple developer:

Applescript:

[[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];

My code:

Applescript:

set errors to current application's NSDictionary's dictionary()
set scriptPath to makeNS_string(((current application's NSBundle's mainBundle())'s pathForResource:"HelpersFinder" ofType:"scpt")) -- Helper returns NSstring
set scriptUrl to current application's NSURL's fileURLWithPath_(scriptPath)
set appleScript to ((current application's NSAppleScript's alloc())'s initWithContentsOfURL:scriptUrl |error|:errors)

It throws an error:

*** -[NSAppleScript initWithContentsOfURL:error:]: value passed to argument of type 
^@ must be either `missing value' or `reference'; assuming `missing value'.

I can get it to work by setting error to missing value, but i want possible errors to be added to the errors dictionary. What would be the right syntax?

Last edited by Jonathan Engelhardt (2016-07-30 06:35:24 am)

Offline

 

#2 2016-07-30 11:24:08 am

Jonathan Engelhardt
Member
Registered: 2010-06-11
Posts: 57

Re: Load Applescript from Object-C for accessing external software

ok, i switched to Object-C for this task.

i got it mostly working, but still i have something i am struggling with:
The function loading and executing the AppleScript receives a list of Arguments like {"123","456",...}. With the code below i got everything work fine.

Applescript:

if ([scriptArgumentArray count])
{
NSAppleEventDescriptor *arguments = [[NSAppleEventDescriptor alloc] initListDescriptor];
NSString *object;

for (object in scriptArgumentArray) {
[arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:object]
atIndex:([arguments numberOfItems] + 1)]; //This +1 seems wrong... but it's not
}

[containerEvent setParamDescriptor:arguments forKeyword:keyDirectObject];
}
}

But now i need to pass more complex AS records ore NSDictionaries like {a:"123",b:{c:1, d:{"456"}} instead of AS lists. I basically need a recordDescriptor (or something better?) instead of a List descriptor. But i am really struggling on how to correct the code

The AS function calls are simple though like "myfunction(recordhere)".

To get an idea an what i need to SEND to the applescript, i modified the return of the applescript to see what it looks like in object C

End of the applescript reads:

Applescript:

return {a:{b:"123", c:"234"}, d:""}

Obj-C receives it like this

Applescript:

Result(<NSAppleEventDescriptor: { 'usrf':[ 'utxt'("a"), { 'usrf':[ 'utxt'("b"), 'utxt'("123"), 'utxt'("c"), 'utxt'("234") ] }, 'utxt'("d"), 'utxt'("") ] }>)

What i need is the other way arround. How to come from the AS record to the NSAppleEventDescriptor?

Last edited by Jonathan Engelhardt (2016-07-30 11:42:28 am)

Offline

 

#3 2016-07-30 09:20:03 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5136

Re: Load Applescript from Object-C for accessing external software

Applescript:

set appleScript to ((current application's NSAppleScript's alloc())'s initWithContentsOfURL:scriptUrl |error|:errors)


The correct syntax if you don't care about the error is:

Applescript:

set appleScript to ((current application's NSAppleScript's alloc())'s initWithContentsOfURL:scriptUrl |error|:(missing value))

otherwise:

Applescript:

set {appleScript, theError} to ((current application's NSAppleScript's alloc())'s initWithContentsOfURL:scriptUrl |error|:reference)

But you don't really want to use NSAppleScript, either in AS or Objective-C. Use load script instead.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

#4 2016-07-31 04:14:49 am

Jonathan Engelhardt
Member
Registered: 2010-06-11
Posts: 57

Re: Load Applescript from Object-C for accessing external software

I'll try that! What's NSAppleScript for then?

Offline

 

#5 2016-07-31 04:44:01 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5136

Re: Load Applescript from Object-C for accessing external software

Jonathan Engelhardt wrote:

What's NSAppleScript for then?


For non-Cocoa-AppleScript apps.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

#6 2016-07-31 12:39:45 pm

Jonathan Engelhardt
Member
Registered: 2010-06-11
Posts: 57

Re: Load Applescript from Object-C for accessing external software

Thank you for the advise! Works perfect!

I want to advance the stuff a little bit:
I created a class shAppleScript which shall handle init and function calls and which a can connect in IB.

The idea is to pass handler name and paramters to shAppleScript object to make it call the appropriate handlers in the loaded script.
With basic applescript this is not possible (as far as i know). But is there a way (maybe using Object-C stuff) to achieve this?

That way i would have instances to connect to. Would ease a lot of stuff.

Applescript:

script shApplescript
property parent : class "NSObject"

-- Properties
property appleScript: missing value

-- Functions
on initScript_(scriptName)
set scriptPath to ((current application's NSBundle's mainBundle()'s pathForResource:scriptName ofType:"scpt") as text)
set appleScript to (load script (scriptpath as posix file))
end

on call_handler_parameters(handlerName,parameters)
tell appleScript to handlerName(parameters)
end

So basically i just would call

Applescript:



-- IB Outlet
property myScript: missing value -- Instance of shAppleScript

myScript's initScript_("myScript")
myScript's call_handler_parameters("DoSomethingWith","Parameters")

Last edited by Jonathan Engelhardt (2016-07-31 12:46:04 pm)

Offline

 

#7 2016-07-31 06:47:11 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5136

Re: Load Applescript from Object-C for accessing external software

You can treat AppleScript classes like other classes -- make a property and connect it to an instance in IB, or use alloc()'s init(). The main difference is that handlers become both class and instance methods.

The other issue you have to keep in mind is that calling methods between classes deal in Cocoa objects, so you need to coerce received parameters and results back to their AppleScript classes (if that's what you want).


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

#8 2016-08-01 03:17:50 am

Jonathan Engelhardt
Member
Registered: 2010-06-11
Posts: 57

Re: Load Applescript from Object-C for accessing external software

EDIT: solved... see last line

I solved it that way:

I break it down to what matters - i have two classes AppDelegate and shLib and a script in the resources folder called HelpersFinder.scpt.

AppDelegate:

Applescript:

-- IB Outlets
property lib: missing value -- connected to shLib

on applicationDidFinishLaunching_(aNotification)
-- Register Scripts
lib's registerScripts()
lib's HelpersFinder's showMessage_("Hallo2") -- DOESNT WORK!
end

shLib:

Applescript:


property test: "TEST"

-- Register Helper Scripts
on registerScripts()
log "lib: registerScripts()"
set HelpersFinder to initScript_("HelpersFinder")
HelpersFinder's showMessage:"Hallo" -- WORKS! -> "Hallo -> TEST"
end

-- Init Script
on initScript_(scriptName)
log "lib: initScript_("&scriptName&")"
set scriptPath to ((current application's NSBundle's mainBundle())'s pathForResource:scriptName ofType:"scpt") as text
set myScript to (load script (scriptPath as posix file))
set scriptInstance to myScript's newInstance(me)
return scriptInstance
end

Content of HelpersFinder.scpt

Applescript:

on newInstance(_parent)
   script HelpersFinder
       
       property parent : _parent
       on showMessage:userMessage
           tell application "Finder"
               display dialog userMessage & "-> " & my parent's test
           end tell
           return {a:1, b:2}
       end showMessage:
   end script
end newInstance

While in shLib the function call

Applescript:


HelpersFinder's showMessage:"Hallo"

works. But back in AppDelegate i can't call

Applescript:

lib's HelpersFinder's showMessage_("Hallo2")

The error reads

*** -[BAGenericObject showMessage:]: Can’t make «class ocid» id «data optr000000006548616C6C6F3200» 
into type list, record or text. (error -1700)

Any ideas what i am doing wrong?

EDIT: it was coercing...

Last edited by Jonathan Engelhardt (2016-08-01 04:17:03 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)