June 93 - MACINTOSH Q & A
MACINTOSH Q & A
MACINTOSH DEVELOPER TECHNICAL SUPPORT
Q When a request for information is passed to me through an Apple event, the direct object parameter of my reply event is a descriptor list that includes an AERecord of
my information. When I use AEPutPtr and the AEPutParamDesc, is the data copied or
merely referenced? Should I be disposing of the AERecord and/or the descriptor list,
or should I expect AEProcessAppleEvent to dispose of them?
A Whenever you make one of the AEPutXXXX calls, the Apple Event Manager copies the data you put into the list, event, or record, so as soon as you make the call you can
dispose of the data you put. Thus, the following is correct:
AEPutParamDesc(&theEvent, keyDirectObject, &theSpec);
AEDisposeDesc(&theSpec);
And so is this:
HLock(myTextHandle);
AEPutParamPtr(&theEvent, keyDirectObject, typeText,
(Ptr)*myTextHandle, GetHandleSize(myTextHandle));
DisposeHandle(myTextHandle);
The only two descriptors disposed of by the Apple Event Manager itself (at the conclusion of AEProcessAppleEvent) are the original Apple event and the reply Apple
event. So, anything that you create and manipulate yourself should be disposed of by
you when you add it to another Apple event record or when you're done with it. The two
that you don't dispose of yourself are theEvent and reply, which are passed to you, as
in:
pascal OSErr AEXXXHandler(AppleEvent *theEvent, AppleEvent *reply,
long refIn)
This even holds true for AESend. When you send an event, you can immediately dispose
of your copy of the event, as follows:
AESend(&myEvent, nil, kAENoReply, kAENormalPriority,
kAEDefaultTimeout, nil, nil);
AEDisposeDesc(&myEvent);
Q The System 7.1 Digest has a disturbing comment about GetMHandle -- namely that it was never supported and will no longer work. Is this true?
A This warning is misleading and is being corrected in future release notes. It applies only to pop- up menus created with the pop-up menu control. Before System 7.1,
after a control was created GetMHandle would return the menu handle for the control,
although it was never documented as doing so. In System 7.1 it was changed so that the
menu would be inserted into the menu list only when the control was getting ready to
pop up the menu and deleted as soon as the control was done with it, so you could no
longer use GetMHandle to retrieve the menu handle. The proper way to get the menu
handle is from the mHandle field of the popupPrivateData structure. The handle to this
structure is in the contrlData field of the pop-up menu's control record.
A corollary is that the pop-up control has always checked to see if the menu is already
in the menu list. If it is, the control doesn't get the menu from the menu resource and
doesn't delete the menu when it's done. You can use this feature, for example, if you
want to create a menu with NewMenu rather than getting it from a resource. In this
case, and all other cases where the application inserts and deletes the pop-up menu in
the menu list itself, GetMHandle can be used to retrieve the menu handle because it's
under the control of the application.
Q I read that Photo CD discs can be read by the AppleCD SC Plus and the AppleCD 150. Does this mean a plain vanilla AppleCD SC can't read them? Is this a hardware
limitation, or will there be a software fix?
A Apple erroneously reported that the original AppleCD SC could not read single-session Photo CD discs. This turns out not to be the case; all of Apple's CD-ROM
drives can read single- session Photo CD discs.
Two levels of support are available for Kodak Photo CDs: the ability to read the first
session on the Photo CD itself, and the ability to deal with more than just the initial
session of a multisession CD. The AppleCD 300i is the first CD-ROM player from
Apple to support multisession Photo CDs. For details about both support levels, check
the Tech Info Library on AppleLink.
Q Inside Macintosh Volume V, page 103, says that when a PICT pattern opcode (for instance, 0x0012) comes along, and the pattern isn't a dither pattern, the full pixMap
data follows the old-style 8-byte pattern. The pixMap data structure shown on page
104 starts with an unused long (baseAddr placeholder), followed by the rowBytes,
bounds, and so on. However, looking at the Pict.r file on the October 1992 Developer
CD, at the same opcode (BkPixPat == 0x0012), the first data field after the old-style
pattern (hex string[8]) is the rowBytes field (broken down into three bitstrings).
The baseAddr placeholder field isn't there. Which is correct?
A The Inside Macintosh Volume V documentation on pages 103-104 is wrong. The Pict.r file correctly describes the format of the PnPixPat and BkPixPat opcodes. So
there shouldn't be a baseAddr field in the pixMap record of a pattern as stored in the
PnPixPat of a PICT. However, the baseAddr does occur in a 'ppat' resource as described
on page 79. Thanks for pointing out this discrepancy.
Q How do I find the correct time values to pass to GetMoviePict, to get all the sequential frames of a QuickTime movie?
A The best way to find the correct time to pass to get movie frames is to call the GetMovieNextInterestingTime routine repeatedly. Note that the first time you call
GetMovieNextInterestingTime its flags parameter should have a value of
nextTimeMediaSample + nextTimeEdgeOK to get the first frame. For subsequent calls
the value of flags should be nextTimeMediaSample. Also, the whichMediaTypes
parameter should include only tracks with visual information, 'vide' and 'text'. Check
the Movie Toolbox chapter of the QuickTime documentation for details about the
GetMovieNextInterestingTime call. For a code example, see the revised SimpleInMovie
on this issue's CD. The routine to look at is called DoGetMoviePicts in the file
SimpleInPicts.c.
Q My routine uses a dialog hook to set and retrieve certain values in new items added to the default box. Previously, with SFPPutFile, I was able to use a hit on the Save item
to retrieve and save the values. This also works with CustomPutFile unless the
Replace/Cancel dialog box appears, because the dialog hook routines are also called for
it! With the dialog pointer now pointing at the small alert, any reference to expected
items leads to disaster, since they don't exist. Isn't calling the dialog hook routine to
respond to hits in the alert box wrong and therefore a bug?
A Both Standard File and the Edition Manager in System 7 allow you to have control in your filter when one of the subdialog boxes comes up. You can differentiate between the
main dialog and the subdialogs by looking in the refCon field of the dialog record passed
to you. In Standard File's case, if the dialog is the main dialog, the refCon will be:
/* From StandardFile.h */
/* The refCon field of the dialog record during a modalfilter
or dialoghook contains one of the following: */
#define sfMainDialogRefCon 'stdf'
#define sfNewFolderDialogRefCon 'nfdr'
#define sfReplaceDialogRefCon 'rplc'
#define sfStatWarnDialogRefCon 'stat'
#define sfLockWarnDialogRefCon 'lock'
#define sfErrorDialogRefCon 'err '
This is described in detail on page 26-18 of Inside Macintosh Volume VI, in the
middle of the section that describes all the callbacks and pseudo items for Standard File
under System 7. The main purpose of this is to allow your additional dialog items to
react properly when another dialog box is brought up in front of them, not to allow you
access to the subdialogs. Also, since Standard File has no idea what types of items
you've added to the dialogs, giving you control during subdialogs allows you to change
the look of your subitems, or to keep them active if they need periodic time for any
reason.
Q How do I find the current KCHR resource? A Here's a method for getting a copy of the KCHR resource currently being used by the system. This method works for both System 6 and System 7.
long keyScript, KCHRID;
Handle KCHRHdl;
/* First get the current keyboard script. */
keyScript = GetEnvirons(smKeyScript);
/* Now get the KCHR resource ID for that script. */
KCHRID = GetScript((short)keyScript, smScriptKeys);
/* Finally, get your own copy of this KCHR. Now you can pass
a proper KCHR pointer to KeyTrans. */
KCHRHdl = GetResource('KCHR', KCHRID);
}
Q When I use CopyBits to move a cGrafPort's portPixMap to another cGrafPort (my printing port), it works like a charm when background printing is turned on, but
when CopyBits gets called with background printing turned off, the image that prints
isn't the image at all. Why is this happening?
A You should be aware that since you're copying the pixels directly from the screen, the baseAddr pointer for the screen's pixMap may be 32-bit addressed. In fact, with
32-Bit QuickDraw, this is the case. This in itself isn't a problem, since CopyBits
knows enough to access the baseAddr of the port's pixMap in 32-bit mode, as follows:
mode = true32b;
SwapMMUMode(&mode);// Make sure we're in 32-bit addressing mode.
// Access pixels directly; make no other system calls.
SwapMMUMode(&mode);// Restore the current mode.
That's how you'd normally handle things if you were accessing the pixels directly
yourself. Unfortunately, the LaserWriter driver doesn't know enough to do the
SwapMMUMode and instead ends up copying garbage (from a 32-bit pointer stripped
to a 24-bit pointer).
So why does background printing work? Because when you print in the background,
everything is rolled into a PICT, which the driver saves off for PrintMonitor. Since
the driver is using the standard QuickDraw picture bottlenecks to do this, and CopyBits
knows to swap the MMU mode before copying the data into the picture, everything
works great. Later, at PrintMonitor time, the picture is played back. Since the data is
no longer 32-bit addressed, the LaserWriter driver doesn't have to call
SwapMMUMode to do the right thing; it can just play the picture back. The solution we
propose for you is something similar. At print time (before your PrOpenPage call),
call OpenPicture, copy the data from the screen with CopyBits, call ClosePicture, and
then call DrawPicture within your PrOpenPage/PrClosePage loop. That should do the
trick.
Note that copying bits directly from the screen is not something we recommend.
Unless you have no alternative, you should always copy from the original source of the
data instead.
Q Is there a way to read Greenwich Mean Time offsets from the Map control panel? A There's actually a system-level call to find out where you are. It's a Script Manager call named ReadLocation (used by the Map control panel), which returns a structure
giving you all the information you need. Here's a description of the call, copied from
MPW 411:
pascal void ReadLocation(MachineLocation *loc)
= {0x205F,0x203C,0x000C,0x00E4,0xA051};
File {CIncludes}script.h
In C:
pascal void ReadLocation(MachineLocation *loc);
pascal void WriteLocation(const MachineLocation *loc);
These routines access the stored geographic location and time zone information for the
Macintosh from parameter RAM. For example, the time zone information can be used to
derive the absolute time (GMT) that a document or mail message was created. With
this information, when the document is received across time zones, the creation date
and time are correct. Otherwise, documents can appear to be created after they're read.
(For example, someone could create a message in Tokyo on Tuesday and send it to San
Francisco, where it's received and read on Monday.) Geographic information can also
be used by applications that require it.
If the MachineLocation has never been set, it should be <0,0,0>. The top byte of the
gmtDelta should be masked off and preserved when writing: it's reserved for future
extension. The gmtDelta is in seconds east of GMT; for example, San Francisco is at
minus 28,800 seconds (8 hours * 3600 seconds per hour). The latitude and longitude
are in fractions of a great circle, giving them accuracy to within less than a foot,
which should be sufficient for most purposes. For example, Fract values of 1.0 = 90º,
-1.0 = -90º, and -2.0 = -180º. In C:
Fract latitude;
Fract longitude;
char dlsDelta; /* signed byte; daylight savings delta */
long gmtDelta; /* must mask - see documentation */
The gmtDelta is really a 3-byte value, so you must take care to get and set it
properly, as in the following C code examples:
long GetGmtDelta(MachineLocation myLocation)
long internalGMTDelta;
internalGMTDelta = myLocation.gmtDelta & 0x00ffffff;
// need to sign extend
if ( (internalGMTDelta >> 23) & 1 )
internalGmtDelta = internalGmtDelta | 0xff000000;
return (internalGmtDelta);
}
void SetGmtDelta(MachineLocation *myLocation, long myGmtDelta)
char tempSignedByte;
tempSignedByte = myLocation->dlsDelta;
myLocation->gmtDelta = myGmtDelta;
myLocation->dlsDelta = tempSignedByte;
}
Q Did you hear that they had computer music at Clinton's inauguration? A Yes, they danced to Al Gore Rhythms. Q What (if at all) is the limitation on the number of files in a folder? In other words, is there a number N, such that if I have N files in a folder, and I try to Create file
number N+1, I'll get some error?
A In general, the number of files that can be put in an HFS directory is unlimited; there isn't any point at which you'll receive an error from Create, because new file
description records can almost always be created. The only way you can get a disk full