home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
answers
/
macintosh
/
programming-faq
< prev
next >
Wrap
Text File
|
1993-12-20
|
59KB
|
1,491 lines
Newsgroups: comp.sys.mac.programmer,comp.answers,news.answers
Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news.kei.com!eff!news.umbc.edu!europa.eng.gtefsd.com!uunet!pipex!sunic!kth.se!hemul.nada.kth.se!d88-jwa
From: d88-jwa@hemul.nada.kth.se (Jon WΣtte)
Subject: The Mac Programming Public Domain FAQ Answer sheet.
Message-ID: <1993Dec21.120855.19647@kth.se>
Followup-To: comp.sys.mac.programmer
Sender: usenet@kth.se
Nntp-Posting-Host: hemul.nada.kth.se
Organization: Royal Institute of Technology, NADA
Date: Tue, 21 Dec 1993 12:08:55 GMT
Approved: news-answers-request@MIT.Edu
Lines: 1476
Xref: senator-bedfellow.mit.edu comp.sys.mac.programmer:77849 comp.answers:3110 news.answers:16056
Archive-name: macintosh/programming-faq
The Public Domain Mac Programming FAQ Answer sheet.
Last update: 931023
This sheet was started by and is presently maintained by Jon
W{tte, whom you may reach as h+@nada.kth.se. If there is
anything you find errant, missing or in need of an update,
please send me your submission and I will include it (I can't
promise correct attributions, but I will try) All FAQ Answer
submissions sent to me will be considered to be in the public
domain unless stated otherwise (in which case they will not be
included in this FAQ sheet)
This sheet is currently archived on nada.kth.se where you can
reach it using afs as /afs/nada.kth.se/public/ftp/pub/hacks/mac-f
aq/CSMP_PD_FAQ or using anonymous FTP (GIVE YOUR E-MAIL ADDRESS
AS PASSWORD!) as pub/hacks/mac-faq/CSMP_PD_FAQ
I will try to update this sheet every two weeks or so. Changes
since first revision:
Fixed spelling and formatting. Added question numbering.
Files and Networks: [Mattias Ullrich]
Lisp and SmallTalk: [Rainer Joswig]
Free development languages: [Bob Loewenstein]
Various: [Pete Gontier]
Lots of suggestions: [Peter Lewis]
Wake Up And Smell The Glue: [Matthias Neeracher]
Development environments: [Howard Berkey]
SmallTalk: [Alun ap Rhisiart]
CustomGetFile: [Jim Walker ]
This sheet is divided into several parts; each of which covers a
general area which often gets asked about in the Internet
newsgroup comp.sys.mac.programmer. Please download a copy of
this answer sheet and search it before you post to the 'net, to
help reduce bandwidth.
There is NO or VERY LIMITED error checking in these code
examples, FOR BREVITY ONLY. You should make sure you ALWAYS
check ALL return codes, and handle any that you are not prepared
to deal with appropriately.
The coding style used in the example C code is my own, and
you'll have to live with it.
The groups are (you may search for *<number>* to jump directly
to a group with its questions and answers)
0) Development and debugging tools and documentation for the Mac
1) Files and the File Manager
2) Serial ports
3) TCP/IP and sockets
4) AppleEvents and the Apple Object Model
5) AppleScript
6) Drawing using QuickDraw
7) Drawing NOT using QuickDraw (aka directly to screen)
8) Cache issues and other processor differences
9) What about pre-emptive multitasking?
10) Handles; they are driving me crazy; Memory issues
11) _Gestalt and compatibility
12) Standalone code and dynamic linking
13) Reading the keyboard for games and screen savers
14) QuickTime
15) Ice Cream and Frozen Yoghurt
*0* Development and debugging tools for the Macintosh
0.1) Q: What do I need to start writing Macintosh software?
A: A Mac, a lot of time, and a few hundred $. Although you can
develop software on a Classic-type machine, it is not to be
attempted by the weak of heart or stressed of time. If you're
doing paid work and/or work for a company, a Quadra-class
machine or Centris 650 or better is almost a must; remember that
your time costs your employer much more than just your salary. 8
MB is a minimum to run at all comfortably, and Virtual Memory is
not suited for development work. Similarly; if you don't have at
least 20 MB free on your hard disk (40 MB for MPW) you need to
buy more space.
You need a development system such as Think C, Think Pascal ,
MPW C or Prograph, you need at least some of the New Inside Mac
books (Toolbox Essentials, Files, Memory come to mind) and a
good entry-level third-party book may help.
Once you are up to speed on the general layout of the Mac and
its toolboxes, you should call APDA and order the monthly
developer mailing, which will give you a CD chock full of
documentation, utilities and system software once a month. You
will also, obviously, need a CD player; one of which Apple's own
CD300 is a very good buy at the time of writing this. If you
don't have the dough for the monthly mailing ($250/year) you can
order a _develop_ subscription; this quarterly magazine
($30-$50/year) comes with a CD containing all Inside Mac
documentation.
Another tool which many find a must-have is the Think Reference
version 2.0, containing reference material on the most used
parts of the Mac toolbox with lightning-fast look-up and mostly
correct usage hints and code snippets.
0.2) Q: What is the most used Macintosh development language?
A: Out of products on the market, I have no idea; both MPW and
Think products appear to be used. Among hobbyists, the Think
products from Symantec are most popular because of the low
price, and steep educational discounts, and, of course, the
easily approachable interface!
The Think C linker only strips dead code on a FILE level basis
(and this is when you turn on "Smart Linking") The MPW linker
(of no specified IQ, as someone so eloquently put it :-) strips
dead code by the function. That may be part of the reason the
Think C linker is ten times faster than the MPW linker.
In the beginning, the Mac was programmed using Mc68000 assembly
or Pascal; this was reflected in the Old Inside Mac volumes
which only gave Pascal-style and assembly-style interfaces to
the Mac toolbox. These days, Apple tells us to use C or even
better C++ for developing new applications, as that will speed
up the transition to PowerPC and also coming cross-platform
efforts.
There are also at least two Fortran compilers, at least three
SmallTalk implementations (ObjectWorks, SmallTalk/V and
SmallTalkAgents), a world-class LISP/CLOS implementation
(Macintosh Common Lisp 2.0) and a Modula/2 implementation.
Apparently, using Envy/packager, you can strip out unused code
pretty effectively from Digitalk and PP apps, which are then
smaller (and of course more memory efficient) than C++ apps.
Metrowerks have a Pascal and a Modula II compiler. Rumour has it
they're building C and C++ for both 68k and coming PPC Macs.
CSI has MacForth, of which I only know the name and someone who
says it's pretty good.
There is another good Common Lisp implementation: Procyon Common
Lisp. I don't know if it is actively supported, but Procyon CL
is also available for DOS, OS/2 and Windows (as Allegro CL/PC)
and actively developed.
0.3) Q: Where do I find a public domain C compiler for the Mac.
Is there a GCC for the mac? What about the FSF boycott of Apple
products?
A: There is no really good solution for a "for-free" C
development system for the Mac. GCC has been ported, but
requires the MPW shell and MPW assembler to run; these have to
be bought from APDA. There is a standalone port of GCC 1.37
underway, but it is presently on hold because of licensing
issues. There was a freely available C compiler called Harvest
C, which was somewhat unstable but usable for smaller programs;
it was abandoned by the original author Eric W Sink because of a
lack of time.
The FSF boycott of Apple products means they will not talk to
you if you ask them for help in doing a Mac port, and they will
not incorporate your changes into their main code base. However,
they still allow others to port GNU stuff to the Mac, and it has
been done with most of the application-like GNU programs (bison,
flex, perl (not really part of GNU), ...)
0.4) Q: Are there any other free Mac development platforms?
A: Yerk and Mops. These are object oriented languages based on
the old product Neon which itself was based on Forth. They are
available with Manuals at oddjob.uchicago.edu (anonymous FTP).
Plus, there's MacGambit, MacScheme, xlisp, and MacMETH which is
the actual ETH (read: Nick Wirth's group) Modula 2, all for free
via FTP.
And OpenProlog. And SIOD (Scheme in One Defun) And [mail in more
if you dare]
0.5) Q: What's the difference between the MPW and Think
environments?
A: The main difference is that Think is an integrated
environment, while MPW provides you with a command-line shell
for your Mac and tools to use in it. MPW also has a slightly
higher systems demand and a much slower linker.
The good thing about MPW is that you can write scripts and make
files to do anything you want in the way you want it. Think
still doesn't have a viable solution to do a build that requires
more than one link operation, or has more than one destination
file.
For the MPW environment, there are three source level debuggers;
SADE, SourceBug and Voodoo Monkey. The latter is an experimental
debugger with support for threads debugging; the middle is
bundled with MPW while SADE has to be bought separately (but is
fully scriptable in its own scripting language)
The Think environments have their own integrated debuggers; the
Think Pascal one has a lot of useful features while the Think
C/C++ one is a little more basic (but is gaining in
functionality with each release) Stepping through source code
and looking at variables is generally faster and easier in Think
than the MPW debuggers.
Any commercial Mac developer should have both Think and MPW of
whatever language they prefer (Pascal, C or C++)
0.6) Q: What is a good low-level debugger for the Mac?
A: MacsBug is freely available for ftp from ftp.apple.com; log
in as user anonymous and give your FULL e-mail address as
password. MacsBug is your basic monitor-type debugger that takes
a few hundred Ks of memory, and lets you break, step,
disassemble, look at the stack etc of most anything running on
your Mac. Since it's free (it's also on the developer CDs) and
provides most of the functionality you need, this is a popular
choice.
TMON is another debugger which sports a more mac-like interface;
it provides windows and uses the mouse. It can take as little or
much memory as you want by excluding or including certain areas
of functionality. A nice touch is the 6502 disassembler that you
can use to de-bug the code the IOP processors run on the Mac
IIfx and Quadra 900/950.
Jasik Designs have a debugger called The Debugger which can do
both low- and high-level debugging, with or without source and
for all types of code, application, code resources, everything.
This is the debugger of choice for many large developers because
of its high power and many features not found anywhere else.
However; newcomers beware! This is the Lamborghini of debuggers;
if you know how to drive it, it is the fastest way from A to B;
if you don't, you'll just end up in the ditch.
0.7) Q: Are there any visual developments environments for the
Mac (comparable to Visual C++)?
A: There is no Visual C++ as such. However, there is a C++
parser/editor called ObjectMaster which provides good browsing
and editing capabilities if you already have a C++ compiler.
Think C++ also comes with a browser built-in, and you can draw
dialogs/windows using plain old ResEdit, even for your custom
view types.
AppMaker is a GUI builder/code generator. Granted, it's not as
nice as VC++, but it's quite a product in any case.
Also, Neuron Data has their UI tool called Open Interface, which
is better than VC++ and creates code portable across 35
platforms. Unfortunately it's $2500 per developer per platform.
(There's also two other cross-platform products called XVT and
Galaxy, the former has gotten flak on UseNet while the latter
reportedly has decent networking support)
There is a fully visual, dynamic, object oriented data-flow-drive
n programming language for the Mac called Prograph Corporate
Programming Something-or-other (CPX). It is expensive ($1500)
but offers a built-in database, easy interfaces to existing data
bases, very high productivity in implement-test-debug cycling
and also offers cross-platform capabilities (it comes with a
class library which, when your code is written using it, works
under Windows after re-compilation)
There is a crossing between SmallTalk and C++ that is called
Component Workshop; although it seems large and slowly evolving,
it does offer some promising features not found in C++ itself.
There is also something called SmallTalkAgents that makes it
easy to create Mac applications using SmallTalk. If you'd rather
do Common Lisp, Macintosh Common Lisp offers a Common Lisp
Object System with support for most Mac interface items; you can
edit code while it is running and build stand-alone
applications.
However, all of these tools generate rather larger binaries with
larger system demands than a program written in C. On the other
hand; C++ programs require more memory and disk space than
programs written in assembly. It's a trade-off, and I believe
this type of tools is the wave of the near future.
0.8) Q: What class libraries are there for the Mac?
A: Apart from the libraries mentioned above, there are three
contenders: MacApp, TCL, and OOPC. On the horizon may be
Bedrock.
MacApp is a heavy-duty class library that has tons of features
and a steep learning curve; it runs under MPW with Pascal or
C++, and also under Think Pascal 4.0 A major application written
in MacApp is PhotoShop.
TCL stands for Think Class Library and comes with Think Pascal,
C or C++. It is a smaller library that still fills most peoples
needs; since Think C implements a subset of C++ (the most
important OO concepts such as virtual functions and inheritance)
and the TCL is carefully written not to take advantage of any
C++ features not in Think C, you can use it with Think C. A
major application written in TCL is Lotus 1-2-3.
OOPC is a newcomer in the field, and uses plain ANSI C. However,
it mangles the pre-processor to provide you with a system with
full inheritance, virtual functions, and dynamic re-binding of
functions for classes or individual objects. Start-up is slow,
since all "linking" of virtual functions and classes is made at
run-time, but performance otherwise is good. A Windows version
is promised for later this year.
0.9) Q: How should I debug and test my software?
A: Get ahold of, and install, the extensions DoubleTrouble,
DisposeResource and EvenBetterBusError. They will catch 80% of
any memory related bugs you may have, including many bugs that
follow NULL handles or pointers.
A low-level debugger is required, and while you install it,
install the "leaks" dcmd which will help you catch memory leaks
in your application. All of these tools are available from
ftp.apple.com.
*1* Files and the File Manager
1.1) Q: How do I tell fopen() to open a file the user has
selected using StandardGetFile?
A: The "standard" ANSI C file functions are less than well
suited for the Macintosh way of doing things. However, if you
are doing a port for your own enjoyment and benefit (or maybe
for in-house work) you can use the following function: (see
below about converting a wdRefNum into a vRefNum/parID pair)
*code*
FILE *
fopen_mac ( short vRefNum , long parID , char * fileName , char * mode ) {
short oldVol ;
short aVol ;
long aDir , aProc ;
FILE * ret = NULL ;
if ( GetVol ( NULL , & oldVol ) ) {
return NULL ;
}
if ( GetWDInfo ( oldVol , & aVol , & aDir , & aProc ) ) { return NULL ;
}
if ( HSetVol ( NULL , vRefNum , parID ) ) {
return NULL ;
}
ret = fopen ( fileName , mode ) ;
if ( HSetVol ( aVol , aDir ) ) {
/* an error we can't currently handle */
}
if ( SetVol ( oldVol ) ) {
/* an error we can't currently handle */
}
return ret ;
}
*end*
All of the above is necessary for one reason or another - if you
are interested, by all means look HSetVol up in Think Reference
2.0 or New Inside Mac: Files.
In older versions of MPW; this wouldn't work since the MPW
libraries used to do a GetVol and explicitly use that value by
itself.
1.2) Q: When can I use the HOpen, HCreate etc file calls? Are
they only System 7 calls?
A: All the HXxx calls that take a vRefNum and parID as well as
the file name are implemented in glue that works on any system
that has HFS (meaning 3.2 and up with the HD20 INIT, and all
systems from System 6 and up)
The glue is available in MPW 3.2 and up, and Think C 5.0 and up.
This goes for all HXxx calls except HOpenDF; therefore, if you
are interested in System 6 compatibility, use HOpen instead and
make sure you don't allow file names beginning with a period.
1.3) Q: Why do you say wdRefNum sometimes and vRefNum sometimes?
Why do you say parID sometimes and dirID sometimes?
A: When the Mac first made an appearance in 1984, it identified
files by using a vRefNum (volume reference number meaning a
floppy disk or later hard disk) and a name. Once HFS saw the
light of day, folders within folders became a reality, and you
needed a dirID as well to point out what folder you really meant
on the volume. However, older programs that wasn't being
rewritten still knew nothing about directory IDs, so Apple had
SFGetFile make up "fake" vRefNums that didn't just specify a
volume, but also a parent folder. These are called wdRefNums
(for working directory) and were a necessary evil invented in
1985. You should not create (or, indeed, use) wdRefNums
yourself.
There is a system-wide table that maps wdRefNums onto
vRefNum/parID pairs. There is a limit to the size of this table.
A dirID and a parID is almost the same thing; you say "parID"
when you mean the folder something is in, while you say a
"dirID" when you mean the folder itself. If you for instance
have a folder called "Foo" with a folder called "Bar" in it, the
parID for "Bar" would be the dirID for "Foo."
1.4) Q: How do I convert a wdRefNum as returned by SFGetFile
into a vRefNum/parID pair to use with the HXxx calls.
A: Use GetWDInfo, which is declared as:
Pascal OSErr GetWDInfo ( short wdRefNum , short * vRefNum , long
* parID , OSType * procID ) ;
The procID parameter must be non-NULL and point to an OSType
variable, but the value of that variable can and should be
ignored.
It is recommended that, as soon as you get your hands on a
wdRefNum, for instance from SFGetFile, you directly convert it
into a vRefNum/parID pair and always use the latter to reference
the folder.
1.5) Q: How do I select a folder using SFGetFile?
A: This requires a custom dialog with a filter proc. It is too
complicated to show here, but not totally impossible to
comprehend. There is sample code on ftp.apple.com, in the
directory dts/snippets, on how to do this.
1.6) Q: How do I get the full path of a file referenced by a
vRefNum, parID and name?
A: You don't.
OK, I cheated you. There is exactly ONE valid reason to get the
full path of a file (or folder, for that matter) and that is to
display its location to the user in, say, a settings dialog. To
actually save the location of the file you should do this:
(assuming the file is in an FSSpec called theFile - you can use
FSSpecs in your program even if you don't run under System 7;
just make your own MyFSMakeFSSpec that fills in the FSSpec
manually if it's not implemented)
*code*
if ( ! aliasManagerAvailable ) { /* System 6 ? */
GetVolumeName ( theFile -> vRefNum , vName ) ; GetVolumeModDate ( vRefNum , & date ) ;
Save ( vName , date , parID , fileName ) ;
} else {
NewAlias ( NULL , theFile , & theAlias ) ;
Save ( theAlias ) ;
DisposeHandle ( ( Handle ) theAlias ) ;
}
*end*
If you are really concerned about these issues (of course you
are!) you should save BOTH of these methods when available, and
load back whatever is there that you can handle; since users may
be using your application in a mixed System 6/System 7
environment.
To get back to the file is left as an exercise for the reader.
To open a file using fopen() or the Pascal equivalent, see above
about using and not using HSetVol.
1.7) Q: What about actually getting the full path for a file? I
promise I will only use it to show the location of a file to the
user!
A: Enter PBGetCatInfo, the Vegimatic of the Mac file system. Any
Mac hacker of knowledge has taken this system call to his heart.
What you do is this:
*code*
OSErr
GetFolderParent ( FSSpec * fss , FSSpec * parent ) {
CInfoPBRec rec ;
short err ;
* parent = * fss ;
rec . hFileInfo . ioNamePtr = parent -> name ;
rec . hFileInfo . ioVRefNum = parent -> vRefNum ;
rec . hFileInfo . ioDirID = parent -> parID ;
if ( parent -> name [ 0 ] ) {
rec . hFileInfo . ioFDirIndex = 0 ;
} else {
rec . hFileInfo . ioFDirIndex = -1 ;
}
rec . hFileInfo . ioFVersNum = 0 ;
err = PBGetCatInfoSync ( & rec ) ;
if ( ! ( rec . hFileInfo . ioFlAttrib & 0x10 ) ) { /* Not a folder */ if ( ! err ) {
err = dirNFErr ;
}
}
parent -> parID = rec . dirInfo . ioDrParID ;
parent -> name [ 0 ] = 0 ;
return err ;
}
OSErr
GetFullPathHandle ( FSSpec * fss , Handle * h )
{
Handle tempH = NULL ;
short err ;
FSSpec fs = * fss ;
while ( fs . parID > 1 ) {
tempH = NULL ;
PtrToHand ( & fs . name [ 1 ] , & tempH , fs . name [ 0 ] ) ; PtrAndHand ( ( void * ) ":" , tempH , 1 ) ;
HandAndHand ( * h , tempH ) ;
SetHandleSize ( * h , 0L ) ; HandAndHand ( tempH , * h ) ; DisposeHandle ( tempH ) ; tempH = NULL ;
GetFolderParent ( & fs , & sSpec ) ;
fs = sSpec ;
}
GetVolName ( fs . vRefNum , fs . name ) ;
PtrToHand ( & fs . name [ 1 ] , & tempH , fs . name [ 0 ] ) ; PtrAndHand ( ( void * ) ":" , tempH , 1 ) ;
HandAndHand ( * h , tempH ) ;
SetHandleSize ( * h , 0L ) ;
HandAndHand ( tempH , * h ) ;
DisposeHandle ( tempH ) ;
tempH = NULL ;
if ( ! IsFolder ( fss ) ) {
SetHandleSize ( * h , GetHandleSize ( * h ) - 1 ) ; // Remove colon }
return 0 ;
}
*end*
1.8) Q: So how do I get the names of the files in a directory?
A: You use PBGetCatInfo again, but this time you set ioFDirIndex
to 1 or more (you need to know the dirID and vRefNum of the
folder you're interested in) You then call PBGetCatInfoSync for
values of ioFDirIndex from 1 and up, until you get an fnfErr.
Any other err means you are not allowed to get info about THAT
item, but you may be for the next. Then collect the names in the
string you made ioNamePtr point to as you go along. Note that
you need to fill in the ioDirID field for each iteration through
the loop, and preferrably clear the ioFVersNum as well.
Note that the contents of a directory may very well change while
you are iterating over it; this is most likely on a file server
that more than one user uses, or under System 7 where you run
Personal File Share.
1.9) Q: How do I find the name of a folder for which I only know
the dirID and vRefNum?
A: You call (surprise!) PBGetCatInfo! Make ioNamePtr point to an
empty string (but NOT NULL) of length 63 (like, an Str63) and
ioFDirIndex negative (-1 is a given winner) - this makes
PBGetCatInfo return information about the vRefNum/dirID folder
instead of the file/folder specified by vRefNum, parID and name.
1.10) Q: How do I make the Finder see a new file that I created?
Or if I changed the type of it; how do I display a new icon for
it?
A: You call (surprise!) PBGetCatInfo followed by PBSetCatInfo
for the FOLDER the file is in. Inbetween, you should set
ioDrMdDat to the current date&time. Code:
*code*
OSErr
TouchFolder ( short vRefNum , long parID ) {
CInfoPBRec rec ;
Str63 name ;
short err ;
rec . hFileInfo . ioNamePtr = name ; name [ 0 ] = 0 ;
rec . hFileInfo . ioVRefNum = vRefNum ; rec . hFileInfo . ioDirID = parID ; rec . hFileInfo . ioFDirIndex = -1 ; rec . hFileInfo . ioFVersNum = 0 ; err = PBGetCatInfo ( & rec ) ;
if ( err ) {
return err ;
}
GetDateTime ( & rec . dirInfo . ioDrMdDat ) ; rec . hFileInfo . ioVRefNum = vRefNum ;
rec . hFileInfo . ioDirID = parID ; rec . hFileInfo . ioFDirIndex = -1 ; rec . hFileInfo . ioFVersNum = 0 ;
err = PBSetCatInfo ( & rec ) ;
return err ;
}
*end*
1.11) Q: Aren't we done with PBGetCatInfo soon?
A: Well, it turns out that you can also find out whether an
FSSpec is a file or a folder by calling PBGetCatInfo and check
bit 4 (0x10) of ioFlAttr to see whether it is a folder. You may
prefer to call ResolveAliasFile for this instead.
You can also check the script of the file's title using
PBGetCatInfo and check the ioFlFndrXInfo field if you want to
work with other script systems than the Roman system.
Another common use is to find out how many items are in a
folder; the modification date of something or the correct
capitalization of its name (since the Mac file system is case
independent BUT preserves the case the user uses)
1.12) Q: How do I set what folder should initially be shown in
the SFGetFile boxes?
A: You stuff the dirID you want to show into the lo-mem global
CurDirStore, and the NEGATIVE of the vRefNum you want into the
lo-mem global SFSaveDisk.
If you are using CustomGetFile and return sfSelectionChanged
from an "init" message handler, you must remember to clear the
script code, else the selection will not change.
1.13) Q: How do I find the folder my application started from?
How do I find the application file that's running?
A: Under System 7, you call GetCurrentProcess, followed by
GetProcessInformation with a pointer to an existing FSSpec in
the parameter block. This will give you your file, and, by using
the vRefNum and parID, the folder the application is in.
Beware from writing to your applications resource or data forks;
the former breaks on CDs/write protected floppies/file
servers/virus checkers, the latter fails on PowerPC as well as
in the above cases.
*2* Serial ports
2.1) Q: How do I get at the serial ports?
A: You call OpenDriver for the names "\p.AOut" and "\p.AIn" to
get at the modem port, and "\p.BOut" and "\p.BIn" for the
printer port. The function RAMSDOpen was designed for the
original Mac with 128 kB of memory and 64 kB of ROM, and has
been extinct for several years.
However, many users use their serial ports for MIDI, LocalTalk,
graphic tablets, or what have you and have installed an
additional serial port card to get more ports. What you SHOULD
do as a good application is to use the Comms Toolbox Resource
Manager to search for serial resources; this requires that the
Comms Toolbox is present (true on earlier System 6 with an INIT,
on later System 6 and System 7 always, as well as on A/UX) and
that you have initialized the comms resource manager. The exact
code follows (adapted from Inside Mac Comms Toolbox):
*code*
#include <CommsResources.h>
OSErr
FindPorts ( Handle * portOutNames , Handle * portInNames , Handle * names , Handle * iconHandles ) {
OSErr ret = noErr ;
short old = 0 ;
CRMRec theCRMRec , * found ; CRMSerialRecord * serial ;
* portOutNames = NewHandle ( 0L ) ; * portInNames = NewHandle ( 0L ) ; * names = NewHandle ( 0L ) ;
* iconHandles = NewHandle ( 0L ) ; while ( ! ret ) {
theCRMRec . crmDeviceType = crmSerialDevice ;
theCRMRec . crmDeviceID = old ;
found = ( CRMRec * ) CRMSearch ( ( QElementPtr ) & theCRMRec ) ;
if ( found ) {
serial = ( CRMSerailRec * ) found -> crmAttributes ;
old = found -> crm DeviceID ;
PtrAndHand ( & serial -> outputDriverName , * portOutNames , sizeof ( serial -> outputDriverName ) ) ;
PtrAndHand ( & serial -> inputDriverName , * portInNames , sizeof ( serial -> inputDriverName ) ) ;
PtrAndHand ( & serial -> name , * names ,
sizeof ( serial -> name ) ) ;
PtrAndHand ( & serial -> deviceIcon , * iconHandles , sizeof ( serial -> deviceIcon ) ) ;
} else {
break ;
}
}
return err ;
}
*end*
This will create four handles with the driver names, device
names and driver icon handles for all of the available serial
devices. Then let the user choose with a pop-up menu or
scrolling list, and save the choice in your settings file.
You can use OpenDriver, SetReset, SetHShake, SetSetBuf,
SerGetBuf and the other Serial Manager functions on these
drivers. To write to the serial port, use FSWrite for
synchronous writes that wait until all is written, or PBWrite
asynchronously for queuing up data that is supposed to go out
but you don't want to wait for it. At least once each tim
e through your event loop, you should call SerGetBuf on the in
driver reference number you got from OpenDriver, and call FSRead
for that many bytes - neither more nor less.
If you are REALLY interested in doing the right thing, you will
use the Communications Toolbox Connection Manager instead; this
will give you access to modems, direct lines, and networks of
various kinds using the same API! Great for stuff like BBSes
that may be on a network as well etc. The Comms Toolbox also
priovides modularized terminal emulat
ion and file transfer tools, although the Apple-suplied VT102
tool is pretty lame, as is the VT102 mode of the VT320 tool.
*3* TCP/IP and sockets
3.1) Q: Where is a Berkley sockets library for the Mac?
A: There are some problems with that. MacTCP, the Mac Toolbox
implementation of TCP/IP, doesn't have an API that looks at all
like Berkley sockets. For instance, there is ONE paramater-block
call to do a combined listen()/accept()/bind() - sort of. I have
heard that there may be a socket library available by ftp from
MIT but haven't seen it myself.
There is also a pretty good C++ TCP implementation called GUSI
which is easily handled, and it also is callable from C using
the Berkley socket API. Apart from TCP, it also handles
"standard" Mac network protocols such as ADSP. The big
disadvantage is that it is currently only implemented for MPW.
The ftp site is nic.switch.ch, software/mac/src/mpw_c.
I can also recommend the Communications Toolbox; for the price
of using an API that is simpler than the Berkley sockets, you
get the benefit of being able to use any kind of connection (TCP
tools are available)
Novell and Wollogong offer commercial socket-like libraries.
3.2) Q: Where do I find MacTCP?
A: You can buy the MacTCP developers kit from APDA. It is also
available on E T O, and if you want saner headers than those,
try ftp to seeding.apple.com.
*4* AppleEvents and the AppleEvent Object Model
4.1) Q: What are AppleEvents?
A: AppleEvents are a level-5 network protocol. If you are not
familiar with the ISO network stack, this means it's a way of
structuring sessions between network entities (programs) that is
not dependent on the underlying protocol (such as PPC or TCP/IP)
Despite being a network protocol, they can be very useful on
Macs that are not on a network. In short, they provide
applications with a comprehensive way to send arbitrary
structured data to other applications (or themselves) which
receive the events through their main event loop.
The AppleEvent Object Model is a way of looking at applications
and the data they contain, and also a level-6 network protocol.
You _can_ send AppleEvent Object Model data through AppleEvents
(and the standard AppleEvents defined in the AppleEvent Registry
use it) but you don't have to - unless you want to talk with
other applications, of course, then the AEOM is a lingua franca.
4.2) Q: What are the four required AppleEvents?
A: There are four events your application really must implement
if you want to sell it: the kCoreEventClass class,
kAEOpenApplication, kAEQuitApplication, kAEOpenDocuments and
kAEPrintDocuments events IDs. When you support these events (or
any AppleEvents) you will not get startup info through
GetAppParams() anymore, unless you run under System 6 of course.
The kAEOpenApplication event will be sent to you when the user
double-clicks your app and it's not started yet. When receiving
it, you can put up a new untitled window.
kAEOpenDocuments is sent when the user double-clicks your apps
documents. Note that if the first AppleEvent you receive is a
kAEOpenDocuments event, the user started your app by
double-clicking its documents.
kAEPrintDocuments is sent when the user selects your documents
and chooses "Print" in the Finder menu. If this is the first
AppleEvent you receive, you should print the documents and then
quit the application again; if you received a kAEOpenApplication
or kAEOpenDocuments event before this, you should just print the
documents and close them when you're done.
kAEQuitApplication is sent to you when the user chooses
"Shutdown" or "Restart" from the Apple Menu. You should ask the
user whether he wants to save any unsaved changed documents, and
then quit unless the user presses Cancel.
Interestingly enough, you can use these four AppleEvents to send
even to non-AE-aware applications, and the system will translate
these events into fake menu selections for you.
A good way of shutting down the Finder is to send it a Quit
AppleEvent. You should send a Quit AppleEvent to File Sharing
Extension before you shut down the Finder, though; the FSE is
found by looking for a process with the creator 'hhgg'.
4.3) Q: Are there any limits or tradeoffs with AppleEvents?
A: As always, more power means more responsibility.
AppleEvents sent to applications on other Macs require
authentification the first time they are sent. If the remote Mac
allows Guests to link to programs, the INIT AutoGuest 2.0 might
help (or the code solution that comes with it and you can build
into your application)
In the first version of the AppleEvent manager, there was a
total 64K limit on the size of data and overhead. This limit has
been lifted with the version of the AppleEvent manager that
comes with AppleScript.
AppleEvents require a lot of memory copying and handle resizing
in their construction; this means that large AppleEvents may be
slow in construction, especially when compared to a pure PPC
Toolbox or ADSP/ASDSP link.
You should use your own application signature as event class for
AppleEvents you make up, in order not to collide with anybody
else. Other than that, you are free to make your own events for
your own needs, though supporting the required events and at
least a subset of the Core event suite will buy you a lot of
functinality from within AppleScript. Especially important are
the Get Current Selection and Set Current Selection events
(which are really Get/Set Data on the contents of the current
selection of the application)
The signature for your application SHOULD be registered with DTS
to avoid conflicts; this is done through e-mail to
DEVSUPPORT@AppleLink.Apple.Com and the form you use is located
on the developer CDs and found on ftp.apple.com.
*5* AppleScript
5.1) Q: How does AppleEvents interface with AppleScript?
A: AppleEvents are the meat and potatoes of AppleScript. If you
support the AppleEvent Object Model from within your
application, users can control you through AppleScript.
The first thing you should do is get ahold of Inside Mac:
Interapplication Communication, and a copy of the AppleEvents
Registry. The former tells you all you ever need to know about
AppleEvents, while the latter is paramount for implementing the
right standard events. If everybody use the standard events,
dynamic data interchange between any applications will become
sweet reality!
Then there is the 'aete' resource which lets you put names on
the events you support, so that users can "Open Terminology" on
your application from within the Apple Script Editor and use the
proper AppleScript commands in their scripts. The format of an
aete resource is defined in Inside Macintosh: Interapplication
Communication.
5.2) Q: Can I compile and run scripts from within my
application?
A: Yes, this is very simple. There are toolbox calls for reading
scripts, compiling scripts, and executing scripts. (OSACompile,
OSAExecute) These are all documented in Inside Mac:
Interapplication Communication.
5.3) Q: Is this a good way of getting a macro language almost
for free?
A: "Good" is an understatement. Just let users write scripts,
load them into menu items and go. Total systems integration in
under a week, including adding support for the AEOM to your
application.
There is source code for an application called "MenuScipter" on
the developer CD which shows you how to do an application with
all of the menus being AppleScript scripts.
*6* Drawing using QuickDraw
6.1) Q: Why is CopyBits so slow?
A: It is not. It just requires some hand-holding to get good
results. The main rules are: Make sure the source and
destination pixMaps are of the same depth.
Make sure the front color is black and the back color is white.
Use srcCopy and don't use a masking region.
Copy to an unclipped window (the frontmost window).
Make sure the ctSeed values of the source pixMap and dest pixMap
match.
Copying few and large pixMaps is faster than copying many and
small ones. Icon-sized sprites count as small ones.
Make sure your source bitmap or pixelMap has the same alignment,
when adjusted for the source and destination rect expressed in
global screen coordinates. The necessary alignment is 32 bits (4
bytes), although 128 bit (16 byte) alignment is probably even
better on 68040 macs and won't hurt on other macs.
Example of global alignment:
Your window is positioned at (42,100) (H,V)
Your destination rectangle is (10,20)-(74,52)
The alignment coefficient of the rectangle in global coordinates
is (42+10)*bitDepth where bitDepth is one of 1,2,4,8,16 or 32.
Make sure your source pixmap rect has the same coeffecient
modulo your alignment factor (in bits) For black&white macs,
this is still true, although bitDepth is fix at 1. Offscreen
pixMaps can calculate with a "global posistion" of 0,0 and get
correct results.
6.2) Q: Why is CopyBits still too slow?
A: Because there is always some overhead involved in calling
QuickDraw; you have the trap dispatcher, clipping checks, and
checking whether the CopyBits call is being recorded in a PICT
handle (if you called OpenPicture)
If you can't live with this, look at *7* below, but PLEASE try
and make CopyBits work, and retain the CopyBits code in your
application, so users with special monitors (accellerator cards,
PowerBook color screens, Radius Pivot screens) can still play
your game. (non-game applications don't need more speed than
CopyBits can give at its max. Promise!)
6.3) Q: What is the fastest way to set one pixel?
A: NOT SetCPixel()! Assuming you have the correct ForeColor()
set, you can set the pen size to (1,0) and call Line (0,1)
I have heard PaintRect is good for this but requires slightly
more code. Using PaintRect eliminates a trap call.
6.4) Q: Why do pictures I record suddenly draw as empty space or
not draw at all?
A: When recording pictures, you have to set the clipping area to
exactly the frame of the picture you are recording. This is
because it is initally set at -32768,32727 in both directions,
and offsetting the picture even one pixel when drawing it will
result in the region wrapping around and becoming empty.
When recording pictures, do this:
*code*
PicHandle h = OpenPicture ( & theRect ) ; ClipRect ( & theRect ) ;
/* draw the picture */
ClosePicture ( ) ;
*end*
6.5) Q: Where can I find the format of picture files and
resources?
A: The format of a picture resource version 1 is defined in a
technical note. This format is obsolete.
The format of a picture resource version 2 is defined in Old
Inside Mac vol V, with addenda in Old Inside Mac vol VI.
Some things happen with QuickTime compressed pictures; try the
Inside Mac: QuickTime book or wait for Inside Mac: Imaging which
is the definite reference on QuickDraw.
The format of a picture file is the same as that of a picture
resource with 512 added 0 bytes in front.
6.6) Q: GWorlds?
A: What about them? They're great. Look them up in Old Inside
Mac vol VI. Don't forget to SetGWorld back to what it was before
calling WaitNextEvent.
6.7) Q: How do I find the current depth of the screen?
A: My question to you is: What screen? Many macs have more than
one screen attached. You can use GetDeviceList and walk the
devices to find the screen you're looking for (use
TestDeviceAttrib to see whether it's a screen) or you can call
GetMaxDevice() to find the deepest device your window
intersects.
Once you have the device handle, finding the depth is just a
matter of looking at the dgPMap pixMapHandle, and dereference it
to the pmSize field. Done.
*7* Drawing directly to screen
7.1) Q: Why is it a bad idea to draw directly to screen?
A: Because of several reasons:
- You will be incompatible with future display hardware.
- You will be incompatible with some present-day display
hardware, such as Radius Pivots and PowerBook color screens.
- You have to think about a lot of things; testing it all on
your own machine is not possible and the chances of crashing are
great.
- You will be incompatible with future hardware where devices
may live in some unaccessible I/O space.
7.2) Q: But I really need to do it. I can't make my animation
into a QuickTime movie, and CopyBits is too slow, even when
syncing to the screen retrace.
A: You have to prepare yourself, and ask these questions:
1) Do I want to support all screens, or just 8-bit devices?
2) Do I have a few weeks of free time to make it work?
3) Do I want to get nasty mail when I break on some hardware and
have to rev the application - even if I may not be able to get
ahold of the hardware that makes it break?
If all you're doing is rendering an image pixel-by-pixel or
line-by-line, maybe you can draw directly into an offscreen
pixMap/GWorld and then CopyBits the entire GWorld to screen?
That will be more compatible, especially if you use the
keepLocal flag when creating the GWorld.
7.3) Q: Okay, so how do I get the base address of the screen?
A: "The" screen? Which screen? There may be several. The base
address may be on an accellerated screen card. There may be more
than one screen covering the same desktop area.
Due to unfortunate circumstances, there is a bug in
GetPixBaseAddr() that causes it to return incorrect results for
some versions of System 7. Instead, get the baseAddr directly
from the gdPMap handle of the GDHandle for the screen you draw
to. This address may need switching to 32bit mode to be valid.
7.4) Q: Quit stalling and give me code!
A: Okay, but I'll let you sweat over Inside Mac to figure out
what it does. All of it is important; believe me! To make this
code run faster, a lot of the things it does can be done once
before starting to draw.
Make sure that you have a window that covers the area where you
are drawing, so other windows will not be overdrawn. Also make
sure that you do not do direct-to-screen-drawing while you are
in the background.
*code*
/* This is presently untested code */
/* value is dependent on what depth the screen has */
/* this code doesn't work on non-color-quickdraw Macs (i e the MacClassic) */
/* where is in GLOBAL coordinates */
void
SetPixel ( Point where , unsigned long value ) {
Rect r ;
GDHandle theGD ;
char * ptr ;
long rowBytes ;
short bitsPerPixel ;
PixMapHandle pmh ;
Boolean oldMode ;
r . left = where . h ;
r . top = where . v ;
r . right = r . left + 1 ;
r . bottom = r . top + 1 ;
theGD = GetMaxDevice ( & r ) ;
if ( theGD ) {
where . v -= ( * theGD ) -> gdRect . left ; where . h -= ( * theGD ) -> gdRect . top ; pmh = ( * theGD ) -> gdPMap ;
rowBytes = ( ( * pmh ) -> rowBytes ) & 0x3fff ; ptr = ( char * ) ( * pmh ) -> baseAddr ; bitsPerPixel = ( * pmh ) -> pixelSize ; oldMode = true32b ;
ptr += where . v * rowBytes ;
SwapMMUMode ( & oldMode ) ; switch ( bitsPerPixel ) { case 1 :
if ( value & 1 ) {
ptr [ where . h >> 3 ] |= ( 128 >> ( where . h & 7 ) ) ;
} else {
ptr [ where . h >> 3 ] &= ~( 128 >> ( where . h & 7 ) ) ;
}
break ;
case 2 :
ptr [ where . h >> 2 ] &= ( 192 >> 2 * ( where . h & 3 ) ) ;
ptr [ where . h >> 2 ] |= ( value & 3 ) << 2 * ( 3 - ( where . h & 3 ) ) ; break ;
case 4 :
ptr [ where . h >> 1 ] &= ( where . h & 1 ) ? 0xf : 0xf0 ;
ptr [ where . h >> 1 ] |= ( value & 15 ) << 4 * ( 1 - ( where . h & 1 ) ) ; break ;
case 8 :
ptr [ where . h ] = value ;
break ;
case 16 :
( ( unsigned short * ) ptr ) [ where . h ] = value ;
break ;
case 32 :
( ( unsigned long * ) ptr ) [ where . h ] = value ;
break ;
}
SwapMMUMode ( & oldMode ) ;
}
}
*end*
*8* Cache issues and other processor differences
8.1) Q: Why does my application work on an SE with accellerator
(or a Mac II or Quadra), but not on one without?
A: Assuming you're not calling Color QuickDraw (which is not
available on accellerated SEs), you most probably have an
odd-aligned word access somewhere.
The 68000 does not allow words or longwords to be read from odd
addresses, while the 68020 and up relaxes this restriction (it
still is slower than aligned-word access though)
This may or may not crash depending on your compiler:
*code*
struct foo {
char c1 ;
char c2 ;
char c3 ;
char c4 ;
char c5 ;
} bar ;
long * x = ( long * ) & bar . c2 ;
* x = 0x12345678 ; /* X is odd if compiler doesn't pad */
This WILL crash on an SE/Plus/Classic/PB100:
char foo [ 10 ] ;
long * x = ( long * ) & foo [ 1 ] ;
* x = 0x12345678 ;
*end*
8.2) Q: Why does my application work on a IIci but not on a
Quadra?
A: Two reasons:
1) The Quadras 900 and 950 have special processors that handle
the serial ports; if you write directly to the serial chips, you
will crash (this goes for the IIfx as well)
2) The Quadras have 68040 processors, as have the Centrises.
These processors have separate instruction and data caches (like
the 68030) but they are larger (4K each) and unlike the 68030
which is write-through data cached, the 68040 is copy-back data
cached. This means that changes you make to "your code" aren't
really changed all the time, since the changes may still be in
the data cache and not written to memory when the CPU reads that
part of memory into its I-cache. Even worse; that part might
already have been read into the I-cache before you change it in
the D-cache, meaning that writing out the D-cache will still not
be enough. You need to flush both the caches when writing
self-modifying code.
Self-modifying code includes code that builds its own jump
tables and code that decrypts itself and code that "stubs" MDEFs
or WDEFs to jump back into the application code.
You flush the cache using FlushDataCache() which is implemented
if Gestalt says you have a 68020 or better processor (or if the
_HwDispatch trap is implemented)
8.3) Q: Why does my application work on my Quadra but not on my
accellerated SE?
A: You're probably calling Color QuickDraw without first
checking if it's available. The following machines do not have
color QuickDraw in ROM nor RAM:
Mac Plus, Mac SE, Mac Classic, Mac Luggable, PowerBook 100,
Outbound
8.4) Q: I do check for color quickdraw, but crash nevertheless.
A: _Gestalt lies under some versions of System 7; it says that
non-color machines HAVE color QuickDraw when you test using the
gestaltQuickdrawFeatures selector.
Instead, check the gestaltQuickdrawVersion selector, if it
returns >= gestalt8BitQuickdraw then you can safely use
gestaltQuickdrawFeatures, else you only have b/w QuickDraw.
8.5) Q: Why are there no compilers that optimize for the
Mc68040?
A: Beats me; optimizing for the 68040 can make programs up to
50% faster on that chip while still losing nothing, or very
little (less than 10%) on older chips.
*9* Inflammatory subjects
9.1) Q: What about pre-emptive multitasking?
A: To the user, the Mac multitasking method, which builds upon
each application calling WaitNextEvent, GetNextEvent or
EventAvail every so often and the Process Manager/MultiFinder
switching applications only at such calls, is at least as good
as preemtive multitasking, because the present system
priotitizes user interface responsiveness over everything else.
The only shortfall about this is formatting floppies, which
locks up the Mac CPU. This is because the Mac floppy controller
is really stupid, and would happen even if the Mac multitasked
preemptively.
There IS "real" pre-emptive multitasking available for use in
Mac applications; the expensive way is buying A/UX 3.0 which can
have Mac applications written as UNIX processes; the cheap way
is installing the Thread Manager which will allow you to create
pre-emptive threads. However, the restrictions on those threads
are the same as those on Time Manager tasks: don't call any
function in an unloaded segment, and don't call QuickDraw or any
toolbox call which may move memory (which are most ToolBox
calls; paradoxally, BlockMove is safe :-) as are, surprisingly,
FSRead and FSWrite)
There are several problems with making the Mac OS preemptive;
including apps that draw outside their windows or directly to
screen, user dragging and other issues.
9.2) Q: What about protected memory? I'm sick and tired of
re-booting when my application crashes.
A: Write better software!
Or install The Debugger from Jasik Designs, which can provide
your application with write-protection of critical parts of
memory. This may only work for 030 Macs, though.
Making the Mac OS memory-protected is tricky, because
applications expect to be able to write to low memory, the
system heap, temporary memory, window lists, and even each
other's heaps in some interapplication communication solutions
that date back to before AppleEvents and the PPC Toolbox.
*10* Handles; they are driving me crazy
10.1) Q: What is a handle?
A: A handle is a pointer to a pointer to something. However, it
is more than that; creating a handle by taking the address of
one of your own pointers does NOT create a Handle; the Memory
Manager will only deal properly with Handles that are created
using NewHandle or something that calls it (such as NewRgn or
GetResource)
10.2) Q: When do I have to lock a Handle?
A: The contents of a Handle may move, and when it does, the
pointer your handle is pointing to is changed to point to the
new address so your handle is always valid. The toolbox may call
the memory manager to allocate more memory pretty much anytime
you call it (the toolbox) and when memory is allocated, your
handle may move in memory. Don't dereference a handle into a
pointer (or take the address of a field in a record a handle is
double-pointing to) and then call the toolbox and expect the
pointer to still be valid. The only way to ensure that the
pointer will still be valid is to call HLock on the handle to
lock it.
Use HGetState and HSetState to save & restore the "locked" state
of a handle when you lock it.
10.3) Q: How do I dispose of Handles?
A: DisposeHandle (formerly called DisposHandle) once and ONLY
once will do the trick. Trying to dispose of an already disposed
Handle is an error. DoubleTrouble (see above) will catch such
bugs when they do occur.
10.4) Q: What about resources?
A: Calling GetResource returns NULL if the resource is not found
or there is not enough memory, else it returns a handle to the
resource. This handle may be moved or locked like any other
handle, but DO NOT call DisposeHandle to get rid of a resource
handle - call ReleaseResource. DisposeResource (see above) will
catch this kind of bug.
Remember that AddResource makes a resource handle out of an
ordinary handle, and RmveResource or DetachResource makes an
ordinary handle out of a resource handle. You cannot call
AddResource with a resource handle; you have to DetachResource
it first.
Resource handles are automagically disposed when the resource
file they belong to is closed.
10.5) Q: I'm trying to use a largish array in Think C, but get a
"code overflow" error. This is valid C, why doesn't it work?
A: The ANSI standard does not guarantee that any structure
larger than 32767 bytes be correctly handled. Because of
historical constraints, the Mac memory model is built around
several small blocks of size 32K or less; these are used both
for code and global/static data. If you want to use more code or
data, you have to turn on "far code" or "far data" - you still
will not get around the restriction of 32K code or data per
compiled file, though.
As opposed to, say, DOS or Windows, however, you can allocate as
much memory as you want (and there is in the machine) and step
through it using ordinary pointers; it's just that global and
static data space is addressed off the A5 register using a 16bit
displacement addressing mode in the 68000 processor.
*11* _Gestalt and compatibility
11.1) Q: I see all these people call Gestalt without first
checking whether it's implemented. Isn't that bad?
A: No; Gestalt and a few other traps (the HXxx file manager
traps, and FindFolder) are implemented using glue so they do the
right thing even if the trap is not implemented.
If you want to get rid of the glue, you can #define
SystemSevenOrLater (and, using Think C/C++, re-pre-compile
MacHeaders) However, then you will be responsible for checking
for these features before you use them.
11.2) Q: What more functions are implemented in glue?
A: Wake Up and Smell the Glue! [by Matthias Neeracher]
How often have you wished you could use that cool new ToolBox
call, but didn't want to make your application System 7
dependent? Well, it might be that you *could* in fact have used
the call. Several traps are implemented in glue, that is, much
of their functionality is linked into your application and thus
available even if you are running under an old System.
This list applies to MPW 3.2 and should also be valid for the
current version of Think C. If you find any inaccuracies, please
report them to me. (neeri@iis.ee.ethz.ch)
FSOpen: Tries first OpenDF, then Open.
HOpenResFile: Full functionality emulated if trap not available
HCreateResFile: Full functionality emulated if trap not
available
FindFolder: Under System 6, understands the following values for
folderType and returns the System Folder for all of them:
kAppleMenuFolderType
kControlPanelFolderType
kExtensionFolderType
kPreferencesFolderType
kPrintMonitorDocsFolderType
kStartupFolderType
kSystemFolderType
kTemporaryFolderType
SysEnvirons: Full functionality emulated if trap not available
NewGestalt: Returns an error if not implemented
ReplaceGestalt: Returns an error if not implemented
Gestalt: The following selectors are always implemented:
vers mach sysv proc fpu
qd kbd atlk ram lram
11.3) Q: I have to support System 6, don't I?
A: It would be foolish to lock yourself out of the many benefits
the System 7 API provides for software that you start to write
now. Some of the System 6 and older things (likely SFGetFile and
wdRefNums among others) will be phased out of the interfaces and
lose support; especially on future platforms.
The installed base of System 7 is larger than that of System 6;
this is not surprising because Apple has been shipping System 7
for several years with all new machines, including the LCII,
Classic II, Performas and Color Classic. Another argument is
that newer computer owners (having System 7) are much more
likely to buy new software than old computer owners who have
systems that already do what they want them to.
The added work to support both System 6 and System 7 is
significant; if you have the time and money you may want to do
it, but only supporting System 6 and not System 7 is doomed to
fail in the market of today.
Some may call this position subjective; I call it business sense
based on market demographics. A rule of thumb may be that if you
target color machines only, you can just as well demand System 7
as well.
*12* Standalone code and dynamic linking
12.1) Q: I've got a CODE resource off in limboland (sometimes
called the resource fork) and I want to open it... what do I do?
A: You open the file you have the code resource in, load the
resource and lock it high (don't unlock it first, since someone
else may be using it). Then you cast the handle to a function
pointer, and call it normally.
Suppose your code resource is compiled as a SACD id 128, and is
defined as:
*code*
long
main ( MyParams * params ) {
switch ( params -> message ) {
case messageInit :
return init ( params ) ;
...
}
return 0L ;
}
*end*
Also suppose you already have the vRefNum, parID and name of the
resource file you want to use. Do this:
*code*
setup_paramblock ( & the_params ) ;
the_params . message = messageInit ;
refNum = HOpenResFile ( vRefNum , parID , name , fsRdPerm ) ;
if ( refNum < 1 ) {
fail ( ResError ( ) ) ;
}
the_code = GetResource ( 'SACD' , 128 ) ;
HLockHi ( the_code ) ;
retval = ( * ( ( long ( * ) ( MyParams * ) ) * the_code ) ) ( & the_params ) ;
...
*end*
Exactly how you structure your calling conventions is up to you;
there is no accepted standard (except for HyperCard XCMDs, but
that is probably overkill for you).
*13*
13.1) Q: How do I read the modifier keys of the keyboard?
A: Just call EventAvail and check the event.modifiers field.
Only works when you are in the foreground. You can also use
GetKeys(), or (as a last resort) check the lo-mem global KeyMap
directly.
*14* QuickTime
14.1) Q: I want to write a Amiga QuickTime player and need the
CODEC format details.
A: Although the structure of QuickTime movies is well documented
in Inside Mac: QuickTime, the inner workings of the Apple
compression modules is a trade secret that Apple will only
license to you at great cost. Perhaps it's time for a freeware,
cross-platform QuickTime codec?
*15* Ice Cream and Frozen Yoghurt
15.1) Q: Dessert?
A: Honey Hill Farms Cookie Jar Frozen Yoghurt or Haagen-Dazs
Raspberry & Cream Ice Cream.
Hokey-Pokey icecream with chocolate sauce and (for those who
like their brain food firmer) Armond and Double Chocolate
CookieTime cookies!? [Denis Birnie]
--
-- Jon W{tte, h+@nada.kth.se, Mac Hacker Deluxe --
"From now on I will re-label the EQ on the deck as Fizz and Wobble
instead of HF and LF."