Launch Doc
Volume Number: 2
Issue Number: 2
Column Tag: Assembly Lab
Launch Doc Utility in MacAsm 
By Paul F. Snively, Columbus, IN, MacTutor Contributing Editor
Whew! This program, which started out being a simple little thing, got
complicated in a hurry!
Welcome to Launch Doc, the MacTutor document launching utility.
Huh?
A little bit of background is in order. I recently acquired a 512K upgrade for
what I had affectionately dubbed my "Meager Mac." Needless to say, one of the more
exciting things about owning a Fat Mac is having the ability to run Switcher. I had a
copy of Switcher 2.0 (ancient history, yes, I know) lying around which I immediately
started tinkering with.
It didn't take long to discover Switcher's ability to create "sets" which, when
double-clicked from the Finder, would launch all of my favorite applications. Now a
problem arose: how do you specify an application's document ("Write/Paint Set," for
example) as the startup application?
Answer: you don't, unfortunately. This frustrated me; it would have been really
nice to be able to launch my set automatically upon bootup.
Hang on when you double-click a document icon in Finder it knows what
application to launch. Why not do something similar, like write an application which
maintains a document name and, when executed (excuse me, launched), determines the
owner and launches it (passing it a Finder Info handle to the document).
Well, that's the story of Launch Doc in a nutshell. It's probably worth pointing
out that the version of Switcher that I now have (4.4) allows you to start up with
Switcher and your favorite set simply by calling the set "Switcher.StartUp." If you
have a set by that name and make Switcher the startup application, booting that disk
will get you into whatever applications you have in the set. Thanks, Andy.
This doesn't make Launch Doc useless, though. If nothing else, Launch Doc came
in handy during the last stages of its own development, since I used it to cause its own
source code to be launched whenever I booted the disk. Furthermore, I use Launch Doc
to launch another very long term document/ application: my saved game for Infocom's A
Mind Forever Voyaging!
Now for an overview:
There are two INCLUDE directives in the source. The first is a must, the second
is convenient, but only possible on a 512K or higher machine. Failing a 512K system,
list the file and find the EQUates for CurApName and AppParmHandle. They're used by
Launch Doc. Use the equates instead of the include.
The globals are straightforward and minimal: a launch parameter block, room
for a pointer, and room for a short (64 character, counting the length byte) string.
The source assembles to "Buffer.Bin" and resource compiles to "Launch Doc."
The type is APPL (naturally), the creator is LDOC, and the Finder flags are $2000 (the
bundle bit is set).
The resources follow. First is the signature. Any Mac application that has its
own icon must have a signature, the icon(s), FREF(s), and a BNDL.
The icon list follows. I cannot tell a lie: I design my icons last, and for testing
purposes use a solid black icon. After the code is done, I use ResEdit to create my real
icon. I then launch the application under TMON, use the Load Res user area routine to
load the ICN# for the application, and print a dump of the hex codes that make up the
icon and its mask. I then go back and edit the source to reflect the object code. It almost
takes longer to describe than to do, and as far as I'm concerned, it's quicker than using
icon editors and converters! [Note: Chris Yerga's nifty icon converter package in
assembly might change your mind. It produces source code listings from icon binary
files. See MacTutor, Jan. 1986.-Ed]
Next comes the FREF (file reference) resource. There's only one file to refer to
with Launch Doc: the application itself. Its local ICN# ID is 0.
Next is the bundle. This is necessary for the Finder to install the program on the
desktop.
The remaining resources are the elements of Launch Doc's user interface.
Ideally, the only one of these items that you will ever see is the dialog box, which is
used to edit the name of the document to launch. The alert boxes are error messages;
they let you know that something has gone wrong somewhere. Possible error conditions
include errors writing the document name to disk (most likely a disk full error), an
inability to read the file information for the document (the specified document
probably isn't on the default volume or the document name is null), an inability to
launch applications (why would you want to? I don't call it Launch Doc for nothin'),
and an inability to find the application that created the document (the document is on
the volume but the application isn't).
The main program is largely a collection of subroutine calls. Ordinarily this
would be considered good design, but it did cause some problems. My code could be
politely described as "workmanlike," and if I weren't already past deadline I'd take a
stab at cleaning it up. This is left as an exercise for the reader.
First all of the managers are initialized with the exception of the window
manager. I wanted to avoid a double-flicker effect from launching Launch Doc and then
launching another application in rapid succession. The result was several
_InitWindows throughout the code (anytime a dialog or alert is about to come up), but I
think it was worth it.
GetDocName is an interesting routine. Something that most Mac programmers
are aware of, but not many seem to use, is that an application can have a data fork as an
integral part of the application. This is great for programs that only need one data file.
Since I wanted to save a document name on a continuing basis, using Launch Doc's own
data fork seemed like a good idea. This idea is not original with me; the public domain
game Megaroids uses the same technique to save the high score. GetDocName opens the
data fork of the current application (by using the system global CurApName) and tries
to read the first 64 bytes of the data fork into the FileName global. If the read fails, the
routine CLR.B's FileName (effectively creating a zero-length string). In any event, the
local variable structure is dropped and the routine returns.
'EditMaybe' is the heart of the user interface to Launch Doc. EditMaybe
determines whether the mouse button is being held down. If it is not, EditMaybe closes
Launch Doc's data fork and returns, otherwise it tosses up a dialog box showing the
current document name and allowing the user to edit it and save it or exit to the Finder.
How? First the _GetNewDialog trap is used to bring up the dialog box.
_GetDItem is used to get the handle to item #4 (the editable text item). _SetIText is
used to set the dialog's text equal to the string in the FileName global. _SelIText is used
to select the whole item for editing. Finally, _ModalDialog is used to interact with the
user. Thanks to the fact that all other items are disabled, only clicking on the buttons
or pressing Return or Enter has any effect.
You may have noticed the flim-flamming around with the stack on some of the
dialog related toolbox traps. The reason for this is that the toolbox wants pointers to
the parameters, not the parameters themselves. Since I refuse to allocate global space
for something that is only going to be thrown away (as a great deal of the _GetDItem
info is), I just allocated space on the stack and then used the PEA x(SP) instructions to
push pointers to them. It necessitates some extra mental keeping track of the stack, but
it's worth it - the end result is that the results are on the stack, where they should be.
_SetIText simply sets a text item to the string passed to it. It is used in this
instance to make the editable text item in the dialog equal to the document name which
was read from the data fork.
_SelIText is used to select any portion (or all) of an editable text item. I used it
to select the entire name. This causes the dialog to behave in much the same manner as
the Standard File package or Disk Initialization package, both of which select the entire
name on editable items. The reason for this is that the user, if he or she is going to
change anything, is likely to change the whole thing.
_ModalDialog is then used to interact with the user. The editable text is disabled,
so it can be edited without returning to the caller every time an event occurs in that
field (we don't care abou individual events; we only care about the end result).
Pressing Return or Enter has the same effect as clicking on the OK button.
If the user selects OK, EditMaybe uses the _GetIText toolbox trap to read the
newly edited (maybe) filename into the FileName global. It then uses the _Write OS
trap to write the string back out to the data fork of Launch Doc. If there was a problem
with the write, an alert is displayed. EditMaybe _Closes the file, checks D4 to see what
it should do upon returning, and returns.
If the user selects Finder, EditMaybe closes the data fork, checks D4 and returns.
If Finder was hit or there was a _Write error, the Z flag will be set upon
returning from EditMaybe and Launch Doc will RTS its way to the Finder. Otherwise
GetDocInfo will be called.
GetDocInfo uses _GetFileInfo to determine two very pertinent pieces of
information about the document to launch: its type and creator.
If there was a problem getting the info, an alert box tells the story. If you try to
launch an application with Launch Doc (type = APPL), the same thing happens.
LoadFileInfo is interesting. There is a little known access method on the
Macintosh which uses a parameter called ioFDirIndex, which is neither more nor less
than the number of the file on the volume. It so happens that the _GetVolInfo OS trap
returns, among other things, the number of files on the volume. Armed with that
information and the ioFDirIndex means of using _GetFileInfo, LoadFileInfo can get the
info on every file on the volume without having to know a single filename. First, it
determines how many files are on the volume. It then allocates a pointer large enough
to hold all of the information for all of the files. A simple loop then reads the info into
the block.
FindAppl searches the block containing the file info for a file whose creator
matches the creator of the document and whose type is APPL. If it fails to find such a
file, an alert gives the user the message, otherwise _GetFileInfo is used (again), this
time with a pointer to a block for the name, which is what we really need (for
_Launch).
BuildFInfo customizes the Finder Info handle to represent the fact that we want to
open a document of whatever type is in D6. We only want to open one file, and it's on
the default volume. The file version number is zero (it always is, according to IM) and
the name is given.
Upon returning from BuildFInfo, Launch Doc points A0 to the _Launch parameter
block, which in turn points to the name of the application to launch. Launch Doc