March 93 - MACINTOSH Q & A
MACINTOSH Q & A
MACINTOSH DEVELOPER TECHNICAL SUPPORT
Q Our program has a problem with filenames that start with a period. During an Open call, if the filename starts with a period, the Open code calls the Device Manager (for
drivers and DAs) instead of the File Manager. However, we've seen other applications
that can successfully open these files. What's the secret? How do we open files that
otherwise look (from the name) like drivers?
A The Open trap is shared between the Device Manager and the File Manager. When Open is called, it checks first to see whether you're trying to open a driver. Driver
names always start with a period. If you can, avoid using filenames that begin with a
period. Macintosh Technical Note "HFS Elucidations" (formerly #102) discusses this
conflict. The secret to opening those files is using the new Open Data Fork functions
available with System 7 -- FSpOpenDF, HOpenDF, and PBHOpenDF. These functions
bypass the driver name check and go right to the File Manager. Here's the code we use
to open a file:
err := HOpenDF(vRefNum, dirID, fileName, permission, refNum);
IF (err = paramErr) THEN {HOpenDF call isn't available}
err := HOpen(vRefNum, dirID, fileName, permission, refNum);
{try again with old HOpen call}
Try this and your problem should go away under System 7. The code retries with the
regular Open call (which uses the same input parameters), so this code can be used in
programs that run under both System 6 and System 7.
Q In System 7, the memory allocated for INITs by the 'sysz' resource mechanism seems to be limited to about 16 MB on our 32 MB Macintosh IIfx. For 'sysz' values up
to 15 MB it works great, but it seems the system heap can't grow beyond 16 MB. Is
there some reason for this?
A The system heap size at startup is limited to approximately half the size of total RAM. This is because the early startup code places the stack and some globals in the
middle of RAM so that the system heap can grow up from below while BufPtr is
lowered from above. This is basically the situation until an application is launched.
Things are eventually rearranged so that the system heap will have more room to
grow, but this doesn't happen until the Process Manager is launched, after INIT time.
This limitation would mean that you could size your heap until it reached nearly (but
not quite) half the size of RAM. We suggest that you attempt to allocate some of your
RAM later, after the Process Manager starts up; at that point, the system heap should
be somewhat less limited.
Q The Macintosh Technical Note "Setting ioNamePtr in File Manager Calls" (formerly #179) says that ioNamePtr needs to point either to nil or to storage for a Str255.
This contradicts the Technical Note "Searching Volumes -- Solutions and Problems
(formerly #68), which gives an example of a recursive indexed search using
PBGetCatInfo. The example uses a Str63. Which Technical Note is correct?
A To be generically correct, ioNamePtr should point to a Str255. However, in the case of PBGetCatInfo and other calls that return a filename (or a directory name), a
Str63 is sufficient. The reasons are tied to the history of the Macintosh file system.
MFS, the original Macintosh file system, supported filename lengths of up to 255
characters. However, the Finder on those systems supported filename lengths up to
only 63 characters and, in fact, developers were warned to limit filename lengths to
fewer than 64 characters (see page II-81 of Inside Macintosh Volume II).
HFS, the hierarchical file system (in every Macintosh ROM since the Macintosh
Plus), further limited filename lengths to 31 characters. If you mount an MFS disk
while running HFS, the old MFS code is called to handle the operation. So, the file
system can still create and use files with long filenames on MFS volumes. When the
System 7 file system was being designed, Engineering had to decide what size string to
use in FSSpec records. The decision was to use a Str63 instead of a Str31 to be able to
support long MFS filenames, and to use a Str63 instead of a Str255 because there
were probably very few filenames with over 63 characters (remember, the old
Finder limited filenames to 63 characters). Using a Str63 instead of a Str255 saves
192 bytes per FSSpec record.
So, we recommend that you use at least a Str63 for filenames, as in "Searching
Volumes -- Solutions and Problems." If you need to manipulate the filename in any
way after you've gotten the name -- for example, to concatenate it with another string
-- you might want to use a Str255.
Note: Even though the System 7 file system supports filenames longer than 31
characters on MFS volumes, the System 7 Finder does not. In fact, the System 7 Finder
currently crashes if you try to open an MFS volume (that is, open the volume window)
that has files with names longer than 31 characters.
Q I'm trying to use the Macintosh Time Manager to calculate elapsed times, but when I increase the delay time from $4FFFFFF to $5FFFFFF I get incorrect results. Why is
this happening?
A There seems to be an undocumented limitation of the Time Manager: it can't keep track of times longer than about a day, so it replaces them with the maximum time it
supports. For Time Manager tasks, this isn't crippling; the task simply executes
earlier than expected. When used for elapsed-time calculations, however, it's a bad
thing; the Time Manager installs the task with the smaller time, and when you remove
it, you see a smaller than expected remaining time. This makes it appear as if a large
period of time has passed.
The value at which the Time Manager trims is approximately $53A8FE5. The reason
for this strange value is somewhat complex. The Time Manager uses a VIA timer to do
its measurement. This timer runs at 783360 Hz, giving it a resolution of about 1.276
microseconds. However, the Macintosh could never actually provide this kind of
accuracy, given its latencies and overhead. Also, this frequency would have given a
32-bit counter a range of only about 91 minutes. Therefore, the Time Manager
actually throws away the low four bits of this counter, keeping a 32-bit counter with
a resolution of 20.425 microseconds and a range of 24 hours, 22 minutes. This time
is a lot larger than the maximum number of microseconds that can be measured, but is
equal to 87,724,005 milliseconds, which is (ta-dahh!) $53A8FE5. This is why you
were overflowing the Time Manager's internal counter, causing your task to be
clipped.
All should work well if you use times less than 24 hours. If you need to measure
durations for times exceeding the Time Manager's limits, you can use a
fixed-frequency task that executes every hour and increments an hour counter. To
determine the fractional hours component of the time, you'd remove the task to
determine how much longer till the next hour.
Q When a picture that contains a pixMap is spooled into a window, how and when is the depth of the pixMap in the picture converted to the depth of the screens the window is
on?
A When a picture is spooled in, if QuickDraw encounters any bitmap opcode, it allocates a pixMap of the same depth as the data associated with the bitmap opcode,
expands the data into the temporary pixMap, and then calls StdBits. StdBits is what
triggers the depth and color conversions as demanded by the color environment (depth,
color table, B&W settings) of the devices the target port may span (as when a window
crosses two or more screens).
If there's not enough memory in the application heap or in the temporary memory
pool, QuickDraw bands the image down to one scan line and calls StdBits for each of
these bands. Note that if you're providing your own bitsProc, QuickDraw will call it
instead of StdBits. This process is the same when the picture is in memory, with the
obvious exception that all the picture data is present; the color mapping occurs when
StdBits does its stuff.
Q How do I get the pixel depth of the QuickTime video media for a given track? A To find the video media pixel depth, you'll need to retrieve the media's image description handle. You can use GetMediaSampleDescription to get it, but this routine
needs both the video media and the track's index number. It's not obvious, but a media's
type is identified by its media handler's type. Thus, you can walk through a movie's
tracks by using its indexes until you find video media, at which point you have both the
track index and video media.
The following sample code does the trick:
#include
#include
#include
Media GetFirstVideoMedia(Movie coolMovie, long *trackIndex)
Track coolTrack = nil;
Media coolMedia = nil;
long numTracks;
OSType mediaType;
numTracks = GetMovieTrackCount(coolMovie);
for (*trackIndex=1; *trackIndex<=numTracks; (*trackIndex)++) {
coolTrack = GetMovieIndTrack(coolMovie, *trackIndex);
if (coolTrack) coolMedia = GetTrackMedia(coolTrack);
if (coolMedia) GetMediaHandlerDescription(coolMedia,
&mediaType, nil, nil);
if (mediaType = VideoMediaType) return coolMedia;
}
*trackIndex = 0; // trackIndex can't be 0
return nil; // went through all tracks and no video
}
short GetFirstVideoTrackPixelDepth(Movie coolMovie)
SampleDescriptionHandle imageDescH =
(SampleDescriptionHandle)NewHandle(sizeof(Handle));
long trackIndex = 0;
Media coolMedia = nil;
coolMedia = GetFirstVideoMedia(coolMovie, &trackIndex);
if (!trackIndex || !coolMedia) return -1; // we need both
GetMediaSampleDescription(coolMedia, trackIndex, imageDescH);
return (*(ImageDescriptionHandle)imageDescH)->depth;
}
Q What's the difference between ignorance and apathy? A We don't know and we don't care. Q Could you tell me what the "printer driver is MultiFinder compatible" bit is used for?
A The "printer driver is MultiFinder compatible" bit provides two features. First, it allows the printer driver resource file to be opened by multiple clients. This was
obviously needed to support multiple applications printing simultaneously under
MultiFinder. The other feature provided by the flag is the loading of PDEFs into the
system heap rather than the application heap (which is where they go under the
Finder). The MultiFinder-compatible bit has a major limitation: if your driver has
this flag set, you aren't allowed to add or resize resources, or do anything else that
would cause the RAM- resident resource map to change. Although MultiFinder lets
multiple applications open the printer resource file at the same time, it has no control
over the resource map that gets loaded by the Resource Manager when the file is
opened. Because of this, each client gets its own personal copy of the resource map.
When these clients get done with the file, they write the resource map back to the file
(via UpdateResFile). Obviously, if the resources have changed in any way, the last
client to call UpdateResFile is the only one whose changes will be recorded. This is a
"thrill seeker" method of handling the printer driver resource files, but since none of
the Apple printer drivers currently add or resize resources, it made sense.
So the bottom line here is that if you want your drivers to be compatible under
MultiFinder, you'll have to implement a scheme that doesn't require adding or resizing
resources. It's OK to change the data in a resource, as long as you don't change its size.
Changing the data won't cause changes to the resource map, so each client will still
have accurate copies of the map.
Here's what would happen to your printer driver's resources under the Finder and
MultiFinder when the MultiFinder-compatible bit is set:
• Under the Finder in system software version 6.0.x: All resources are
loaded into the application heap -- regardless of the resource attribute's bit
setting. If the resource has the "load into the system heap" bit set, it will still
be loaded into the application heap under the Finder. This makes sense in the
Finder world because the application heap will usually have more room than
the system heap.
• Under MultiFinder in System 6 or System 7: All the printer driver's
resources will be loaded into the system heap. This is true whether the "load
into the system heap" bit is set or not.
Why does the resource loading occur this way, even when the resource's "load into the
system heap" bit is set? Patches to the GetResource trap load all your printer driver's
resources into the system heap when the MultiFinder-compatible bit is set under
MultiFinder, and into the application heap under the Finder (as described above),
which is why you can't override this behavior.
By the way, you should be aware of the SetPDiMC MPW tool, which is available on the
Developer CD Series disc. It will automatically set the MultiFinder-compatible bit for
you when you build your printer driver.
Q If I call FSWrite and attempt to write more than space allows, what happens? Of course I get a Disk Full error, but does FSWrite write as much as possible before
quitting, and then return the number of bytes written in the count parameter?
A In the current implementation of the file system, writes to local volumes owned by the file system are an all-or-nothing deal. If the space for a write can't be allocated,
the write call fails and no bytes are written.
However, do not depend on that, because the Macintosh file system doesn't control all
volumes that might be mounted. Today, Apple ships four external file systems:
CD-ROM, AppleShare, ProDOS File System (for Apple II ProDOS volumes), and PC
Exchange (for MS-DOS volumes). Various third parties have written other external
file systems. The way they react to error conditions may not be the same as local
volumes controlled entirely by the file system.
To make your application always work correctly, you should check for errors and
handle them appropriately. If you get a dskFulErr, you should assume that if any
information was written to the file, it wasn't written correctly. You should either
reset the file's EOF to its previous position (if you're appending to an existing file) or
delete the file (if you had just created the file and were writing to it for the first
time).
Q How can I mount a volume without using aliases? I get the mounting information, then attempt to mount the volume. However, the PBVolumeMount call returns an error
code.
A The PBGetVolMountInfo, PBGetVolMountInfoSize, and PBVolumeMount functions are currently handled by only the AppleShare external file system (part of the AppleShare
Chooser extension). Those functions are available on AppleShare volumes when the
AppleShare Chooser extension is version 7.0 (system software versions 7.0 and
7.0.1), version 3.0 (AppleShare 3.0), or version 7.1 (System 7.1). The AppleShare
Chooser extension version 3.0 can be installed on System 6 systems, and then the
PBGetVolMountInfo, PBGetVolMountInfoSize, and PBVolumeMount functions can be
used in System 6. Other file systems may support these functions in the future. The
paramErr error code is returned when these functions aren't available on a particular
volume.
Q I need to prevent users from copying my application off a volume. Is there a new equivalent of the old Bozo bit?
A The Bozo or NoCopy bit was bit 11 in the fdFlags word of the FInfo record. As noted in the Macintosh Technical Note "Finder Flags" (formerly #40), this bit hasn't been
used for that purpose since System 5. In fact, System 7 reused bit 11 for the
isStationery bit. (See Inside Macintosh Volume VI, pages 9-36 and 9-37, for the
current list of Finder flag bits.)
There isn't an equivalent of the Bozo bit. However, the System 7 Finder won't copy
files that have the copy-protect bit (bit 6) set in the ioFlAttrib field returned by the
PBGetCatInfo function. However, the bits in the ioFlAttrib field can't be changed with
the PBSetCatInfo function. Instead, they're used to report the state of things set by
other parts of the file system.
The copy-protect bit is set by the AppleShare external file system when it finds that a
file's copy-protect bit is returned by an AppleTalk Filing Protocol file server. The
AppleShare external file system is the only file system we know of that sets the
copy-protect bit. There's no way to make the local file system set the copy-protect bit
for volumes it controls.
Q Are there any tricks that might speed up reading and writing large files to disk? We're using standard C calls (fread and fwrite) for this purpose since our file I/O
calls need to be platform-independent. Are there any low-level File Manager calls that
might speed up the file I/O?
A The C fread and fwrite functions are slower than File Manager calls because the standard C library adds another layer of overhead to file I/O. In addition, unless you
turn buffering off, all file I/O is double-buffered when you use the standard C library
functions. That is, fread reads from a RAM buffer in which the lower-level C library
code has buffered data read from a disk file; fwrite writes data into a RAM buffer and
the lower-level C library code writes from that buffer into a disk file.
For the highest file I/O throughput, and for maximum flexibility and functionality on
the Macintosh, you should use the File Manager for all file access. The low-level File