moqingsong
论坛版主
论坛版主
  • 注册日期2002-04-07
  • 最后登录2011-02-03
  • 粉丝0
  • 关注0
  • 积分74分
  • 威望71点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
阅读:5866回复:0

The Mac Programming FAQ Answer sheet

楼主#
更多 发布于:2003-01-27 12:58
The Mac Programming FAQ Answer sheet. [READ ME!]

--------------------------------------------------------------------------------

Subject: The Mac Programming FAQ Answer sheet. [READ ME!]
From: d88-jwa@hemul.nada.kth.se (Jon W砒te)
Date: 5 Jul 1995 02:19:16 GMT
Newsgroups: comp.sys.mac.programmer.misc, comp.sys.mac.programmer.info, comp.answers, news.answers

--------------------------------------------------------------------------------

Archive-name: macintosh/programming-faq

Mac Programming Frequently Asked Questions Answer Sheet
Last update: 10 May 95 - sharp dressed FAQ

Please download a copy of this answer sheet and search it before you
post to the \'net, to help reduce bandwidth.

Please send all correspondence regarding content directly to the current
caretaker and content editor, Chris Thomas, <thunderone@delphi.com>.  
All submissions sent will be considered to be in the public domain
unless stated otherwise (in which case they will not be included in this
FAQ sheet).  When writing, be sure that you include something
appropriate in the subject line.  I\'m now automatically deleting mail
with blank or whitespace subjects unread due to the growing nasty
practice of sending junk email without a subject.  The idea, apparently,
is to be cute and get you to read the mail without deleting it.  This
sheet was started and is distributed by Jon Watte, whom you may reach as
<h+@austin.metrowerks.com>.

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-faq/CSMP_PD_FAQ
or using anonymous FTP as pub/hacks/mac-faq/CSMP_PD_FAQ You can also
find it on rtfm.mit.edu unedr the name macintosh/programming-faq.  WWW
version is available as <http://www.nada.kth.se/~d88-jwa/mac-faq.html>.

No FAQ can substitute for real documentation (some of which is
mentioned in this FAQ) If you ask a question in comp.sys.mac.programmer
which has a good answer in one of the important sources, you will probably
not get an answer.  (Inside Macintosh, Macintosh Technical Notes being
important sources).

There is NO or VERY LIMITED error checking in the 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.  
Needless to say, do not use the code as is.

Exciting new stuff:  More general dev tools update.  See especially
question 1.2.  List Manager replacements.  The usual tweaking.

Topics:
[search for *number* to find a topic quickly]
[topics changed since last FAQ are marked with \"+\", new topics with \">\"]

 1. +Development Tools
     getting started, tool-specific issues
 2. Memory
     handles, large arrays, resource handles
 3. User Interfacing
     menus, windows, events, multitasking
 4. Files
     Mac fopen, wdrefnums, getting full pathnames
 5. Imaging
     QuickDraw and the means to avoid it
 6. Text
     Text editing packages, string conversion
 7. Communications and Networking
     Serial ports, TCP/IP, sockets
 8. Interapplication Communication
     AppleEvents, OSA, Scripting, and You
 9. Dynamic Linking & Code Resources
     the dynamics of code resources & trap patches
10. Compatibility
     gestalt & glue
11. Optional System Software
   11.1. QuickTime
       codec details and the lack thereof
12. Third-Party Solutions
   12.1. Databases
       client/server solutions for the masses
   12.2. >Circumventing Toolbox Limitations
       foul baggage begone- List Manager replacements
13. Dessert
     yummies the Macintosh Way
14. Contributors
     whodunnit

*1* Development and debugging tools for the Macintosh

1.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 is a must; remember that your
time costs your employer much more than just your salary.  A PowerMac is
highly preferable.  16 MB is a minimum to run at all comfortably (40 MB
recommended), and Virtual Memory (including RamDoubler, unfortunately)
is not suited for development work.  Similarly, if you don\'t have at
least 80 MB free on your hard disk you need to buy more space.  You will
also need a CD-ROM drive.

You need a development system such as CodeWarrior, MPW Pro, Symantec C++
8.0 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; Apple\'s own CD600 is a very good buy at the time of this
writing.  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 most Inside Mac
documentation.  Another good product to order is the MacOS SDK, which
for $99 gives you a CD with every API in existence up to and including
the 7.5 Mac Toolbox additions.  It\'s somewhat redundant if you already
have the Developer CD subscription.  <apda@appplelink.apple.com> Apple\'s
Developer Web has almost all of the contents of the Developer CD online.  
<http://www.info.apple.com/dev>

If you don\'t know how to program, go learn your language of choice
BEFORE attempting a \"real\" Mac application.  Programming is a discipline
often requiring different thought processes than your normal day job.  A
beginning book, like Lippman: The C++ Primer, one of the Teach Yourself
C++ books, or the primers available on the CodeWarrior CD, might help.

An indispensable Mac programming tool is the Macintosh Programmer\'s
Toolbox Reference (MPTA), an up-to-date hypertext reference guide
containing reference material on the New Inside Mac-documented portions
of the Toolbox with lightning-fast look-up and mostly correct usage
hints and code snippets.  MPTA can be found on the Developer CD, and is
also offered on a seperate $99 CD.  <apda@applelink.apple.com>

Think Reference version 2.0.1, precursor to MPTA, contains reference
material on many parts of the Mac toolbox with lightning-fast look-up
and mostly correct usage hints and code snippets.  While it does not
cover any post-System 7 system additions, nor the modern \"universal\"
headers format, it does include information on the standard C/C++
libraries.  Available wherever fine Symantec products are sold -
<apda@applelink.apple.com> for one.

1.2) Q: What is the most used Macintosh development system?

A: Currently, the three most widely used are CodeWarrior (CW), MPW, and
Symantec C++, probably in that order, though I don\'t have any
statistics.  The latest version of any one of these is adequate for Mac
development.

CodeWarrior: In early 1994, CodeWarrior came out of nowhere and grabbed
a large share of the market visibility because they had the fastest
compiler and they generated PowerPC code as well as 68K code.  Today,
CodeWarrior has the smoothest development environment and most complete
C++ implementation, supporting both templates and exceptions.  CW/6
includes C, C++, and Object Pascal support, and can generate x86
binaries.  Among hobbyists, CW seems to be the most popular because of
it\'s low price, ultra-fast compile time, and support that no other
company on the planet can match.  See comp.sys.mac.programmer.codewarrior
for more information and CodeWarrior-related praise.  Contact
<sales@metrowerks.com>.

MPW: The grandaddy of all Mac development environments, descended from
the original Mac development environment based on a Lisa.  MPW is an
extremely flexible, powerful, Unix-like command line environment with
makefile, multiple windows and split-pane support.  Many development
tools are MPW-based.  MPW Pro comes with C, C++, Pascal, assemblers for
both 68k and PowerMac, various other useful tools, and the C++-based
framework MacApp for a reasonable price.  MPW has in the past been
extremely slow, but shows signs of redemption.  Contact
<apda@applelink.apple.com>.

Symantec C++: This is the eighth-generation descendant of the C
environment favored by Mac developers for over five years.  Symantec C++
8.0 is a complete, scriptable, modular development environment including
C, C++, and soon, a PowerPC assembler.  The C++ implementation supports
templates.  A development version of a PowerPC C++ compiler supporting
exceptions and RTTI is available at Symantec\'s devtools site.  SC++ 8.0
doesn\'t at this time support 68k Mac development.  For that purpose,
you\'re required to use the old, decrepit TPM development environment,
which is included.  Contact <sales@devtools.symantec.com>.

There are also at least two Fortran compilers, at least three SmallTalk
implementations (ObjectWorks, SmallTalk/V and SmallTalkAgents) and
others.  There are ways of stripping SmallTalk apps so they\'re smaller
and faster as standalone apps than in the environment.

Languge Systems has Object Pascal and Fortran for PowerMac.  Absoft has
Fortran and C++ for PowerMac.  These all require MPW.

There\'s also a world-class LISP/CLOS implementation from Apple called
Macintosh Common Lisp.  Recently, Apple announced that DigiTool has
licensed MCL with the intent (among other things) to provide a PowerMac
version and other updates.

Zedcor has FutureBasic, which seems to be a very popular...  It also
seems to be the only well-supported implementation of BASIC on
Macintosh.

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.

A new possible up-and-coming languge is Apple\'s Dylan, which is
something of a cross between BASIC, Pascal, and C.  C-based code can be
used directly from Dylan, but Dylan can\'t yet be used directly from C.  
The Apple Dylan environment is rumored to be as far beyond MPW as MPW is
beyond thick bundles of FORTRAN punch cards.

1.3) Q: Okay, which is the most used Mac programming languge?

A: The existing Macintosh code base is mostly C, with C++ second, and
Pascal finding it\'s niche in third.  Few people are writing mainstream
software in Pascal anymore, probably because (a) it\'s rather hard to
move to non-Mac platforms (b) Pascal is only rarely being taught past
the first year in Computer Science.

1.4) Q: Where do I find a free/share/copyleftware 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 on nic.switch.ch:software/mac/src/think_c.  

gcc-1.37r14 V1.1 standalone is available for ftp at nic.switch.ch:
software/mac/src/think_c.

A not-entirely-stable port of GCC 2.3.3 to MPW is available for ftp at
atg.apple.com [anyone know the directory?].  A much more solid port of
GCC 1.37 is available for MPW as well.

Stan Shebs <shebs@cygnus.com>, the driving force behind all of the MPW
GCC ports, is working on a new port of GCC 2.5.8.

For those whose main interest is in developing only text-based C/C++
programs, using GCC under MacMiNT might be appropriate.  MacMiNT is a
UNIX like operating system ported from the Atari ST which supports many
freely available UNIX utilities like GCC, GDB, make, tcsh, byacc, perl,
and more.  MacMiNT stuff can be found at nic.switch.ch in
\'software/mac/src/macmint\'.

The FSF/LPF boycott of Apple products is over as of January 1995, which
means they will now incorporate changes made for Macintosh into their
main code base, if such changes are easily incorporated, and they
won\'t be any more antagonistic to Mac programmers than they would be
to any other micro-to-workstation-class programmers.

So what are you waiting for? Go out and port something from GNU! Send in
the changes!  We still lack decent free development tools!

1.5) Q: Are there any other free Mac development platforms?

A: The best source for information on free compilers/interpreters is the
Free Compilers FAQ which is written by Brian Connors
<connorbd@cleo.bc.edu>.  Watch for it in c.s.m.p.info.

1.6) Q: What\'s the difference between the MPW, Think and CodeWarrior
environments?

A: As of CodeWarrior/6, MPW 3.3, and Symantec C++ 8.0.1 (SC++),
CodeWarrior will allow faster turnaround times, MPW will provide the
most flexibility and overall power, and Symantec C++ has the edge with
regard to helpful project browsing features.

CW C++ supports templates and exceptions, Symantec C++ supports only
templates, MPW\'s new compilers are based on Symantec C++.

SC++ 8 doesn\'t generate 68k code, while pre-CW/6 CodeWarrior requires
you to use seperate (virtually identical) environments, and builds are
controlled from a Makefile in MPW, of course.

All three need much hard disk space.  SC++ requires the most RAM.  MPW
requires the most disk space.

MPW is the slowest, followed distantly by SC++, which is followed
closely by CodeWarrior.

The best thing about MPW is that you can write scripts and make files to
do anything you want in the way you want it.  SC++ and CodeWarrior can
be AppleScripted to do builds that require more than one link operation,
but the process is more involved, and CW doesn\'t currently support
scripting in full.  SC++ 8 can do builds which require more than one
link operation.

For the MPW and CodeWarrior environments, there are four source level
debuggers; Metrowerks, SADE, SourceBug, 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).  Metrowerks Debugger is
included with CodeWarrior.

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).

Metrowerks has their own debugger which works like the MPW debuggers; i e
it runs the application standalone and pokes at it from the outside,
while the Think debuggers run the application \"wrapped\" in a special
environment, making for some subtle interferences with your heap (which
you usually don\'t notice).  The Metrowerks Debugger is Thread
Manager-savvy on the 68k side.

BOTTOM LINE:

If you\'re developing for both Power and regular 68k Macs, you need
CodeWarrior.  MPW is an option which makes sense if you need to develop
code for non-CFM OpenTransport or if you have a ridiculously large
number of independent code modules to compile, or if you\'re a Unix
person.  CodeWarrior, in addition to it\'s own integrated environment,
includes the non-compiler parts of MPW and MPW-hosted Metrowerks
compilers/linkers.  SC++ is an option only for PowerMac development.

1.7) Q: What is a good low-level debugger for the Mac?

A: MacsBug is freely available for ftp from <ftp://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.  As of 6.5d10, Macsbug supports PowerPC debugging.

Jasik Designs has 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.  
The Debugger is PowerMac native and supports PowerPC disassembly.  It
includes an excellent code coverage tool and MacNosy, a general
disassembler.  Support is direct from the author and generally great.
<macnosy@jasik.com>

1.8) 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.  A demo is available on the CodeWarrior
CD.  Think C++ comes with a browser built-in, and you can edit
dialogs/windows using plain old ResEdit, even for your custom view types.

Symantec C++ 7.0 also bundles a view editor/code generator called Visual
Architect; it is fairly complete and has a good level of integration
into the Think Project Manager.

AppMaker is a GUI builder/code generator.  Granted, it\'s not as nice as
VC++, but it\'s quite a product in any case.

MarksMan version 3.0 has totally revised TCL templates, and now
generates well-thought-out TCL code.  It can also generate ANSI C code
etc.

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 is the premier
cross-platform application builder framework; with everything from
styled text to network support.

There is a fully visual, dynamic, object oriented data-flow-driven
programming language for the Mac called Prograph CPX.  It features a
full-featured class library, a powerful, user-extensible GUI Builder, full
access to the entire Mac toolbox, a database engine, high-level interfaces
to SQL, Oracle, etc.  But the coolest thing about Prograph is its
interpretative debugger, fully integrated with the visual code editor,
which lets you write your code _while it\'s running_.  Execution
automatically rolls back to where changes you make have relevance.  A
PowerMac-native compiler and a Windows version are expected in \'95.  A
complete demo version is available from <sales@prograph.com>.  Cost is
$695 ($395 for students).

SmalltalkAgents comes with a GUI builder, which lets you draw your
interface, and then outputs the code for you.

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.

1.9) Q: What class libraries are there for the Mac?

A: Apart from the libraries mentioned above, there are three contenders:
MacApp, TCL, and PowerPlant.  \"Bedrock\" will never be released as a
product, although parts of it surface in TCL 2.0 and other parts will be
the base for the OpenDoc Parts Framework.

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.  (TCL
1.1.3) Starting with Symantec C++ 7.0, Think Class Library 2.0 using
templates and \"real\" C++ objects is shipping.

The C++ Standard Template Library (STL) compiles under Symantec C++
and CodeWarrior, and versions are available for both.

PowerPlant is the Metrowerks CodeWarrior offering; it\'s written by the
guy who designed the Think Class Library, but it has a lot of
differences from the original TCL; for one, it\'s not a monolithic one
base class framework.  On the other hand, it has some catching up to do
before it reaches the level of MacApp.  It is gaining quite fast on TCL,
but isn\'t all there yet.  It has the most complete support for
AppleEvents & scripting & drag & drop other modern features.

1.10) 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.  (Jasik\'s Debugger (see above) obviates the need
for these.)

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.11) Q: Are there any good Mac programming magazines?

A: One Mac programming magazine I know of is MacTech Magazine (formerly
MacTutor).  It covers a variety of Mac programming topics on various
levels.  Operating independently from Apple, it has a lot of stuff for
the beginning Mac programmer, as well as occasional nuggets for the more
experienced of us.  <custservice@xplain.com>

Another VERY GOOD Magazine is _develop_ which is put out by Apple four
times a year; it comes with a CD containing code for all articles ever
published in _develop_, and a lot of documentation and system software
freebies as well.  $30/year in the US.  <dev.subs@applelink.apple.com>

1.12) 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, if you have
a 68030-equipped Mac.

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.  To add to the burden, Apple\'s own software tends to be the
worst offender in these cases.

But fear not, Mac fans! Jonathan Kimmitt has written Patmos, the
\"Protected address translation mode operating system\".  It is an
application that brings the advantages of protected mode programs to
your Quadra class Macintosh by the simple expedient of taking over the
memory management unit of the 68040 in a very simple kernel (<100K in
size), we immediately gain compatibility with the BSD unix program
environment.  The advantages of this are as follows:

(a) You can run certain programs (such as /bin/sh) designed for MacBSD
(b) You can compile almost all GNU software including C and C++ without.
modifying the source code in any way
(c) All programs run with a flat 32-meg address space, with no worries
about 32K segments or the other mac paraphernalia.
(d) The majority of program bugs can be caught cleanly without crashing
 your mac
(e) All your files are shared between Patmos and MacOS so you can edit
using your favourite mac editor, then immediately compile in Patmos
without having to reboot or copy files around.

The downside is that not all macs use the memory management unit in the
same way, or even have the same kind of MMU, so Patmos may not run on
your particular mac model.  However, since the kernel source code is
very small, the task of adapting it to a new environment is very simple,
and once achieved, all application programs running in user mode are
enabled to run without even recompiling.

<ftp://nic.switch.ch in /software/mac/src/patmos>

1.13) Q: I have this library written in (Think) Pascal that I want to use
from Think C/Symantec C, but I get link errors/don\'t know how to do it.  
What should I do?

A: Start by writing a .h file describing the interface.  Remember to
declare the Pascal functions \"pascal\".  Build a library with Think Pascal
and convert it with oConv.

Do you get link errors on symbols defined in your Pascal lib? Check the
capitalisation used.

Do you get errors on symbols like LMUL and LDIV? Those functions are
defined in the Think Pascal library Runtime.lib or uRuntime.lib.  Include
uRuntime.lib and try again.

Do you get link errors on standard symbols like thePort? This is due to
bad capitalization in Symantec\'s libs.  Run oConv with .v checked.  This
will create a TEXT file with a .v extension.  Open that with a text
editor and correct the capitalization.  Run oConv again, with .v checked
this time too.

Do you still get errors on standard symbols? Are you using Think
C/Symantec C++ version 6 or higher? Then you must open the library (after
converting it) from Think C version 5, and remove the unit named
%_TOOLBOX.  (If I\'m not mistaken, this is the toolbox init unit, which
you won\'t need anyway.)

1.14) Q: CodeWarrior vs. Think/Symantec C++:  Which is better?

A:  See the above discussion on CodeWarrior, Think, and MPW for a full
understanding of the issues involved.

1.15) Q: Can CodeWarrior read Think libraries?

A: Yes, in a way.  Here are the steps required.

1) Secure a copy of Think Pascal and a machine that can run it
2) Import the Think C library into Think Pascal
3) Build a Think Pascal library (in MPW format)
4) Import MPW format library into CodeWarrior

1.16) Q: What are some good books on the subject of learning the Mac
Toolbox?

A: Any of Dan Parks Sydow\'s numerous books on the subject.  Recommended
also is Dave Mark\'s _Ultimate Mac Programming_ (a Macworld book, for
some odd reason).  Stay away from Dave Mark\'s _Learn C on the Mac_ and
_Learn C++ on the Mac_.

See also Nick DeMello\'s books review, posted in c.s.m.p.info from time
to time.

1.17) Q:  Source code!  I want source code!  Where can I find some?

A: Celestin Company, Inc. sells the Apprentice 2 CD-ROM.  Apprentice
contains over 600 megabytes of programmer utilities and up-to-date
source code in CodeWarrior, Symantec, and MPW projects for C, C++, and
Pascal.  <ftp://ftp.teleport.com/vendors/cci/apprentice/apprentice.hqx>
for an index and info.  <celestin@olympus.net>

Also, the alt.sources.mac archive at <ftp://ftpbio.bgsu.edu> contains a
lot of misc. source code and snippets not found elsewhere.

<ftp://nic.switch.ch> is another good source for unique source code.

Info-mac is a good source for source, info-mac/dev/src.

1.18) 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.

This is one area where CodeWarrior\'s 68k support shines; it works around
most such limitations and it doesn\'t cost much in performance either!

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.

On the PowerPC, everything is 32bit from the start; that runtime model
is much more like UNIX.  The horizon is the limit.

*2* Memory

2.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).

2.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.

2.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.

2.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 RemoveResource 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.

*3* User / Machine interaction

3.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.

3.2) Q: How do I move the mouse cursor to a specific position?

A: Wait! Don\'t do it! There has to be a better way!

If you feel you HAVE to do it (for a game or VERY special simulation
situation) you can use the Cursor Device Manager documented in the tech
notes on <ftp.apple.com>.  If that manager is not installed, as it\'s not
on older Macs, you can use the following code:

You need to have some low-memory globals defined.  they may be defined
in SysEqu.h.

#define MTemp 0x828
#define RawMouse 0x82c
#define CrsrNewCouple 0x8ce

Note that CrsrNewCouple is actually a combination of two globals, just
to make our life slightly easier.

The code I use to move the mouse is:

*code*
void
MoveMouseTo ( Point where ) {

    HideCursor ( ) ;
    * ( Point * ) RawMouse = where ;
    * ( Point * ) MTemp = where ;
    * ( short * ) CrsrNewCouple = -1 ;
    ShowCursor ( ) ;
}
*end*

You need to hit a couple more global variables if you want this to work
properly in a multiple-monitor system, but i forget what they are
offhand.  poke through SysEqu.h, and you should be able to figure it out
without a problem.

On the PowerPC, these lo-mem globals may not be available for native
applications; however, all Power Macintoshes implement the Cursor Device
Manager.  All Macs made after March \'93 (including Centris 650 and 610)
implement the Cursor Device Manager, in fact.

There is also a file on nada.kth.se:pub/hacks/mac-faq/MoveMouse.c which
shows how to use the Cursor Device Manager, written by an excellent
Apple engineer.  Grab!

Careful, version 1.0 of the Universal Header \"CursorDevices.h\" file was
completely incorrect.  Use 2.0a3 or later.

3.3) Q: My menus don\'t show up in the menu bar

A: If your menus are hiearchical, you\'ll have to install them manually;
GetNewMBar won\'t do it for you.  See also 3.5.

3.4) Q: When the user selects my menus, I get strange results back; they
seem to have different menu IDs than my menus?

A: The Menu ID as used by the menu manager is NOT the same thing as the
MENU resource ID (used in the MBAR resource and with GetMenu()) When you
create a MENU, ResEdit sets the menu ID to the MENU resource ID, but if
you re-number the resource, you will have to open the menu in ResEdit
and change the menu ID using the \"Edit MENU ID\" menu item.

3.5) Q: I use GetMenu() to find a menu in the menu bar, and then change
it, but it seems I have a memory leak OR my changes don\'t \"punch
through\"

A: GetMenu() is only intended if you don\'t already have the menu \"in
memory.\" The call you should use almost all the time is GetMHandle()
which gets the handle to a menu in the current menu bar by its menu ID
(not resource id).

3.6) 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).  The latest word from Apple is that this
preemptive support is going away, to be replaced by something else in
Copland.

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.  The system is being reimplemented for 8.0
(Copland) to solve these problems.

*4* Files

4.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 ( NULL, aVol , aDir ) ) {
        /* an error we can\'t currently handle */
    }
    if ( SetVol ( NULL, 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.

4.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.

4.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 weren\'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.\"

4.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.

4.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.

4.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.

4.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.  Note that
this sample code isn\'t all there, but should point you in the right
direction:

*code*
Boolean IsFolder(FSSpec *fs) // this function is called later
{
        CInfoPBRec rec;

        rec.hFileInfo.ioNamePtr = fs -> name;
        rec.hFileInfo.ioVRefNum = fs -> vRefNum;
        rec.hFileInfo.ioDirID = fs -> parID;


        if ( !fs -> name [ 0 ] )
        {
                rec . hFileInfo . ioFDirIndex = 0 ;
        } else
        {
                rec . hFileInfo . ioFDirIndex = -1 ;
        }

        rec . hFileInfo . ioFVersNum = 0 ;
        PBGetCatInfoSync (&rec);

        return(!rec.hFileInfo.ioFlAttrib & 0x10);
}
*end*

*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 ] )  // dougw -- neg of FAQ
    {
        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 ;
        }
    } else {
        parent -> parID = rec . dirInfo . ioDrParID ;
        BlockMove(rec.dirInfo.ioNamePtr, parent->name, rec.dirInfo.ioNamePtr[0]);
    }
    return err ;
}
*end*

*code*
OSErr GetFullPathHandle ( FSSpec * fss , Handle * h )
{
    Handle  tempH = NULL;
    FSSpec fs = * fss ;
    FSSpec sSpec;

    if(*h == NULL) // allocate a handle if needed
    {
        *h = NewHandle(0);
    }

    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 ;
    }
    
    // fs should now contain info about the volume itself
    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 ) ;
    }

    DisposeHandle(tempH);
    return 0 ;
}
*end*

4.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 preferably 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.

4.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.

4.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 = PBGetCatInfoSync ( & 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 ;
    rec . hFileInfo . ioNamePtr [ 0 ] = 0 ;
    err = PBSetCatInfoSync ( & rec ) ;
    return err ;
}
*end*

4.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)

4.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.

4.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 GetProcessInformation using the
ProcessSerialNumber kCurrentProcess 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.

*code*
OSErr   CurrentProcessLocation(FSSpec *applicationSpec)
{
    ProcessSerialNumber currentPSN;
    ProcessInfoRec info;
    
    currentPSN.highLongOfPSN = 0;
    currentPSN.lowLongOfPSN = kCurrentProcess;
    info.processInfoLength = sizeof(ProcessInfoRec);
    info.processName = NULL;
    info.processAppSpec = applicationSpec;
    return ( GetProcessInformation(&currentPSN, &info) );
}
*end*

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.

4.14) Q: When can I use those nifty, easy to use FSSpec calls?

A: In Systems >= 7, in System 6 with QuickTime installed, in any system
if you use the FSpCompat functions provided by MoreFiles [see below].

4.15) Q: I hate dealing with the low-level file manager stuff;  why
didn\'t Apple provide a complete high-level interface using FSSpecs?

A: Good question.  Apple, in the guise of Jim Luther of Mac Developer
Technical Support, has written a library called MoreFiles, which not
only provides a high-level interface to low-level file stuff, but
provides FSSpec glue for Systems below 7.  MoreFiles is available on the
Developer CD\'s (see above) and also at Appple\'s developer ftp site.

*5* Imaging with QuickDraw

5.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, unless it\'s rectangular.

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.

5.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 4.8 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!)

5.3) Q: What is the fastest way to set one pixel?

A: On 68k Macs, 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.

5.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*

5.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 turn to Inside Mac: Imaging with QuickDraw 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.

5.6) Q: GWorlds?

A: What about them?  They\'re great.  Look them up in IM: Imaging With
QuickDraw.  Don\'t forget to SetGWorld back to what it was before calling
WaitNextEvent.

5.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 TestDeviceAttribute 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 gdPMap pixMapHandle, and dereference it
to the pmSize field. Done.

5.8) 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.

5.9) 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 and with my source GWorld aligned properly.

A: You have to prepare yourself, and ask these questions:

- Do I want to support all screens, or just 8-bit devices?

- Do I have a few weeks of free time to make it work?

- 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.

5.10) 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
early 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.

5.11) 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 ;
        default :
            abort ( ) ; /* Should never get here */
        }
        SwapMMUMode ( & oldMode ) ;
    }
}
*end*

*6* Text
 
6.1) Q: How do I get TextEdit to display more than 32k of text?
 
A: You don\'t.  Truly, it\'s not worth it.  There\'s a call-for-call
TextEdit replacement called TE32k which does > 32k text, and is
available from any recent Info-Mac mirror.  It doesn\'t do styled text,
though.

6.2) Q: How do I get TextEdit to display more than 32k of __styled__
text *and* embedded objects in the text (such as pictures)?
 
WASTE, available at ftp://ghost.dsi.unimi.it/pub2/papers/piovanel, is a
vast improvement over TextEdit.  Version 1.0 does >32k styled text
retains compatibility with the TextEdit style scrap (which is used to
store styled text in files such as SimpleText\'s, as well as in the
clipboard), includes source code and is freeware.  Really worth the
download.  Version 1.1 adds embedded objects within the text, such as
pictures, intelligent cut-and-paste, built-in Drag Manager support,
built-in Undo support.  1.1 is currently in alpha, but seems to be very
stable.

\"But,\" you nervously stutter, \"WASTE is in Pascal!  And it\'s munged so
that it won\'t work as an imported library w/Metrowerks C!  What now?\"

Dan Crevier is maintaining a C port of WASTE, and the current version
along with other WASTE goodies is at <ftp://rhino.harvard.edu/pub/dan/>.

6.3) Q: I\'m too back-asswards to use WASTE 1.1.  How do I include
pictures in text using TextEdit?

A: There\'s no really easy way (such as a TEAddPict() call), and it will
be a nasty kludge if you do get it working, but if you can live with
that, here\'s how to do it.  I do recommend that you take a look at Q
6.2, above.
 
Write an algorithm to get the position of a special marker character
[Teach/SimpleText uses option-space] or text attribute that the user
will insert wherever he wants a picture.  Pass this position to a
function similar to the one below.

*code*
/*
    TEDrawPicture
    Draw a picture within TextEdit\'s text.
    
    input:
        pos - the position of the special character in the text where the user
                wants a picture.
        r   - size of picture
    
    output:
        r   - frame in which picture was drawn
*/
 
void TEDrawPicture(short pos,PicHandle pic,Rect &r,TEHandle theTE)
{
    Point   bottomLeft;  //I think TT/ST uses topleft
    
    bottomLeft = TEGetPoint(pos, theTE);
    
    r.right = bottomLeft.h + (r.right - r.left);
    r.top = bottomLeft.v - (r.bottom - r.top);
    r.left = bottomLeft.h;
    r.bottom = bottomLeft.v;
    
    DrawPicture(pic, &r);
}

*end*
 
I\'ll leave selection and hiliting as an exercise for the reader (don\'t
ya love it when people say that?).
 
Thereotically, it should be possible to kludge up TextEdit to the point
where it would treat pictures as if they were actually letters (rather big
letters, but letters just the same).  That\'s what the width and word break
hooks are for, after all.  However, this would be a lot of Work, and I\'ve
never seen it done.  One is lead to believe that it\'s less work to create
an improved version of TextEdit from the ground up with picture support.  
WASTE 1.1, in fact, does this rather nicely.

6.4) Q: I have all this money, and I want to get rid of it. How do I
edit more than 32k of styled text now?

A: There are at least three solutions.

1) The Galaxy application framework comes with a styled text editting
engine which does more than 32k of text. It also happens to support
cross-platform application development. Pricing starts at $10000.
<galaxy@visix.com>

2) DataPak is selling a cross-platform library called \"PAIGE\".  It is
written to be customizable to any extent, and you can do _anything_ in
it (want quicktime movies that play and flow with the text while
editting? Three pages of code; you can adapt their picture sample code.)
Available for Mac, Windows & Never Trusted and Power Mac.  Pricing at
$5000 ($25000 for source code) - it might be cheaper if you talk to
them.  Customer support is reputed to be \"lousy\".

3) Or you could use WASTE 1.1 with it\'s embedded objects implementation
(want quicktime movies that play and flow with the text while editing?
One page of code, if that much.)

6.5) Q: How do I convert from a string to a floating point type?

A: Once you\'ve got an Str255, you want to call the routine
StringToExtended to change the number into type extended80, which is the
80-bit floating point type.  The nice thing about StringToExtended is
that it even works in funky foreign language scripts like Chinese.  To
use the routine, you must pass it not only the Str255 that you want
converted, but also the results of the StringToFormatRec routine and the
GetIntlResourceTable routine.  The documentation is generally difficult,
so I\'ll describe the parameters and give you a code example below.  
Here\'s what you pass to StringToExtended:

- source:
Obviously the string representation of the number.

- myFormatRec:
This is simply the format that you expect the number to be.  For
example, if you wanted a positive integer with up to 3 decimal places,
you would want the format to be \"###\".  (The \"#\" symbol means a non-zero
filled digit, whereas a \"0\" would mean zero filled.) If you wanted an
floating point exponential notation with up to 2 digit integer portion,
exactly 2 digit decimal portion, and exactly 1 digit after the \"E\", your
format would be \"##.00E+0\".  (Actually, in Canada, you folks might use a
\",\" instead of a \".\" for the decimal point; if you do, then you would
put the locally correct symbol in there.) In a format string, you can
put the format for a positive value, a negative value, and 0 seperated
by semicolons (e.g.  \"##.00E+0;-##.00E+0;0.00E+0\").

But myFormatRec is not the format string itself, but is an internal
format that you get from calling StringToFormatRec.  This is so you can
store the format returned to you by StringToFormatRec and use it on
different international systems.  There is a nice editor for ResEdit for
\'FMAT\' resources that lets you type the format string and will call
StringToFormatRec for you and create an \'FMAT\' resource out of the
result.  Then you can load the \'FMAT\' at run time and pass it to
myFormatRec.

- partsTable:
The number parts table from the \'itl4\' resource.  If you are using
System 7 or later, you call GetIntlResourceTable, asking it for the
number parts table.  You don\'t need to worry about HLock\'ing itlHandle
because StringToExtended doesn\'t move memory; just don\'t do anything
between your call to GetIntlResourceTable and the StringToFormatRec
routine.  If you are using System 6, you need to perform the
GetI
按第一贴的“给分”键,给分。
游客

返回顶部