Stack Translators
Volume Number: 10
Issue Number: 3
Column Tag: Hypercard
Stack Translators for Hypercard 2.2 
Transmogrification, another trick up your sleeve
By Kevin Calhoun, Apple Computer, Inc.
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
About the author
Kevin is a member of the HyperCard team at Apple. In his spare time, oh, wait a
minute, what spare time?
HyperCard developers have frequently asked, reasonably and rightly, for a
version of HyperCard which could build standalone applications, often calling it a
“HyperCard compiler”. They have also asked for a cross-platform version of
HyperCard, particularly one for Microsoft Windows. Recently, they have requested
versions that can build QuickTime movies, Newton applications, and ScriptX projects.
Perhaps soon I’ll be hearing about HyperCard for OpenDoc, Magic Cap, and Taligent.
HyperCard’s ease of use and breadth of functionality make it an attractive choice
among software development tools. Until recently, HyperCard’s ease of use has also
carried the limitation of only running on Macintosh. Ideally, software developers
could develop with HyperCard and avoid the limitations imposed by HyperCard’s
runtime requirements. Why should HyperCard be present in order to run stackware?
Furthermore, why should a Macintosh be required?
While HyperCard 2.2 doesn’t directly target other platforms and technologies, it
can get you closer. It still only builds stacks, and they require HyperCard to run.
However, it offers an open interface for add-on components, called “stack
translators,” which can translate stacks into other forms. Given the appropriate stack
translators, you can use HyperCard 2.2 as a development tool for runtime
environments other than its own. In addition, HyperCard 2.2 ships with a stack
translator that builds standalone Macintosh applications, called StackToApp.
You can create your own stack translators to turn HyperCard stackware into
running applications for any of the platforms and runtime environments I’ve
mentioned above. You can also use them to extract data from HyperCard stacks and
store them in alternate forms for use by other applications or platforms. For
example, you could put styled text from text fields into word processing documents.
You might extract AppleScript scripts from stacks and save them as script files on the
desktop. Anything that a stack might contain - data, links between data, interface
objects, configurations of interface objects, scripted functionality, etc. - can be
extracted by stack translators and munged and transformed into just about any form
you can imagine. As for me, I’d like to see a stack translator that takes my various
stacks and merges data within them into the data stored on my Newton.
The User Experience
HyperCard’s stack translators are Component Manager components. HyperCard
2.2 finds translators any of three ways. First, the System registers all components
(files of type 'thng' in the System Folder or the Extensions folder) during startup.
Second, HyperCard registers components it finds in files of type 'thng' and type 'STAK'.
These can be in the HyperCard folder, or a sub-folder called “Stack Translators”.
Third, XCMDs can also register and unregister a component, so you can choose when
it’s available.
The names of all registered stack translators appear in a popup menu in the
standard file dialog HyperCard displays when the user chooses “Save a copy...” from
the File menu.
When the user chooses a stack translator from the popup menu and clicks the
“Save” button in that dialog, HyperCard calls the appropriate stack translator to
translate the current stack. HyperCard passes the component the data and resource
forks reference numbers, as well as an FSSpec for the destination file.
To write a stack translator, there’s not much you need to know about the
Component Manager. It helps to have some experience in writing standalone code
resources, and you can read much more about components in Inside Macintosh
QuickTime Components.
Components are standalone code resources with a single entry point, and have the
calling interface defined by the Component Manager, as follows:
FUNCTION ComponentEntrypoint(VAR params:ComponentParameters;
storage: Handle): ComponentResult;
Every component has this entry point, and uses the parameters to dispatch to the
right subroutine. The ComponentParameters record contains everything you need to