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

 
AAPL
$486.14
Apple Inc.
+18.78
MSFT
$32.32
Microsoft Corpora
-0.55
GOOG
$883.44
Google Inc.
-2.07

MacTech Search:
Community Search:

Software Updates via MacUpdate

Dragon Dictate 3.0.3 - Premium voice rec...
With Dragon Dictate speech-recognition software, you can use your voice to create and edit text or interact with your favorite Mac applications. Far more than just speech-to-text, Dragon Dictate... Read more
TrailRunner 3.7.746 - Route planning for...
Note: While the software is classified as freeware, it is actually donationware. Please consider making a donation to help stimulate development. TrailRunner is the perfect companion for runners,... Read more
VueScan 9.2.23 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Acorn 4.1 - Bitmap image editor. (Demo)
Acorn is a new image editor built with one goal in mind - simplicity. Fast, easy, and fluid, Acorn provides the options you'll need without any overhead. Acorn feels right, and won't drain your bank... Read more
Mellel 3.2.3 - Powerful word processor w...
Mellel is the leading word processor for OS X, and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
Iridient Developer 2.2 - Powerful image...
Iridient Developer (was RAW Developer) is a powerful image conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
Delicious Library 3.1.2 - Import, browse...
Delicious Library allows you to import, browse, and share all your books, movies, music, and video games with Delicious Library. Run your very own library from your home or office using our... Read more
Epson Printer Drivers for OS X 2.15 - Fo...
Epson Printer Drivers includes the latest printing and scanning software for OS X 10.6, 10.7, and 10.8. Click here for a list of supported Epson printers and scanners.OS X 10.6 or laterDownload Now Read more
Freeway Pro 6.1.0 - Drag-and-drop Web de...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Transmission 2.82 - Popular BitTorrent c...
Transmission is a fast, easy and free multi-platform BitTorrent client. Transmission sets initial preferences so things "Just Work", while advanced features like watch directories, bad peer blocking... Read more

Reiner Knizia’s Kaleidoscope Review
Reiner Knizia’s Kaleidoscope Review By Campbell Bird on August 13th, 2013 Our Rating: :: BEAUTIFULLY ELEMENTALUniversal App - Designed for iPhone and iPad This colorful, nature-themed puzzle game is beautiful, calming, and so... | Read more »
FileThis Fetch Tracks Down All Your Fina...
FileThis Fetch Tracks Down All Your Financial Records and Securely Sends Them To A Single Location Posted by Andrew Stevens on August 13th, 2013 [ | Read more »
Butterfly Sky Review
Butterfly Sky Review By Lee Hamlet on August 13th, 2013 Our Rating: :: BUTT-BOUNCING FUNUniversal App - Designed for iPhone and iPad Butterfly Sky combines the gameplay of Doodle Jump and Tiny Wings into a fun and quirky little... | Read more »
The Portable Podcast, Episode 197
We’ll get our hooks into you! On This Episode: Carter and Mike Meade of BeaverTap Games talk about the speedrun sequel Mikey Hooks, and the work that went into making the hooking mechanic feel just right. Carter and two of the members of Ironhide... | Read more »
Sony To Bring Two Lens Camera Attachment...
Sony To Bring Two Lens Camera Attachments To iOS Devices Posted by Andrew Stevens on August 13th, 2013 [ permalink ] There are two lens camera attachments making their way to iOS as Sony plans to release the DSC-QX10 and the | Read more »
ScribbleMix Review
ScribbleMix Review By Jennifer Allen on August 13th, 2013 Our Rating: :: DEPENDABLE SOCIAL DRAWINGUniversal App - Designed for iPhone and iPad Requiring players to draw entire phrases is a smart move for this Draw Something style... | Read more »
Guitar! by Smule Jams Out A Left-Handed...
Guitar! by Smule Jams Out A Left-Handed Mode, Unlocks All Guitars Posted by Andrew Stevens on August 13th, 2013 [ permalink ] | Read more »
KungFu Jumpu Review
KungFu Jumpu Review By Lee Hamlet on August 13th, 2013 Our Rating: :: FLYING KICKSUniversal App - Designed for iPhone and iPad Kungfu Jumpu is an innovative fighting game that uses slingshot mechanics rather than awkward on-screen... | Read more »
The D.E.C Provides Readers With An Inter...
The D.E.C Provides Readers With An Interactive Comic Book Platform Posted by Andrew Stevens on August 13th, 2013 [ permalink ] | Read more »
Choose ‘Toons: Choose Your Own Adventure...
As a huge fan of interactive fiction thanks to a childhood full of Fighting Fantasy and Choose Your Own Adventure books, it’s been a pretty exciting time on the App Store of late. Besides Tin Man Games’s steady conquering of all things Fighting... | Read more »

Price Scanner via MacPrices.net

Can Surface be Saved? – Another Microsoft Bra...
WinSuperSite’s Paul Thurrott predicts that industry watchers and technology enthusiasts will be debating Microsoft’s decision to enter the PC market for years to come, but in the wake of a disastrous... Read more
Somewhat Watered-Down NeoOffice 2013 Now Avai...
NeoOffice 2013 is the version of NeoOffice in Apple’s Mac App Store. Except for the changes listed below, NeoOffice 2013 has the same features as NeoOffice 3.3 Patch 8. What changes will NeoOffice... Read more
Delayed Fingerprint Sensor Production To Bott...
It may be hard to get a iPhone 5S this fall. Digitimes’ Josephine Lien and Steve Shen report that production of Apple’s next iPhone, commonly referred to as the iPhone 5S and scheduled to be unveiled... Read more
Grovo Launches Freemium iOS App to Accelerate...
Grovo.com has launched its iOS app in the Apple Store for all iOS devices. Grovo’s new app, which complements its web-based training platform, is the most convenient way to get immediate answers to... Read more
iGO Chargers Apple-Certified And Backed With...
In light of recent reports that counterfeit or third party chargers have compromised the integrity of mobile devices and even caused physical harm resulting in death, iGO assures consumers that its... Read more
Apple refurbished iPads and iPad minis availa...
 Apple has Certified Refurbished iPad 4s and iPad minis available for up to $140 off the cost of new iPads. Apple’s one-year warranty is included with each model, and shipping is free: - 64GB Wi-Fi... Read more
Snag an 11-inch MacBook Air for as low as $74...
 The Apple Store has Apple Certified Refurbished 2012 11″ MacBook Airs available starting at $749. An Apple one-year warranty is included with each model, and shipping is free: - 11″ 1.7GHz/64GB... Read more
15″ 2.3GHz MacBook Pro (refurbished) availabl...
 The Apple Store has Apple Certified Refurbished 15″ 2.3GHz MacBook Pros available for $1449 or $350 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. Read more
15″ 2.7GHz Retina MacBook Pro available with...
 Adorama has the 15″ 2.7GHz Retina MacBook Pro in stock for $2799 including a free 3-year AppleCare Protection Plan ($349 value), free copy of Parallels Desktop ($80 value), free shipping, plus NY/NJ... Read more
13″ 2.5GHz MacBook Pro on sale for $150 off M...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $1049.95 including free shipping. Their price is $150 off MSRP plus NY sales tax only. B&H will include free copies of Parallels Desktop... Read more

Jobs Board

Sales Representative - *Apple* Honda - Appl...
APPLE HONDA AUTOMOTIVE CAREER FAIR! NOW HIRING AUTO SALES REPS, AUTO SERVICE BDC REPS & AUTOMOTIVE BILLER! NO EXPERIENCE NEEDED! Apple Honda is offering YOU a Read more
*Apple* Developer Support Advisor - Portugue...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more than Read more
RBB - *Apple* OS X Platform Engineer - Barc...
RBB - Apple OS X Platform Engineer Ref 63198 Country USA…protected by law. Main Function | The engineering of Apple OS X based solutions, in line with customer and Read more
RBB - Core Software Engineer - Mac Platform (...
RBB - Core Software Engineer - Mac Platform ( Apple OS X) Ref 63199 Country USA City Dallas Business Area Global Technology Contract Type Permanent Estimated publish end Read more
*Apple* Desktop Analyst - Infinity Consultin...
Job Title: Apple Desktop Analyst Location: Yonkers, NY Job Type: Contract to hire Ref No: 13-02843 Date: 2013-07-30 Find other jobs in Yonkers Desktop Analyst The Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.