TweetFollow Us on Twitter

June 96 - According to Script: Attaching and Embedding Scripts

According to Script: Attaching and Embedding Scripts

CAL SIMONE

One of the least-implemented powerful capabilities you can add to your application is attaching and embedding scripts. In this column I'll give you an idea of how to do this, and clear up some confusion along the way.

ATTACHING VS. EMBEDDING

The term attach has been used to refer to both attaching and embedding. Allow me to set the record straight by offering definitions of the two terms as they apply to scripting.
  • An attached script is a compiled script or script application that's associated with a menu item in an application; the script is executed when the user chooses that command. This type of script usually resides in a particular place, such as a Scripts folder. Script attachment can be implemented quickly and, at its most basic level, doesn't require your application to be scriptable.

  • An embedded script is a compiled script that's associated with an interface element belonging to an application or with a document. The script can be stored with the application's data, often in a special file known to the application, or embedded within the data for a document file.

ATTACHING SCRIPTS TO MENU ITEMS

Attached scripts are useful for two reasons. You, or your users (depending on what's appropriate for your application), can do the following:
  • Execute scripts to communicate with and control other scriptable applications without leaving your application. This is useful whether or not your application is scriptable.

  • Use scripts as an means of extending the functions or options available in your application. If your application itself is scriptable, script attachment leverages off the work you've already done.
By allowing users to keep a menu of their favorite scripts, you enable them to build a library of expanded functionality for your application. The Mac OS and Finder accomplish this with the Automated Tasks submenu in the Apple menu. You can do this with a Scripts menu that appears as the last (or next to last) of your application's menus.

Here are the steps for implementing this attachable behavior:

  • In the resource file included with your application, include a menu resource with the title "Scripts."

  • In the startup code for your application, locate the Scripts folder in your application's folder, creating it if it isn't there.

  • Walk the files in the Scripts folder, checking for compiled scripts (file type 'osas') and script applications (file type 'APPL', creator 'aplt' or 'dplt'). Add the names of these files to your Scripts menu.

  • When a user selects a script name from the Scripts menu, load the script resource ('scpt' 128) and execute the script, as shown in Listing 1.

Listing 1. Loading and executing a script from a file
FUNCTION RunAttachedScript(theAlias: AliasHandle): OSAError;
VAR
   fileSpec:             FSSpec;
   scriptRes:            Handle;
   scriptDesc:           AEDesc;
   scriptID, resultID:   OSAID;
   myErr, ignoredErr:    OSAError;
   savedRes, refNum:     Integer;
   specChanged:          Boolean;

BEGIN
   (* Get the file specification corresponding to the menu item chosen. *)
   myErr := ResolveAlias(NIL, theAlias, fileSpec, specChanged);
   IF myErr <> noErr THEN MyErrorProc(myErr);

   (* Open the resource fork and grab the script resource. *)
   savedRes := CurResFile;
   refNum := FSpOpenResFile(fileSpec, fsRdPerm);
   IF refNum = -1 THEN MyErrorProc(-1);
   UseResFile(refNum);
   scriptRes := Get1Resource(kOSAScriptResourceType, 128);
   IF ResError <> noErr THEN MyErrorProc(ResError);

   (* Prepare and run the script. *)
   myErr := AECreateDesc(typeOSAGenericStorage, scriptRes^, GetHandleSize(scriptRes),       scriptDesc);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := OSALoad(gGenericComponent, scriptDesc, kOSAModeNull, scriptID);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := OSAExecute(gGenericComponent, scriptID, kOSANullScript, kOSAModeNull, resultID);
   ignoredErr := OSADispose(gGenericComponent, scriptID);
   ignoredErr := AEDisposeDesc(scriptDesc);
   IF myErr <> noErr THEN MyErrorProc(myErr);

   (* Finish up. *)
   ReleaseResource(scriptRes);
   CloseResFile(refNum);
   UseResFile(savedRes);

   (* You might want to do something with the result. *)
   IF resultID <> kOSANullScript THEN MyDealWithResult(resultID);
   RunAttachedScript := myErr;
END;
Before executing a script, you must establish a connection to a scripting component. The easiest thing to do is to connect to the generic scripting component with OpenDefaultComponent. When you're done, disconnect from the component with CloseComponent. Depending on how you design your application, you can open this connection and keep it open while your program is running, or you can open and close the connection each time you load and execute a script. For more information on choosing and connecting scripting components, see Inside Macintosh: Interapplication Communication, Chapter 10.

EMBEDDED SCRIPTS IN APPLICATION DATA OR DOCUMENT FILES

Embedded scripts can be used in two ways:
  • Interface elements belonging to an application, such as tool palette icons, menu items, and buttons, can have scripts associated with them.

  • Scripts can be associated with individual documents. Unlike the above case, you can trigger the script with any method that's appropriate for your application.
Embedding scripts can be extremely powerful. For example, you can associate scripts with elements of a form to supply a field's editing rules, or with a button to perform calculations. Replace a script and you change the rules or the formula! Depending on your particular application, you can use this technique yourself or allow users to do their own replacement.

If you reserve this technique for your own use, you can revise your software simply by replacing scripts with corrected or enhanced versions. Or, if you allow your users to change the embedded scripts, your application becomes easily customizable: users can modify or augment your application's capabilities simply by substituting scripts. You could even ship your application with replacement scripts, which users can substitute for default scripts that you provide.

RETRIEVING EMBEDDED SCRIPTS

There are three methods of retrieving embedded scripts from files, depending on where they're stored. Regardless of which method you choose, it's important to remember that your program should never try to interpret the bytes of a compiled script. However, as long as you keep the bytes intact, you can do whatever you want with them and the script will remain intact.

Aliases to script files. This is the same technique as described above for attached scripts. This method is used primarily for maintaining a list of scripts. You'd use it, for instance, if you kept a collection of scripts in a folder on disk. I don't recommend this technique if the scripts are associated with actual interface elements, because the links that aliases provide to the script files can too easily be broken.

In the document's resource fork. Storing the scripts as resources is convenient because you can easily use your favorite resource editor to copy a script resource from a compiled script or script application and paste it into the special application file or the document. It also makes it easy to grab the scripts for loading and executing, using the method shown in Listing 1 (though in this situation I'd suggest using an ID number other than 128 for the script resource). The drawback is that your users can get their hands on the script with their favorite resource editor.

In the document's data fork. Maintaining the scripts within the data for a document is a more secure method, since it makes it harder for users to extract the scripts. It's also more difficult for you, though, because you may have to keep track of the location within the document's data, and then convert the script into the form required for execution. You'll want to store three pieces of information: the four-character ID 'scpt' (typeOSAGenericStorage), the length of the script data that follows, and the script data itself. The ID isn't essential, but it may come in handy, especially if there are other types of data present or if you load your document's data sequentially.

There are many ways to keep track of multiple types of data in a document file. If you have a lot of different types of data in the file, you can even develop a small database for the data, complete with a directory, so that you can gain quick access to particular types of data, including the script. A simpler way is to maintain the data in one long stream, embedding the script data within the stream. If you know the location of the script within the stream, you can just load and execute it when a user wants to run it. One developer I know reads all the data in the data fork (including scripts) sequentially when the file is opened, so that he doesn't need to keep track of the script's location within the file. Listing 2 shows an example of loading script data from the data fork of a document file.

Listing 2. Extracting script data from a document's data fork

FUNCTION RunEmbeddedScriptFromDataFork(theAlias: AliasHandle;
             scriptLoc: LongInt): OSAError;
VAR
   fileSpec:              FSSpec;
   scriptData:            Handle;
   scriptDesc:            AEDesc;
   dataType:              DescType;
   scriptID, resultID:    OSAID;
   myErr, ignoredErr:     OSAError;
   refNum:                Integer;
   scriptLen, readLen:    LongInt;
   specChanged:           Boolean;

BEGIN
   (* Open the file. *)
   myErr := ResolveAlias(NIL, theAlias, fileSpec, specChanged);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := FSpOpenDF(fileSpec, fsRdPerm, refNum);
   IF myErr <> noErr THEN MyErrorProc(myErr);

   (* Grab the data. *)
   IF MemError <> noErr THEN MyErrorProc(MemError);
   myErr := SetFPos(refNum, fsFromStart, scriptLoc);
   readLen := sizeof(dataType);
   IF myErr = noErr THEN myErr := FSRead(refNum, readLen, @dataType);
   (* dataType should be typeOSAGenericStorage. *)
   readLen := sizeof(scriptLen);
   IF myErr = noErr
       THEN myErr := FSRead(refNum, readLen, @scriptLen);
   IF myErr = noErr THEN scriptData := NewHandle(scriptLen);
   IF MemError <> noErr THEN MyErrorProc(MemError);
   myErr := FSRead(refNum, scriptLen, scriptData^);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := FSClose(refNum);

   (* Prepare and run the script. *)
   myErr := AECreateDesc(typeOSAGenericStorage, scriptData^,
      GetHandleSize(scriptData), scriptDesc);
   DisposeHandle(scriptData);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := OSALoad(gGenericComponent, scriptDesc, kOSAModeNull,
      scriptID);
   IF myErr <> noErr THEN MyErrorProc(myErr);
   myErr := OSAExecute(gGenericComponent, scriptID, kOSANullScript,
      kOSAModeNull, resultID);
   ignoredErr := OSADispose(gGenericComponent, scriptID);
   ignoredErr := AEDisposeDesc(scriptDesc);
   IF myErr <> noErr THEN MyErrorProc(myErr);

   (* You might want to do something with the result. *)
   IF resultID <> kOSANullScript
      THEN MyDealWithResult(resultID);
   RunEmbeddedScriptFromDataFork := myErr;
END;

GIVING IT AWAY

The information in this column is not offered as a complete solution, but is intended to get you moving with implementing attachability. There are many other issues surrounding attachability that are worth exploring, such as getting time during script execution, using attached scripts to allow users to tinker with some of the core functionality of your application, and providing a consistent way for your users to edit attached and embedded scripts. I plan to delve into these other issues in upcoming columns.

Making your application capable of attaching or embedding scripts puts new power into your users' hands, giving them unprecedented ability to develop custom solutions to their problems. It's not hard to do, and the benefits are enormous. Do it today.

CAL SIMONE (mainevent@his.com, AppleLink MAIN.EVENT) Few people know it, but before Cal was in the software business, he used to produce records (the musical kind) in Washington DC and New York. At a time when computers were used mostly to make robotic dance music, Cal was one of the first to painstakingly create "human" performances in pop records with about 60 MIDI synthesizers and, of course, a Macintosh. He now works toward a day when every application will be scriptable.*

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Capo 3.2 - Slow down and learn to play y...
Capo lets you slow down your favorite songs so you can hear the notes and learn how they are played. With Capo, you can quickly tab out your songs atop a highly-detailed OpenCL-powered spectrogram... Read more
OmniOutliner 4.2.3 - Organize your ideas...
OmniOutliner is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
pwSafe 4.0.1 - Secure password managemen...
pwSafe provides simple and secure password management across devices and computers. pwSafe uses iCloud to keep your password databases backed-up and synced between Macs and iOS devices. It is... Read more
WALTR 1.5.4 - Drag-and-drop any media fi...
WALTR is designed to make it easy to upload and convert any music or video file to an iPad or iPhone format for native playback. It supports a huge variety of media file types, including MP3, MP4,... Read more
Audio Hijack 3.1 - Record and enhance au...
Audio Hijack (was Audio Hijack Pro) drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio... Read more
PopChar 7.1 - Floating window shows avai...
We're also selling a 5-license family pack for only $25.99! PopChar helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to... Read more
BBEdit 11.1.1 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
Picasa 3.9.139 - Organize, edit, and sha...
Picasa and Picasa Web Albums allows you to organize, edit, and upload your photos to the Web from your computer in quick, simple steps. Arrange your photos into folders and albums and erase their... Read more
Mac DVDRipper Pro 5.0.5 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
NetShade 6.2 - Browse privately using an...
This promotion is for NetShade and 1 year of Proxy and VPN services NetShade is an anonymous proxy and VPN app+service for Mac. Unblock your Internet through NetShade's high-speed proxy and VPN... Read more

Block Fortress has a Big New Update for...
Block Fortress is a survival-style game that's as fun as it is blocky. It's also just gotten a rather sizeable update that adds a lot more cool stuff. [Read more] | Read more »
Simple and Surreal Star Base Sim rymdkap...
I really like rymdkapsel. Not just because I'm a sucker for games that are cleverly simple or highly stylisitc, but because it's fun and challenging. Actually it's extremely challenging, which is why I was excited to learn that it's getting a couple... | Read more »
Check out the anticipated Angel Stone in...
Fincon has finally revealed Angel Stone in action in the first ever official gameplay trailer for the anticipated hack and slasher. Angel Stone is set in a post-apocalyptic world in which humanity is in danger of being wiped out by the demonic... | Read more »
Moleskine Timepage is an All-New Calenda...
Moleskine Timepage is a bit of a departure for the notebook manufacturer (since it has little to do with notebooks), but it certainly carries their simple and elegant style quite well. [Read more] | Read more »
Jog on Over and Check Out the New Runtas...
Runtastic has put out a fair number of apps to help you sleep, track excercise, and train various parts of your body. Now it's time for your legs to have their own time in the spotlight with Runtastic Leg Trainer. [Read more] | Read more »
It's Lights Out in the Upcoming Pla...
Ember’s Journey is a stark puzzle platformer with a twist: the entire game is played in darkness. The only light you can see by is the one emanating from your own character. [Read more] | Read more »
MooVee - Your Movies Guru (Entertainmen...
MooVee - Your Movies Guru 1.0 Device: iOS iPhone Category: Entertainment Price: $1.99, Version: 1.0 (iTunes) Description: MooVee helps you effortlessly manage your movies, on your iPhone. | Read more »
Geometry Wars 3: Dimensions (Games)
Geometry Wars 3: Dimensions 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Enjoy the next chapter in the award-winning Geometry Wars franchise and enjoy stunning, console-quality... | Read more »
CHAOS RINGS Ⅲ (Games)
CHAOS RINGS Ⅲ 1.0.0 Device: iOS Universal Category: Games Price: $19.99, Version: 1.0.0 (iTunes) Description: The newest addition to the popular smartphone RPG series is finally here! ・CHAOS RINGS Overview | Read more »
The Popular Insight Series of Travel Gui...
Getting around in a country when you can't understand the primary language can be tough. Fortunately there are several options available to help wold travellers with the important stuff like giving directions to a cab driver or asking where the... | Read more »

Price Scanner via MacPrices.net

Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz... Read more
13-inch 2.4GHz Retina MacBook Pro (refurbishe...
The Apple Store has 2013 Apple Certified Refurbished 13″ 2.4GHz/128GB Retina MacBook Pros available for $879–$320 off original MSRP. Apple’s one-year warranty is standard, and shipping is free: - 13... Read more
Apple refurbished iPad Air 2s now available f...
The Apple Store is now offering Apple Certified Refurbished iPad Air 2s for up to $140 off the price of new models. Apple’s one-year warranty is included with each model, and shipping is free: -... Read more
MacBook Airs on sale for up to $80 off MSRP
Save up to $80 on the purchase of a new 2015 13″ or 11″ 1.6GHz MacBook Air at the following resellers. Shipping is free with each model: 11" 128GB MSRP $899 11" 256GB... Read more
Free Glide Live Video Messaging App Brings Ne...
Glide, an Israeli startup whose popular live video messenger has attracted more than 15 million users, has released significant updates to its free iOS app. Glide for iOS now gives users more control... Read more
Top Markets Saturation To Slow Global Smartph...
According to a new mobile phone forecast from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, smartphone shipments are expected to grow 11.3% in 2015 — down from 27... Read more
Apple’s Education discount saves up to $300 o...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.... Read more
Apple refurbished 2014 13-inch Retina MacBook...
The Apple Store has Apple Certified Refurbished 2014 13″ Retina MacBook Pros available for up to $400 off original MSRP, starting at $979. An Apple one-year warranty is included with each model, and... Read more
What Would the ideal Apple Productivity Platf...
For the past four years I’ve kept a foot in both the Mac and iPad camps respectively. my daily computing hours divided about 50/50 between the two devices with remarkable consistency. However, there’... Read more

Jobs Board

Senior Software Engineer - *Apple* SIM - Ap...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
*Apple* Pay Support Readiness Project Manage...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Program Manager, *Apple* Community Support...
**Job Summary** Apple Support Communities ( discussions. apple .com) helps customers get the most from their Apple products and services by providing access to Read more
Senior Data Scientist, *Apple* Retail - Onl...
**Job Summary** Apple Retail - Online sells Apple products to customers around the world. In addition to selling Apple products with unique services such as iPad Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.