August 92 - MACINTOSH Q & A
MACINTOSH Q & A
MACINTOSH DEVELOPER TECHNICAL SUPPORT
Q Is it my imagination, or does GetPictInfo return a bit depth of 1 on QuickTime compressed PICT files?
A Yep! This is what's happening: The Picture Utilities Package doesn't know of the QuickTime Compressed Pixmap opcode (0x8200), so it just skips over the opcode's
data; then it finds the PacksBitRect opcode containing the black-and-white
pseudo-alert that you get when you draw the picture on a machine that doesn't have
QuickTime installed, and GetPictInfo reports back this alert.
Trivia: When QuickTime is installed, it displays the compressed image and then
ignores the following PacksBitRect since QuickTime knows it's only the
black-and-white alert.
Q Is it true that if I double-click a document belonging to my application, the application will be launched and will receive an 'odoc' Apple event, but will not receive
an 'oapp' event--that is, it will receive either 'odoc' or 'oapp' but not both?
A Yes, except actually it will receive one of 'oapp', 'odoc', or 'pdoc'. The 'pdoc' will be followed (as the next event) by a 'quit' if the 'pdoc' was the event sent as the
application was launched.
This is the normal sequence of events, and should be adhered to by everyone who
launches applications. However, it isn't enforced by the system or the Finder. It's
possible for any application to launch your application with any event, since it can
stuff anything in the launchAppParameters field of LaunchApplication, as long as it's a
valid high-level (not even Apple) event. Launching another application this way would
be bad programming, and would break most applications, but you should be aware that
someone who doesn't understand event handling may do this to you.
Note that if another application launches your application using LaunchApplication and
doesn't specify any high-level event in the launch parameter block, the Finder will
automatically supply the 'oapp' event. So, in general, if Apple events and launching
have been coded correctly, you'll always receive an 'oapp', 'odoc', or 'pdoc'.
Q I'm using the Picture Utilities Package to extract the color table from a picture. After getting the color table, I use NewPalette to construct a palette from the color
table (usage = tolerant, tolerance = 0). After I do this, the RGB values in the palette
don't always exactly match the RGB values in the source color table, causing my
program to fail. If I use NewPalette without a source color table, and then use
CTab2Palette to copy the colors over (again with usage = tolerant, tolerance = 0), the
colors match exactly.
A It turns out that NewPalette doesn't use CTab2Palette, but copies the RGB fields in a strange way that's causing the problems you're seeing. NewPalette copies the high byte
in each color table RGB entry into both the high byte and the low byte of the
corresponding palette entry. Thus, if the color table entry for red was $F000, it
becomes $F0F0. This of course makes no difference to QuickDraw since the low byte
isn't displayed, but if your program expects the low byte to match, that's where your
problem exists. CTab2Palette is different, in that it doesn't copy the high byte into the
low byte unless the pmAnimated bit is set.
The best solution for your code isn't to compare the entire RGB value when comparing
colors, but rather to compare the high byte of each RGB component separately. If this
isn't possible, the next best solution is for you to use the workaround that you've
already discovered with CTab2Palette. It's unlikely that the Palette Manager is going to
change in the future for something like this. In fact, we would almost call it a "feature
since other developers may even depend on it.
Q My application wants to open other applications and play with the resources therein, like ResEdit, but when it calls OpenResFile on an application, the program gets lost in
GetNamedResource. Is there something I'm missing?
A Your problem stems from the fact that some resources in the application file you're opening with OpenResFile are marked to be preloaded, and so are loaded into memory
when the resource fork is opened.
Since most applications have CODE resources marked to be preloaded, this turns into a
much bigger problem, because the Segment Loader will treat these preloaded CODE
resources as your code resources if you make a between-segment call that triggers a
call to LoadSeg while the opened resource file is first in the resource chain. If this
happens, you'll begin executing code out of the other application, which will cause
your Macintosh to crash and burn.
The solution to this problem is to bracket OpenResFile calls with SetResLoad(FALSE)
and SetResLoad(TRUE), and to avoid making between-segment calls when you've got
another resource file open that contains CODE resources. This will not only prevent
your application's memory from being used by preloaded resources that you don't
want, but will also prevent the Segment Loader from jumping into the other
application's code. If you need to get CODE resources out of the opened resource file,
you can still prevent the Segment Loader problem by calling UseResFile on your
application's resource reference number to put your application at the top of the
resource chain.
Q How can our application search for files by label or color, getting the actual string for the label/color field, so that users can select from a menu that looks like what
they'd see in the Finder or ResEdit?
A In the icon utilities there's a call that will get you the RGB color and string for the Finder's labels. Information from the May 1992 revision of Macintosh Technical Note
"Drawing Icons the System 7 Way " (formerly #306) is shown below. It includes the
glue code for the call in MPW Pascal and C formats.
FUNCTION GetLabel (labelNumber: INTEGER; VAR labelColor: RGBColor;
VAR labelString: Str255): OSErr;
INLINE $303C, $050B, $ABC9;
The label number is in the range of 0 to 7, and is available in bits 1-3 of the file's
Finder flags (Inside Macintosh Volume VI, page 9-36). The call returns the actual
color and string used in the Label menu of the Finder and the label's control panel. This
information is provided in case you want to include the label text or color when
displaying a file's icon in your application.
Q I'm making an asynchronous low-level File Manager call from inside a completion routine (for example, error := PBxxx(@PB, TRUE);). Occasionally on some
machines, the call immediately returns an error in the function result even though
everything appears to work correctly. Do I need to worry about the result when I make
the call?
A It sounds as if you're making the mistake of testing the function result of an asynchronous File Manager call (the value of register D0 is returned in the function
result). There's no useful information in the function result of an asynchronous call
made to the File Manager; the call might not even have been looked at by the File
Manager yet. The call's result status is stored only in ioResult after the call completes,
or in either D0 or ioResult at the entry to the completion routine. If you're polling to
check for the call's completion, ioResult will indicate the call has completed when it's
less than or equal to 0. In general, when making asynchronous I/O calls (reads or
writes) there are only two types of function result error that are of any possible
consequence: a "driver not open" error (notOpenErr) and a driver reference number
error (badUnitErr or unitEmptyErr), which indicate the call wasn't successfully
queued by the driver and the ioCompletion routine won't be called. Neither one of these
error conditions makes any sense for the File Manager (which isn't a driver); the File
Manager will always call the completion routine (if any) of a given asynchronous
call. Your program should just ignore the function result of an asynchronous low-
level File Manager call and leave it up to the completion routine or the routine polling
ioResult to check for and handle any errors that may have happened on the call.
Q Many of the new File Manager calls are just HFSDispatch with new selector codes. How do I check whether a given selector is implemented? An example of a new File
Manager call is GetVolParms. Currently I don't check, I just read the result code. It
seems to be OK. How should I interpret the response from Gestalt when called with
gestaltFSAttr? As I read it, gestaltFullExtFSDispatching tells me that all the calls are
available. Are there times that only a few of them are available? PBHGetVolParms
seems to be available at all times anyway. Where do I find more info on the workings of
HFSDispatch? In general I would appreciate some more info on the compatibility issue.
A There are two issues. One is that not all versions of the File Manager support all calls. The other is that even if the File Manager supports the calls, individual volumes
may not.
The first issue is addressed by Gestalt's gestaltFSAttr selector. Before System 7,
HFSDispatch supported a fixed range of selectors. The result was that some advanced
file services were unavailable, even though the volume would support them. A good
example is PBCatSearch. If you mount an AppleShare 3.0 or FileShare volume under
System 6 with the AppleShare 3.0 Chooser extension, the volume will report via
PBHGetVolParms that bHasCatSearch is true. But if you try to make the call, you'll get
back a paramErr because HFSDispatch doesn't know about the CatSearch selector.
System 7 doesn't restrict the range of HFSDispatch selectors. For external file
systems, this means it's up to the external file system to determine whether it can
handle the selector and to return an appropriate error if it cannot. This is the meaning
of the gestaltFullExtFSDispatching flag. If it's true, there are no limitations on the
range of selectors.
The second problem is that even though HFSDispatch won't limit the range of
selectors, the volume may still not support the call. To turn the previous example
around, making a PBCatSearch call in System 7 to a pre-AppleShare 3.0 volume will
result in an error because the volume doesn't support the call.
The best way to determine whether a volume supports a feature is to use
PBHGetVolParms. This can return most of the information you need about advanced file
system calls. Unfortunately, there can be problems even with that. For example, when
the user turns file sharing on and off, the bHasPersonalAccessPrivileges flag can
change. So you can't just test attributes once and assume they'll never change.
As far as knowing whether PBHGetVolParms is available, this is not a new call. It's
documented in Chapter 21 of Inside Macintosh Volume V. The way to check for it is to
simply call it and if you get back a paramErr, it's unsupported (page 387). This
seems to be what you're doing, so you should be safe.
To summarize, there's no guaranteed way to know if a particular selector will work
(but it should never crash, just return paramErr). The right sequence of steps is to
first check to see if the HFS supports the full range of calls, then check for specific
features using PBHGetVolParms. And in any event, you should always check for errors
and be prepared to take appropriate action. A good example of how to do this can be
found in the January 1992 version of the Macintosh Technical Note "Searching
Volumes--Solutions and Problems" (formerly #68).Q How does Developer Technical Support manage to answer so many difficult questions so accurately?
A We swear by the Magic 8-Ball as a technical reference. Not only is it convenient, user-friendly, and available at your local toy store for less than ten dollars, but it's
guaranteed 100% correct. This way, we manage to answer all questions quickly and
accurately and still leave time for playing Spaceward Ho!
Q What's the purpose of the MacApp 'mem!' and 'seg!' resources, and where does the documentation for these resources exist?
A The 'mem!' resource allows you to change MacApp's memory allocation reserves in various ways. Each contains three numbers: the amount to add to the temporary
reserve, which is used for system allocations such as system resources and temporary
handles; an amount to add to the permanent reserve, which is used by you for your
memory allocation; and an amount of stack space. Having multiple 'mem!' resources
causes their values to be summed; in this way, you can create a "debugging" 'mem!'
resource that gives you extra space and delete it when you produce a non-debug
version. This is discussed in the MacApp 2.0 General Reference, in Chapter 3.
The 'seg!' resource is used to reserve space for code segments. If the Macintosh ever
tries to load a code segment but fails due to lack of memory, it will crash. Thus,
MacApp keeps a store of memory solely for loading code resources. It sizes this
reserve by adding together the sizes of the segments named in the 'seg!' resource. One
way to do this would be to just name all the segments, so that you know there's room
for them all; however, this would be wasteful, because many segments are often
unused (your printing code, for example). So what you do is name only those segments
that represent the largest code path you can have--the calling chain that would
require the largest set of code segments to be loaded at any time. This is also described
in Chapter 3 of the MacApp General Reference. In contrast, 'res!' names segments that
must be resident all the time; they're actually loaded and made resident, as opposed to
the 'seg!' segments, which are used only to calculate how much memory should be
reserved for segments in general.
Q I've been thinking of shutting down the System 7 Finder. Is this a cool thing to do in my application?
A We normally recommend that you don't quit the System 7 Finder application. Nevertheless, there may be a few good reasons to shut down the Finder. For example,
the Installer (the only application Apple ships with a good reason to do so) sometimes
needs to shut down the Finder and all other applications to make sure system resources
aren't being used while they're being updated by the Installer.
If you find yourself in a situation where you need to shut down the Finder, you should
know about a few things:
• Before you shut down the System 7 Finder, use the Process Manager to see
if the File Sharing Extension is running. If so, you should shut it down before
shutting down the Finder. The File Sharing Extension shouldn't be running
without the Finder because the Finder is the only user interface the File
Sharing Extension has. You shouldn't take away the user interface to file
sharing. There's another good reason to shut down the File Sharing Extension
before the Finder. The Network Extension (not the Network control panel)
handles all the user interface transactions among the Finder, the File Sharing
Monitor control panel, the Sharing Setup control panel, the Users & Groups
control panel, and the File Sharing Extension (the file server). The Network
Extension opens another file, the Users & Groups Data File, so that it can
manipulate users and groups. When you shut down the Finder (with a
kAEQuitApplication Apple event), the Network Extension and its connection to
the Users & Groups Data File are also closed (almost). Because of a minor bug
in the system, the File Manager thinks that the file is closed and that the FCB
used by that access path is free for reuse; however, the File Sharing Extension
thinks the access path to the Users & Groups Data File from the Network
Extension is still open. When the File Manager attempts to reuse that FCB to
open another file later, the file is opened, but because the File Sharing
Extension thinks that FCB is still in use by the Network Extension, it won't
allow access to the file and it returns opWrErr (-49) to the Open call. At this