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

VLC Media Player 2.2.0 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Sound Studio 4.7.8 - Robust audio record...
Sound Studio lets you easily record and professionally edit audio on your Mac. Easily rip vinyls and digitize cassette tapes, or record lectures and voice memos. Prepare for live shows with live... Read more
LibreOffice 4.4.1.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0.3 - Drag-and-drop Web de...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With its user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Cloud 3.3.0 - File sharing from your men...
Cloud is simple file sharing for the Mac. Drag a file from your Mac to the CloudApp icon in the menubar and we take care of the rest. A link to the file will automatically be copied to your clipboard... Read more
Cyberduck 4.6.5 - FTP and SFTP browser....
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Firefox 36.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and... Read more
Thunderbird 31.5.0 - Email client from M...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
VOX 2.4 - Music player that supports man...
VoxIt just sounds better! The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features & support for all audio formats you should ever need... Read more
A Better Finder Rename 9.46 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more

Get The Whole Story – Lone Wolf Complete...
Get The Whole Story – Lone Wolf Complete is Now Available and On Sale Posted by Jessica Fisher on February 27th, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Check Out the Trailer for the Upcoming F...
Check Out the Trailer for the Upcoming FINAL FANTASY: Record Keeper Posted by Jessica Fisher on February 26th, 2015 [ permalink ] DeNA and Square Enix have announced that | Read more »
Legacy Quest is an Upcoming Rouge-like T...
Legacy Quest is an Upcoming Rouge-like That’ll Kill the Whole Family Posted by Jessica Fisher on February 26th, 2015 [ permalink ] Nexon Co. | Read more »
Grudgeball: Enter the Chaosphere Review
Grudgeball: Enter the Chaosphere Review By Jordan Minor on February 26th, 2015 Our Rating: :: MUSCLE MENUniversal App - Designed for iPhone and iPad Regular Show gets an above average game.   | Read more »
Action RPG League of Angels – Fire Raide...
Gaia is being invaded by the Devil Prince and the demonic Devil Army at his disposal, and it’s up to you and your avatar to defeat him in League of Angels – Fire Raiders. Raise a mighty army from hundreds of recruitable angel heroes and take the... | Read more »
Burn Rubber on the Ice With a New Cars:...
Burn Rubber on the Ice With a New Cars: Fast as Lightning Update Posted by Jessica Fisher on February 26th, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
AdVenture Capitalist Review
AdVenture Capitalist Review By Jordan Minor on February 26th, 2015 Our Rating: :: DAS KAPITALUniversal App - Designed for iPhone and iPad An inadvertent Marxist manifesto.   | Read more »
Monster vs Sheep Review
Monster vs Sheep Review By Jennifer Allen on February 25th, 2015 Our Rating: :: SAMEY FUNUniversal App - Designed for iPhone and iPad What Monster vs Sheep lacks in variety it makes up for with stress relieving fun. At least, for a... | Read more »
Is Your Face Ready for the New Outwitter...
Is Your Face Ready for the New Outwitters 2.0 Trailer? Posted by Jessica Fisher on February 25th, 2015 [ permalink ] One Man Left Studios has announced that their turn-based strategy game, | Read more »
HowToFormat Review
HowToFormat Review By Jennifer Allen on February 25th, 2015 Our Rating: :: USEFUL TIPSiPhone App - Designed for the iPhone, compatible with the iPad Making a presentation and want to get it just right? HowToFormat teaches you how... | Read more »

Price Scanner via MacPrices.net

Save up to $50 on iPad Air 2s, NY tax only, f...
 B&H Photo has iPad Air 2s on sale for $50 off MSRP including free shipping plus NY sales tax only: - 16GB iPad Air 2 WiFi: $469.99 $30 off - 64GB iPad Air 2 WiFi: $549 $50 off - 128GB iPad Air 2... Read more
16GB iPad Air 2 on sale for $447, save $52
Walmart has the 16GB iPad Air 2 WiFi on sale for $446.99 on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale price for online orders only,... Read more
iMacs on sale for up to $205 off MSRP
B&H Photo has 21″ and 27″ iMacs on sale for up to $205 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $1029 $70 off - 21″ 2.7GHz iMac: $1199 $100 off - 21″ 2.9GHz... Read more
Apple Takes 89 Percent Share of Global Smartp...
According to the latest research from Strategy Analytics, global smartphone operating profit reached US$21 billion in Q4 2014. The Android operating system captured a record-low 11 percent global... Read more
New Travel Health App “My Travel Health” iOS...
Rochester, Minnesota based Travel Health and Wellness LLC has announced that its new iOS app help safeguard the user’s health when traveling abroad — “My Travel Health” is now available on the Apple... Read more
Sale! MacBook Airs for up to $115 off MSRP
B&H Photo has MacBook Airs on sale for up to $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $799 100 off MSRP - 11″ 256GB MacBook Air: $999 $100... Read more
15-inch 2.0GHz Retina MacBook Pro (refurbishe...
The Apple Store has Apple Certified Refurbished previous-generation 15″ 2.0GHz Retina MacBook Pros available for $1489 including free shipping plus Apple’s standard one-year warranty. Their price is... Read more
Wither The iPad mini? End Of The Road Imminen...
AppleDailyReport’s Dennis Sellers predicts that the iPad mini is going to be left to wither on the vine, as it were, and then just allowed to fade away — a casualty of the IPhone 6 Plus and other... Read more
Android and iOS Duopoly Owns 96.3% of Smartph...
IDC reports that Android and iOS inched closer to total domination of the worldwide smartphone market in both the fourth quarter (4Q14) and the calendar year 2014 (CY14). According to data from the... Read more
13-inch 2.4GHz Retina MacBook Pro available f...
MacMall has the 2013 13″ 2.4GHz/128GB Retina MacBook Pro available for $999.99 for a limited time. Shipping is free. Their price is $300 off original MSRP, and it’s the only sub-$1000 new Retina... Read more

Jobs Board

Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
*Apple* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.