From: pottier@clipper.ens.fr (Francois Pottier)
Subject: csmp-digest-v3-056
Date: Sat, 10 Sep 1994 13:05:29 +0200 (MET DST)

C.S.M.P. Digest             Sat, 10 Sep 94       Volume 3 : Issue 56
 
Today's Topics:
 
        A tool I could REALLY use, written it?
        Async FileMgr Calls
        Future of ASLM
        Review of PowerMac devtools available
        SetDialogDefaultItem() not doing anything!
        Trouble making floating windows work with modeless dialogs



The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier
(pottier@clipper.ens.fr).
 
The digest is a collection of article threads from the internet newsgroup
comp.sys.mac.programmer.  It is designed for people who read c.s.m.p. semi-
regularly and want an archive of the discussions.  If you don't know what a
newsgroup is, you probably don't have access to it.  Ask your systems
administrator(s) for details.  If you don't have access to news, you may
still be able to post messages to the group by using a mail server like
anon.penet.fi (mail help@anon.penet.fi for more information).
 
Each issue of the digest contains one or more sets of articles (called
threads), with each set corresponding to a 'discussion' of a particular
subject.  The articles are not edited; all articles included in this digest
are in their original posted form (as received by our news server at
nef.ens.fr).  Article threads are not added to the digest until the last
article added to the thread is at least two weeks old (this is to ensure that
the thread is dead before adding it to the digest).  Article threads that
consist of only one message are generally not included in the digest.

The digest is officially distributed by two means, by email and ftp.

If you want to receive the digest by mail, send email to listserv@ens.fr
with no subject and one of the following commands as body:
    help		                Sends you a summary of commands
    subscribe csmp-digest Your Name	Adds you to the mailing list
    signoff csmp-digest			Removes you from the list
Once you have subscribed, you will automatically receive each new
issue as it is created.

The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest.
Questions related to the ftp site should be directed to
scott.silver@dartmouth.edu. Currently no previous volumes of the CSMP
digest are available there.

Also, the digests are available to WAIS users.  To search back issues
with WAIS, use comp.sys.mac.programmer.src. With Mosaic, use
http://www.wais.com/wais-dbs/comp.sys.mac.programmer.html.


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

>From Chris Russo <chris@sonicsys.com>
Subject: A tool I could REALLY use, written it?
Date: 24 Aug 1994 16:57:56 GMT
Organization: Sonic Systems, Inc.

While tracking down a nasty memory leak yesterday, I thought of something that
would have been REALLY helpful.  What if I patched NewHandle() so that
whenever it was called it would traipse over to the end of my routine and grab
the Debugger info, then tacked it onto the rear of the handle?

That way, I could look at all of those loose memory fragments from ZoneRanger
and determine instantly from where they had been allocated.

I started working on the thing yesterday, and spent a couple of hours on it.
I wrote patches for NewHandle(), GetHandleSize(), and SetHandleSize().  Those
last two would naturally have to be patched to make the debugging info
transparent to the calling application.

Unfortunately, the routines aren't quite working and tend to crash.  More
unfortunately, I don't have the time to keep working on them. :-(

If anyone's already written such a patch, <whoops> please let me know how it
went and if I could have it.

If anyone would like to take this idea and run with it, by all means do so. 
You can even have the source that I started.  There might be some issues
involving the application's trap dispatch table that I'm not dealing with
properly.  I've never really taken the time to learn that much about it, but
would be happy to learn where I went awry.

btw, I have seen the leaks dcmd and don't really like to use it much.  From
ZoneRanger, I can usually tell which memory blocks are useless, but it's hard
to correlate those to the ones captured in leaks.  On top of that, leaks
crashes my version of TMON.

Once again, if anyone wants to continue my effort, let me know.

- ------------------------------------------------------------------------
Chris Russo                      Macintosh Programmer
Sonic Systems, Inc.              (408) 736-1900 #107
chris@sonicsys.com               NEVER respond to flame bait!

+++++++++++++++++++++++++++

>From onyxtech@aol.com (OnyxTech)
Date: 26 Aug 1994 17:43:03 -0400
Organization: America Online, Inc. (1-800-827-6364)

In article <33fu6k$f5s@news.internex.net>, Chris Russo
<chris@sonicsys.com> writes:

>While tracking down a nasty memory leak yesterday, I thought of
>something that would have been REALLY helpful.  What if I patched
>NewHandle() so that whenever it was called it would traipse over to
>the end of my routine and grab the Debugger info, then tacked it onto
>the rear of the handle?
>That way, I could look at all of those loose memory fragments from
>ZoneRanger and determine instantly from where they had been allocated.

Mmmm.  There is a version of QC(tm) that has similar leaks detection (you
can use sym files as well) that will follow a native PowerPC upgrade ahead
of it in the pipeline.  We are working on graphical representation of heap
allocations and deletions and hope to create some sort of published
interface so tools like ZoneRanger can use our data to represent more
information to users.  After all, why should we re-create ZoneRanger type
utilities when they've already done all the work.  We just need to help
them get at more information.

If you'd like me to keep you (and whomever else is reading this) abreast
of this new version of QC, drop us a line at 'onyxtech@aol.com'.

dEVoN Hubbard
Onyx Technology

+++++++++++++++++++++++++++

>From h+@nada.kth.se (Jon W{tte)
Date: Sat, 27 Aug 1994 15:52:17 +0200
Organization: Royal Institute of Something or other

In article <33fu6k$f5s@news.internex.net>,
Chris Russo <chris@sonicsys.com> wrote:

>While tracking down a nasty memory leak yesterday, I thought of something that
>would have been REALLY helpful.  What if I patched NewHandle() so that
>whenever it was called it would traipse over to the end of my routine and grab
>the Debugger info, then tacked it onto the rear of the handle?
>
>That way, I could look at all of those loose memory fragments from ZoneRanger
>and determine instantly from where they had been allocated.

It's easier to just install the "leaks" MacsBug dcmd. I don't 
know whether it will still work with the new memroy manager 
though. Anyone else know?

Another thing you can do is to replace all your calls to 
NewHandle() etc with MyNewHandle() and have non-patches that 
did the tracking work; you could even define MyNewHandle to 
pass source file and line number information using __FILE__ and 
__LINE__. Then when you compile the release version, you just 
define MyNewHandle() to NewHandle().

This is great for validating memory as well; you can have a 
validation routine that traverses all of your dynamically 
allocated memory and checks it against a list you keep; if 
something's not checked on the list, you have a leak. If a 
pointer/handle is not on the list, you have a dangling 
pointer/handle.

Cheers,

				/ h+


--
  Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden
    Not speaking for IBM.


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

>From chris-b@cs.auckland.ac.nz (Chris Burns)
Subject: Async FileMgr Calls
Date: Sat, 20 Aug 1994 00:58:02 +1200
Organization: AucklandUniversity:ComputerScience:HMU

Hi All,

I've been looking into using async file manager calls, so I started
experimenting with an easy one, an indexed _PBHGetVInfoAsync call until
the error returned is nsvErr (no-such-volume: -35). This works perfectly
using sync calls. Things aren't so rosy on the async front tho'.

Being in a PowerPC friendly kind of mood (and running on a PM8100/80), I
thought "cool, I'll use UPPs for my completion routine specifiers, and
compile a fat app". This aspect is fine, and in fact, the PowerPC native
version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The
68K version however, does not work. The _PBHGetVInfoAsync call returns all
kinds of bogus values instead of nice file manager errors.

Here's the entire code:


////////////////////////////////////////////
// Chris Burns  ©August 1994
////////////////////////////////////////////

#include <Files.h>

////////////////////////////////////////////

typedef struct
{
    HVolumeParam    PB;
    Str255          VolName;
    long            AppA5;
}
VolPBRec,*VolPBPtr;

////////////////////////////////////////////

short           gNumDrives;
volatile short  gNumDrivesDone;

////////////////////////////////////////////

IOCompletionUPP     gCompletionProcUPP;

#if USES68KINLINES
#pragma parameter CompletionProc(__A0)
#endif

pascal void CompletionProc(HParmBlkPtr HPB)
{
long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5);

    gNumDrivesDone++;
    DebugStr(((VolPBPtr)HPB)->VolName);

    SetA5(SavedA5);
}

////////////////////////////////////////////

void main(void)
{
OSErr               Err;
VolPBPtr            VPB;

    gNumDrives = 0;
    gNumDrivesDone = 0;
    gCompletionProcUPP = NewIOCompletionProc(CompletionProc);

    Err = noErr;

    while (Err != nsvErr)
    {
        gNumDrives++;
    
        VPB = (VolPBPtr)NewPtrClear(sizeof(VolPBRec));
        if ((VPB == nil) || (MemError() != noErr))
            DebugStr("\pMain: _NewPtrClear(VPB) FAILED");
        
        VPB->PB.ioCompletion = gCompletionProcUPP;
        VPB->PB.ioVolIndex = gNumDrives;
        VPB->PB.ioNamePtr = VPB->VolName;
        VPB->PB.ioVRefNum = 0;
        VPB->AppA5 = SetCurrentA5();

        Err = PBHGetVInfoAsync((HParmBlkPtr)VPB);

        switch (Err)
        {
            case noErr:
                break;

            case nsvErr:
                continue;

            default:
                DebugStr("\p_PBHGetVInfoAsync FAILED");
                break;
        }
    }

    while (gNumDrivesDone != gNumDrives);

    DisposeRoutineDescriptor(gCompletionProcUPP);
}

////////////////////////////////////////////

The:

#if USES68KINLINES
#pragma parameter CompletionProc(__A0)
#endif

bit was necessary for the 68K version to realize the param block ptr was
in A0 rather than on the stack. I just grabbed it from one of the
Universal Headers because it looked right. It seems to work, and the asm
looks right.

The problem seems to be in my CompletionProc. Whatever value D0.w is upon
exit, comes out as the original Err = PBHGetVInfoAsync(); This shouldn't
be so because that error simply tells me if the request was queued ok. For
file manager completion routines THINK Ref 2.0 says "Save and restore all
CPU registers except A0,A1, and D0-D2". My code seems to do this yet
doesn't run correctly.

Here's the 68K asm:

Hunk:   Kind=HUNK_GLOBAL_CODE  Name="COMPLETIONPROC"(4)  Size=64
00000000: 4E56 FFF8          LINK      A6,#$FFF8
00000004: 2D48 FFF8          MOVE.L    A0,$FFF8(A6)
00000008: 206E FFF8          MOVEA.L   $FFF8(A6),A0
0000000C: 2028 017A          MOVE.L    $017A(A0),D0
00000010: C18D               EXG       D0,A5
00000012: 2D40 FFFC          MOVE.L    D0,$FFFC(A6)
00000016: 526D 0000          ADDQ.W    #$1,gNumDrivesDone
0000001A: 206E FFF8          MOVEA.L   $FFF8(A6),A0
0000001E: 4868 007A          PEA       $007A(A0)
00000022: ABFF               _DebugStr
00000024: 202E FFFC          MOVE.L    $FFFC(A6),D0
00000028: C18D               EXG       D0,A5
0000002A: 4E5E               UNLK      A6
0000002C: 4E75               RTS
0000002E: 8E43 4F4D 504C     DC.B      $80+$0E, 'COMPLETIONPROC', $00
          4554 494F 4E50 
          524F 4300      
0000003E: 0000           

Any help, flames, guidance etc greatly appreciated.

Thanks In Advance,

Chris B
- ---------------------------------------------------------------------
NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns
Internet: chris-b@cs.auckland.ac.nz
Phone:    +64 9 373-7599 x6194
Fax:      +64 9 373-7453                         Async, therefore I am.
- ---------------------------------------------------------------------

+++++++++++++++++++++++++++

>From h+@nada.kth.se (Jon W{tte)
Date: Fri, 19 Aug 1994 22:27:16 +0200
Organization: Royal Institute of Something or other

In article <chris-b-2008940058020001@hmu7.cs.aukuni.ac.nz>,
chris-b@cs.auckland.ac.nz (Chris Burns) wrote:

>version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The
>68K version however, does not work. The _PBHGetVInfoAsync call returns all
>kinds of bogus values instead of nice file manager errors.

That's because you're testing the return value of an asynchronous
call. You're not supposed to do that, since there's no error to
return there yet; instead you're supposed to test ioResult in the
completion proc, or poll ioResult until it's not 1.

Cheers,

				/ h+


--
  Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden

"TextEdit does everything right."
	‹ Jon W{tte


+++++++++++++++++++++++++++

>From chris-b@cs.auckland.ac.nz (Chris Burns)
Date: Sun, 21 Aug 1994 18:19:12 +1200
Organization: AucklandUniversity:ComputerScience:HMU

In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon
W{tte) wrote:

> In article <chris-b-2008940058020001@hmu7.cs.aukuni.ac.nz>,
> chris-b@cs.auckland.ac.nz (Chris Burns) wrote:
> 
> >version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The
> >68K version however, does not work. The _PBHGetVInfoAsync call returns all
> >kinds of bogus values instead of nice file manager errors.
> 
> That's because you're testing the return value of an asynchronous
> call. You're not supposed to do that, since there's no error to
> return there yet; instead you're supposed to test ioResult in the
> completion proc, or poll ioResult until it's not 1.

Sorry Jon, I don't buy it.

(I'm assuming that IM-IV Chpt 19 [File Manager] is still valid because it
documents the low-level file manager routines; I havn't looked at
NIM:Files)

Check out IM-IV Pg 119:

"Routines that are executed asynchronously return control to the calling
program with the result code noErr as soon as the call is placed in the
file I/O queue. This isn't an indication of successful call completion,
but simply indicates that the call was successfully queued."

This is the case with nearly all async calls, they return a file manager
error to the calling program (typically "noErr", but possibly "paramErr"
or others), and then the real error somewhere in the param block (often
also in D0) at completion proc time. These two errors should not be
related in any way. The fact that D0 = $stuvwxyz upon exit of the
completion proc should not mean that the calling code receives an error of
$wxyz (D0.w).

IM-IV Pg 119:

"Warning: Completion routines are executed at interrupt level and must
preserve all registers other than A0,A1, and D0-D2."

Surely this means my completion routine code can do what it wants with
these regs without affecting anything.

IM-IV Pg 119:

"When your completion routine is called, register A0 points to the
parameter block of the asynchronous call and register D0 contains the
result code."

I read this to mean that these were "read-only" values (changes are not
propagated back to calling code). I based this upon the fact that the
completion proc may be called _well_ after the _PBHGetVInfo call. A remote
file system such as an AppleShare volume will definitely be this way for
mnay types of calls.


I have kind-of solved this problem, but not to my satisfaction. If I save
and restore the scratch regs (A0,A1, and D0-D2) the thing works properly.
However, I don't think I should need to do this, and besides, its real
ugly.

#if USES68KINLINES
asm....
#endif

yuck!

Any more ideas would be wonderful.

Thanks Heaps In Advance,

Chris B
- ---------------------------------------------------------------------
NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns
Internet: chris-b@cs.auckland.ac.nz
Phone:    +64 9 373-7599 x6194
Fax:      +64 9 373-7453                         Async, therefore I am.
- ---------------------------------------------------------------------

+++++++++++++++++++++++++++

>From Jaeger@fquest.com (Brian Stern)
Date: 21 Aug 1994 14:39:41 GMT
Organization: The University of Texas at Austin, Austin, Texas

In article <chris-b-2008940058020001@hmu7.cs.aukuni.ac.nz>,
chris-b@cs.auckland.ac.nz wrote:

> Hi All,
> 
> I've been looking into using async file manager calls, so I started
> experimenting with an easy one, an indexed _PBHGetVInfoAsync call until
> the error returned is nsvErr (no-such-volume: -35). This works perfectly
> using sync calls. Things aren't so rosy on the async front tho'.
> 
> Being in a PowerPC friendly kind of mood (and running on a PM8100/80), I
> thought "cool, I'll use UPPs for my completion routine specifiers, and
> compile a fat app". This aspect is fine, and in fact, the PowerPC native
> version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The
> 68K version however, does not work. The _PBHGetVInfoAsync call returns all
> kinds of bogus values instead of nice file manager errors.
> 
> Here's the entire code:
> #if USES68KINLINES
> #pragma parameter CompletionProc(__A0)
> #endif
> 
> pascal void CompletionProc(HParmBlkPtr HPB)
> {
> long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5);
> 
>     gNumDrivesDone++;
>     DebugStr(((VolPBPtr)HPB)->VolName);
> 
>     SetA5(SavedA5);
> }
> Chris B
> -----------------------------------------------------------------------
> NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns
> Internet: chris-b@cs.auckland.ac.nz
> Phone:    +64 9 373-7599 x6194
> Fax:      +64 9 373-7453                         Async, therefore I am.
> -----------------------------------------------------------------------

So why not change it to this:

#if USES68KINLINES
#pragma parameter __D0 CompletionProc(__A0)
#endif

pascal OSErr CompletionProc(HParmBlkPtr HPB)
{
long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5);

    gNumDrivesDone++;
    DebugStr(((VolPBPtr)HPB)->VolName);

    SetA5(SavedA5);

    return HPB->ioResult;

}

No Assembly Required.

My reading of the passages in IM-IV that you quoted seems ambiguous about
whether or not a completion routine returns a result in DO.  My first
guess would have been no.

BTW, Use of the #pragma parameter in this way in MW works differently from
Think C.  In Think you can only use #pragma parameter for inline calls. 
This means that it's only useful for routines that you're calling, not for
cases where your routines are called with parameters in registers.  So
when compiling your CompletionProc with Think C, the compiler ignores the
#pragma parameter and assumes that HPB was passed on the stack.  Oh well 
:-(

-- 
Brian  Stern  :-{)}
Jaeger@fquest.com

+++++++++++++++++++++++++++

>From resnick@uiuc.edu (Pete Resnick)
Date: Sun, 21 Aug 1994 13:02:57 -0500
Organization: University of Illinois at Urbana-Champaign

In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon
W{tte) wrote:

>That's because you're testing the return value of an asynchronous
>call. You're not supposed to do that, since there's no error to
>return there yet; instead you're supposed to test ioResult in the
>completion proc, or poll ioResult until it's not 1.

No, you're wrong. Inside Macintosh: Files, page 2-6 is quite explicit:

    Routines that are executed asynchronously return control to your
    application with the result code noErr as soon as the call is placed in
    the file I/O queue. Return of control does not signal successful
    completion of the call, but simply successful queuing of the request.

You could plausibly get back an error if for some reason the Device
Manager determined that the call could not be queued (a screwy refNum or
the like). You are perfectly correct (though maybe using a little
overkill) in checking the return code from an asynchronous routine. The
problem lies somewhere else.

pr
-- 
Pete Resnick    	(...so what is a mojo, and why would one be rising?)
Doctoral Student - Philosophy Department, Gregory Hall, UIUC
System manager - Cognitive Science Group, Beckman Institute, UIUC
Internet: resnick@uiuc.edu

+++++++++++++++++++++++++++

>From benh@fdn.org (Benjamin Herrenschmidt)
Date: Mon, 22 Aug 94 11:52:45 +0100
Organization: (none)



>>That's because you're testing the return value of an asynchronous
>>call. You're not supposed to do that, since there's no error to
>>return there yet; instead you're supposed to test ioResult in the
>>completion proc, or poll ioResult until it's not 1.
>
>No, you're wrong. Inside Macintosh: Files, page 2-6 is quite explicit:
>
>    Routines that are executed asynchronously return control to your
>    application with the result code noErr as soon as the call is placed in
>    the file I/O queue. Return of control does not signal successful
>    completion of the call, but simply successful queuing of the request.
>
>You could plausibly get back an error if for some reason the Device
>Manager determined that the call could not be queued (a screwy refNum or
>the like). You are perfectly correct (though maybe using a little
>overkill) in checking the return code from an asynchronous routine. The
>problem lies somewhere else.

I remember something about async File Mgr. calls : unlike device manager
calls, File Manager calls ALWAYS calls the completion routine to handle
the result code, and the result of the async call itself MAY be garbage,
event if something is wrong with the queue. The result code you should
use is the one returned to the completion routine (or in the ioResult
field of the paramblock)

I think i read this in a technote or a Q&A... 

BenH.

+++++++++++++++++++++++++++

>From ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University)
Date: 23 Aug 94 18:05:13 +1200
Organization: University of Waikato, Hamilton, New Zealand

In article <chris-b-2108941819120001@hmu7.cs.aukuni.ac.nz>, chris-b@cs.auckland.ac.nz (Chris Burns) writes:
> In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon
> W{tte) wrote:
>
>> In article <chris-b-2008940058020001@hmu7.cs.aukuni.ac.nz>,
>> chris-b@cs.auckland.ac.nz (Chris Burns) wrote:
>>
>> That's because you're testing the return value of an asynchronous
>> call. You're not supposed to do that, since there's no error to
>> return there yet; instead you're supposed to test ioResult in the
>> completion proc, or poll ioResult until it's not 1.
>
> Sorry Jon, I don't buy it.
>
> (I'm assuming that IM-IV Chpt 19 [File Manager] is still valid because it
> documents the low-level file manager routines; I havn't looked at
> NIM:Files)
>
> Check out IM-IV Pg 119:
>
> "Routines that are executed asynchronously return control to the calling
> program with the result code noErr as soon as the call is placed in the
> file I/O queue. This isn't an indication of successful call completion,
> but simply indicates that the call was successfully queued."

There is a technote somewhere which corrects this. Basically, you shouldn't
bother checking the immediate return code from _any_ async call. I recently
got burned with this doing async sound recording: my call to SPBRecord worked
fine everywhere _except_ on a 500-series PowerBook, and then only when I
invoked a combination of certain other recording options at the same time.

There is one situation where you should be careful about polling ioResult
(And I'm not talking about being stupid, sitting in a tight loop at interrupt
level, blocking the completion of the call you're polling for!): the PPC
Toolbox. In System 7.0, the PPC Toolbox sets ioResult some time before it
dequeues the parameter block from its request queue. This means if you have
an interrupt routine that periodically checks the ioResult from a PPC Toolbox
request, and assumes the parameter block can be reused the moment it goes 0
or negative, you could be in for a crash. If you specify a completion routine,
then the parameter block can be safely reused when this routine is called.

I understand this might be fixed in later Systems, but I'm not sure which ones.
If Jim Luther is reading this, he might be able to update us...

Lawrence D'Oliveiro                       fone: +64-7-856-2889
Info & Tech Services Division              fax: +64-7-838-4066
University of Waikato            electric mail: ldo@waikato.ac.nz
Hamilton, New Zealand    37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00

+++++++++++++++++++++++++++

>From chris-b@cs.auckland.ac.nz (Chris Burns)
Date: Wed, 24 Aug 1994 12:47:36 +1200
Organization: AucklandUniversity:ComputerScience:HMU

In article <Jaeger-2108940941410001@slip-1-88.ots.utexas.edu>,
Jaeger@fquest.com (Brian Stern) wrote:

> So why not change it to this:
> 
> #if USES68KINLINES
> #pragma parameter __D0 CompletionProc(__A0)
> #endif
> 
> pascal OSErr CompletionProc(HParmBlkPtr HPB)
> {
> long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5);
> 
>     gNumDrivesDone++;
>     DebugStr(((VolPBPtr)HPB)->VolName);
> 
>     SetA5(SavedA5);
> 
>     return HPB->ioResult;
> 
> }
> 
> No Assembly Required.

Yeah, good idea Brian. This actually works on both platforms and does not
use any asm. Thanks for the idea, I'll end up using this.

It should not be required tho'. Apple docs clearly state that D0 doesn't
have to be save/restored and don't say the error should be returned in D0
either (in fact this cannot be the case because the completion proc could
potentially execute _well after_ the original error has been returned.
Maybe this call cannot be done truely async?

Thanks Again,

Chris B
- ---------------------------------------------------------------------
NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns
Internet: chris-b@cs.auckland.ac.nz
Phone:    +64 9 373-7599 x6194
Fax:      +64 9 373-7453                         Async, therefore I am.
- ---------------------------------------------------------------------

+++++++++++++++++++++++++++

>From Clinton Bauder <gecko1@applelink.apple.com>
Date: Wed, 24 Aug 1994 21:02:10 GMT
Organization: Apple Computer Inc.

In article <chris-b-2008940058020001@hmu7.cs.aukuni.ac.nz> Chris Burns,
chris-b@cs.auckland.ac.nz writes:
>
>        Err = PBHGetVInfoAsync((HParmBlkPtr)VPB);
>
>        switch (Err)
>        {
>            case noErr:
>                break;
>
>            case nsvErr:
>                continue;
>
>            default:
>                DebugStr("\p_PBHGetVInfoAsync FAILED");
>                break;
>        }

If you are making an async call you have to wait for it to complete.  A
return of noErr from an async call doesn't mean it is done.  I merely
means the PB was correctly filled out and has been accepted (queued) by
the File Mananger.  At some later point it will be completed and the
ioResult field will be updated with the correct result and the completion
routine called.  Your application needs to either poll ioResult (wait til
it is not 1 - which means in progress) or poll some other variable which
is set by the completion routine.  To really take advantage of async IO
you should try and do something with the time in between when you make
the file system call and when ioResult changes to <= noErr.

Clinton
- -------------------------------------------------------------
Clinton Bauder        | Opinions expressed are very likely to
SCSI Grunt and Chief  | be entirely different from the official
Herpetoculturist      | party line of Apple Computer Inc.
Apple Computer Inc.   | Support your local herp society.
- -------------------------------------------------------------

+++++++++++++++++++++++++++

>From jumplong@aol.com (Jump Long)
Date: 26 Aug 1994 01:42:07 -0400
Organization: America Online, Inc. (1-800-827-6364)

In article <chris-b-2108941819120001@hmu7.cs.aukuni.ac.nz>,
chris-b@cs.auckland.ac.nz (Chris Burns) writes:

>Any more ideas would be wonderful.

I responded to Chris via email with this:

- ---

Chris,

You need to get a copy of develop magazine issue #13 and read the article
I wrote called "Asynchronous Routines on the Macintosh".  It answers many
of your current questions and will answer many of the questions you're
going to have in the future :-)  In many cases while writing that article,
I found that Inside Mac was either wrong, or just didn't describe things
completely.

Here's some specific information for what you observed.

1) If the File Manager isn't busy when it receives a request (asynchronous
or synchronous), it doesn't queue it - it begins execution of the request
immediately. If the File Manager is busy handling another request, *then*
the request is queued until the all requests before it in the queue have
executed. If the request is a synchronous request, then the system spins
in SyncWait waiting for the synchronous request to be executed. If the
request is an asynchronous request and it is queued, then control is
returned to the caller after the request is queued

2) When the current request is finished executing and the File Manager has
called its completion routine, the File Manager begins excution of the
next request in the queue (if any).

3) Once the File Manager starts executing an asynchronous request, it
doesn't give up control until it is either: a) done handling the request
or b) makes an asynchronous request to a device driver to read or write
block(s) of data and the device driver returns control to the File Manager
while it handles the request asynchronously. The part "while it handles
the request asynchronously" is important because if the driver handles all
requests synchronously (like the old SCSI Manager does), then the File
Manager doesn't get control back from the driver call until it has
completed, and in that case, the File Manager continues with the execution
of the request.

So, when you call PBHGetVInfoAsync, if the File Manager isn't busy, it
starts execution of the request immediately.  Since GetVInfo requests
don't cause calls to the driver (unless you pass a working directory
number instead of real volume reference number), there is nothing to stop
the File Manager from completing the request. That's why you're seeing the
request complete immediately.

The reason you're seeing the 5 you slam into DO in the completion routine
is that the File Manager uses D0 to return function results to
*synchronous* requests.  With an asynchronous request, you never know what
the real result of the request is until it completes, so the File Manager
sets D0 to 0 when it *starts* execution of the request and doesn't worry
about returning the ioResult value (which is 1 while the call is queued or
executing) to the caller. Here's how we (Apple) recommend making
asychronous File Manager requests (note: Device Manager calls are handled
differently - read the article):

/* Make an asynchronous request. */
/* Ignore the function result and look for the */
/* real result when the call completes. */
(void) PBHGetVInfoAsync(&pb);

or in Pascal:

if (PBHGetVInfoAsync(@pb) <> noErr)
  ; { do nothing, check result at completion }

- ---

- Jim Luther


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

>From bentley@MCS.COM (Mike Bentley)
Subject: Future of ASLM
Date: 13 Aug 1994 17:46:25 -0500
Organization: MCSNet Subscriber Account, Chicago's First Public-Access Internet!

What I meant to ask was,
after finally getting something like a shared library manager out for the 680x0
machines, how does ASLM fit into the plan when building a shared library file
with both 680x0 and PowerPC code in it?

My guess is that this doesn't happen, that an ASLM library gets a file and the
equivalent code fragment import library (a 'shlb' -- too bad, 'shlp' is funnier)
is a separate file. This probably means that there is some differences in
implementation detail in the source code.

-Mike Bentley
Crenelle Inc.


+++++++++++++++++++++++++++

>From garryh@seeding.apple.com (Garry Hornbuckle)
Date: 26 Aug 1994 18:39:45 GMT
Organization: Apple Computer, Inc.

In article <32jig1$42k@Mercury.mcs.com>, bentley@MCS.COM (Mike Bentley) wrote:

> What I meant to ask was,
> after finally getting something like a shared library manager out for
the 680x0
> machines, how does ASLM fit into the plan when building a shared library file
> with both 680x0 and PowerPC code in it?

==========================================
Macintosh Dynamic Linked Libraries (DLLs)
==========================================

Apple has developed a complete technology solution for shared code, shared
objects, and dynamic linked libraries (DLLs) on the Macintosh. Parts of
this solution are available today, with additional parts becoming
available in the coming months.
 
There are three key components to Macintosh DLL strategy:
€ Apple's Shared Library Manager (ASLM),
€ Apple's Code Fragment Manager (CFM), and
€ IBM's System Object Model (SOM).
 
Here is a brief summary of ASLM, CFM, and SOM ...
 
ASLM
- ----------
Apple Shared Library Manager is the first component of Apple's DLL
solution to be available, and is an integral part of our overall DLL
offering.  ASLM supports shared code libraries for both procedural and
object oriented development efforts. A number of Apple products have
already been based on ASLM, including MacSNMP and the GeoPort
communications pod technology. Third parties such as Microsoft (OLE for
Macintosh), Novell (AppWare), and Aldus have also adopted ASLM to support
their DLL needs.

In the future, additonal functionality will be added to the Macintosh
operating system as ASLM libraries, including our next generation
networking, the Open Transport Communications Architecture.

ASLM v1.1.2 is the currently shipping release. ASLM v2.0 is under
development, to provide support for native code shared libraries on Power
Macintosh. ASLM 2.x sits on top of (is based on) the Code Fragment
Manager. This work is expected to produce final product in 4Q CY94.

As CFM becomes available on 68K Macintosh (see below), a future ASLM
version (2.1) will support CFM on 68K as well, while continuing to support
current 68K-style shared libraries. Thus,  ASLM v2.x will provide
compatibility for ASLM v1.1, v1.1.1, and v1.1.2 applications.

ASLM adds higher-level object-oriented capabilities to the environment
that are not a part of the Code Fragment Manager itself. ASLM is the
technology of choice when you:

€  need DLLs on 68K today ... ASLM is shipping
€  want simplicity and elegance with C++
€  want a simple but powerful extension mechanism using C, Pascal, or ASM
€  have performance sensitive (i.e., interrupt time) needs like networking
€  want run-time transparent dynamic loading and unloading of code
€  DON'T need transparent access to per-context global data
€  DON'T need to solve the "fragile base class" problem for C++
 
CFM
- ----------
As a second key step in our DLL strategy, Apple has developed a new
foundation layer for dynamic linking on the Macintosh known as the Code
Fragment Manager (CFM). CFM will be a core part of System Software on the
PowerPC Macintosh.

CFM is also being developed for the Macintosh on 68K. This work is
expected to produce final product in 1Q CY95.

The Code Fragment Manager provides code sharing and dynamic linking, with
features supporting per-context globals. CFM will be fully supported by
development tools on Macintosh.

CFM is the best bet when your application:
€  runs on PowerPC Macintosh first, and 68K Macintosh later
€  needs only basic dynamic loading and unloading of shared code
€  needs to reduce system overhead to the minimum amount
€  needs transparent access to per-context global data
€  DOES NOT need system-level OOP support

 
SOM
- ----------
Apple is in the process of licensing and porting IBM's System's Object
Model (SOM) technology to Macintosh. SOM is a multi-platform standard
providing for system-level sharable objects in a language-neutral way. SOM
also solves the "fragile base class" problem, avoiding the need for client
libraries to be recompiled when the base class they inherit from is in a
different library and is changed.

To offer these benefits (multi-platform support and fragile base-class
resolution) SOM requires the use of an IDL as a first step in the
development process.

SOM runs on top of CFM, and thus will become available on both 68K and
PowerPC Macintosh.

SOM is a foundation technology for OpenDoc. 


Integration
- ----------
SOM and ASLM will both live in a CFM run-time environment, and will both
be available on both 68K and PowerPC Macintosh. Thus there will be no
impediment to co-existence of ASLM and SOM, or to applications that use
both ASLM and SOM. In fact, a SOM class could easily call an ASLM class or
vice-versa.

Over time, some of the functionality provided by ASLM may be supplanted by
SOM. However, ASLM APIs will be preserved. As a result, applications
written to the ASLM API may have some functionality transparently migrated
to SOM in the future.

- -----------------------------------------------------------------
Garry Hornbuckle    Product Manager, Communications & Collaboration
- -----------------------------------------------------------------
"If I told you that I   | email      garryh@seeding.apple.com
 spoke only for myself  | applelink  HORNBUCKLE1
 would you believe me?" | fax        (408) 974-1211
- -----------------------------------------------------------------

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

>From Jaeger@fquest.com (Brian Stern)
Subject: Review of PowerMac devtools available
Date: 26 Aug 1994 03:20:05 GMT
Organization: The University of Texas at Austin, Austin, Texas

If you haven't come across it yet, there is an interesting article titled: 

PUTTING THE C(++) INTO POWER MACINTOSH by Jon Lansdell (August 19th 1994),

that has appeared in the current version of powerPC news.  It is the first
part of a two part series that will review the four native development
environments for the PowerMac.  In case you're wondering these are:

*Symantec's Cross Development kit*
*MPW*
*The Absoft C/C++ SDK* 
*CodeWarrior *

Here are a few quotes taken completely out of context:

Symantec's image amongst the Macintosh developer community was somewhat
tarnished by release 6.0 of Symantec C++ for the Macintosh and reports
that it was somewhat buggy. 

MPW - tried, tested and old.  ETO#15 and the MPW Pro CD both contain
pre-release native versions of the MPW Shell and various tools, including
PPCC. While this does compile applications around twice as fast, the
Linker still has to run under emulation, so while Apple work on a new
native development environment, developers have plenty of time for coffee
breaks during the build process. 

The Absoft SDK includes a couple of extras which give it claim to be a
fully rounded development environment.  Although the Linker and Compiler
are native, it does cry out to be part of a completely native development
environment.

You can find the article via your favorite web-client at:

http://power.globalnews.com:8000/

-- 
Brian  Stern  :-{)}
Jaeger@fquest.com

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

>From scotth@jaguar.visix.com (Scott Hofmann)
Subject: SetDialogDefaultItem() not doing anything!
Date: Thu, 25 Aug 1994 13:42:32 GMT
Organization: Visix Software, Reston, Virginia

In some code I've written for a preferences dialog, I use the calls
SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and "Cancel"
buttons look and perform according to Apple spec, but both traps aren't doing
anything- it's like they exist, but are bound to no-op. This happens both in
Symantec C++ 6.0, using the glue from the THINK Ref 2.0, and in Metrowerks CW4.
I'm working on a Centris 650 running System 7.1, so I'm pretty sure my ROMs
contain that trap - could I be mistaken about this? Has anyone use gotten these
traps to work? Thanks,

                                                            scott
-- 
- -----------------------------------------------------------------------------
J. Scott Hofmann                        | "You've saved humanity...once again"
scotth@visix.com                        |       -Q to Capt. Picard, ST:TNG

+++++++++++++++++++++++++++

>From hanrek@cts.com (Mark Hanrek)
Date: 25 Aug 1994 20:18:00 GMT
Organization: The Information Workshop

In article <SCOTTH.94Aug25094232@jaguar.visix.com>,
scotth@jaguar.visix.com (Scott Hofmann) wrote:

> In some code I've written for a preferences dialog, I use the calls
> SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and "Cancel"
> buttons look and perform according to Apple spec, but both traps aren't doing
> anything- it's like they exist, but are bound to no-op. This happens both in
> Symantec C++ 6.0, using the glue from the THINK Ref 2.0, and in
Metrowerks CW4.
> I'm working on a Centris 650 running System 7.1, so I'm pretty sure my ROMs
> contain that trap - could I be mistaken about this? Has anyone use
gotten these
> traps to work? Thanks,


There is a certain "time" that these calls should be made so that they are
associated with the current dialog. Otherwise, it could cause problems in
the cases in which you don't want the system to do its thing for you.  

In other words, the effect is not global, but rather "contextual". 
Example source code will show you what you need to know.

Hope this helps.

Mark Hanrek

+++++++++++++++++++++++++++

>From dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling)
Date: Fri, 26 Aug 1994 09:41:03 +0100
Organization: UniDO

In article <hanrek-2508941320100001@auke.cts.com>, hanrek@cts.com (Mark
Hanrek) wrote:

> In article <SCOTTH.94Aug25094232@jaguar.visix.com>,
> scotth@jaguar.visix.com (Scott Hofmann) wrote:
> 
> > In some code I've written for a preferences dialog, I use the calls
> > SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and 
> 
> There is a certain "time" that these calls should be made so that they are
> associated with the current dialog.

Try something like (this is Pascal, but...):

		myDlog := GetNewDialog(myID, nil, pointer(-1));

		myErr := SetDialogDefaultItem(myDlog, OK);
		myErr := SetDialogCancelItem(myDlog, cancel);

	 { here it comes: }
		myErr := GetStdFilterProc(filterIt); { don't use your own filter }

		repeat
			ModalDialog(filterIt, itemHit);
			{ do something }
		until itemHit in [OK, Cancel];

-- 
| Dirk Froehling - Germany, Uni Dortmund, FB Maschinenbau, LS Mechanik |
| dirk@gaga.maschinenbau.uni-dortmund.de            GEnie: D.FROEHLING |

+++++++++++++++++++++++++++

>From gbolsinga@aol.com (GBolsinga)
Date: 26 Aug 1994 16:02:07 -0400
Organization: America Online, Inc. (1-800-827-6364)

In article <dirk-260894094103@129.217.230.3>,
dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling) writes:

>Try something like (this is Pascal, but...):
>
>  myDlog := GetNewDialog(myID, nil, pointer(-1));
>
>  myErr := SetDialogDefaultItem(myDlog, OK);
>  myErr := SetDialogCancelItem(myDlog, cancel);
>
>  { here it comes: }
>  myErr := GetStdFilterProc(filterIt); { don't use your own filter }
>
>  repeat
>   ModalDialog(filterIt, itemHit);
>   { do something }
>  until itemHit in [OK, Cancel];

You could use your own filter which pre-filters the call and then calls
the 
standard filter proc

Greg
MPI Multimedia
/* These are MY opinions */


+++++++++++++++++++++++++++

>From stk@uropax.contrib.de (Stefan Kurth)
Date: 27 Aug 1994 18:20:16 +0200
Organization: Contributed Software GbR

In article <33lhnv$m7r@search01.news.aol.com>,
GBolsinga <gbolsinga@aol.com> wrote:

> In article <dirk-260894094103@129.217.230.3>,
> dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling) writes:
>
> > { don't use your own filter }
>
> You could use your own filter which pre-filters the call and then calls
> the standard filter proc
 
Yes, but remember to call it like this:
 
    GetStdFilterProc(&theFilterProc);
 
    asm {
        move.l d3, -(a7)
    }
 
    result = theFilterProc(theDialog, &theEvent, &itemHit);
 
    asm {
        move.l (a7)+, d3
    }
 
    return result;
 
since the std filter proc trashes d3, which can cause strange things to
happen to your local variables.

________________________________________________________________________
Stefan Kurth                 Berlin, Germany              stk@contrib.de

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

>From woody@alumni.caltech.edu (William Edward Woody)
Subject: Trouble making floating windows work with modeless dialogs
Date: 26 Aug 1994 06:56:43 GMT
Organization: California Institute of Technology, Alumni Association


I'm having a problem making modeless dialogs work with floating windows.
The problem is with 'IsDialogEvent()' and 'DialogSelect()'.

When I receive the event from WaitNextEvent(), I first determine if the
event is for a modal dialog through 'IsDialogEvent()', and if it is,
I call my subroutine which gets the calls 'DialogSelect()' to process
the event, and then handle the control ID if DialogSelect returns TRUE.

The problem is that it seems that the modeless dialog is not being
processed correctly if there is a floating window up. I think what's
going on is that as the floating window is the frontmost window in the
WindowList, IsDialogEvent() and DialogSelect() do not handle mouseDown,
nullEvent, or keyDown events at all.

Kludging the system to put the dialog at the head of the WindowList
global for processing of the IsDialogEvent() and DialogSelect() routines
allows me to click on buttons, but edit fields are handled completely
wrong.

What I want to know is, what can I do to make IsDialogEvent() and
DialogSelect() work. (I don't want to use the GhostWindow global because
I may have more than one floating window up at once.) If I can't
make those routines work, then how can I replace the routines with
code of my own to handle dialog events?

I'm really stuck here, and I don't know where to turn. This is my last
hope.

advTHANKSance.

						- Bill
-- 
o William Edward Woody	  | "I'm shying from the light
  In Phase Consulting	  |  I always loved the night
  337 West California #4  |  And now you offer me eternal darkness"
  Glendale, CA 91203	  |  		- Depeche Mode, "One Caress"

+++++++++++++++++++++++++++

>From woody@alumni.caltech.edu (William Edward Woody)
Date: 26 Aug 1994 22:19:16 GMT
Organization: California Institute of Technology, Alumni Association

a while ago (yesterday?) I wrote:
> I'm having a problem making modeless dialogs work with floating windows.
> The problem is with 'IsDialogEvent()' and 'DialogSelect()'.
> 
> What I want to know is, what can I do to make IsDialogEvent() and
> DialogSelect() work. (I don't want to use the GhostWindow global because
> I may have more than one floating window up at once.) If I can't
> make those routines work, then how can I replace the routines with
> code of my own to handle dialog events?

Well, without a solution I could use fast enough, I bit the bullet and wrote
the routines MIsDialogEvent() and MDialogSelect() to replace IsDialogEvent()
and DialogSelect() to solve my problem.

I have attached the code I wrote below, so others can also do modeless
dialogs and floating windows at the same time.

NOTE:	In these routines below, MFrontWindow() is the replacement to
	FrontWindow() which figures out the frontmost non-floater window.

NOTE:	These routines are not well-tested. They work for me, but they
	may have bugs (some severe) which prevent their adequate use.
	Note that they were written to be used together, and are not
	compatable with their 'IsDialogEvent()/DialogSelect()' counterparts.
	I don't know why this is; it just is.

Code follows:

- -CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---

/*  MIsDialogEvent
 *
 *	Is this an event for this dialog box?
 */

Boolean MIsDialogEvent(EventRecord *event)
{
    WindowPtr w;
    short where;
	
    switch (event->what) {
	case mouseDown:
	    where = FindWindow(event->where,&w);
	    if (where != inContent) w = NULL;
	    else if (w != MFrontWindow()) w = NULL;
	    break;
	case updateEvt:
	case activateEvt:
	    w = (WindowPtr)(event->message);
	    break;
	case keyDown:
	case autoKey:
	default:
	    w = MFrontWindow();
	    break;
    }
    if (w == NULL) return 0;
    if (((WindowPeek)w)->windowKind == dialogKind) return 1;
    return 0;
}

/*  MDialogSelect
 *
 *	Do the dialog select routines. This does all of the dialog
 *  processing stuff for this dialog window if it is one.
 */

Boolean MDialogSelect(EventRecord *event, DialogPtr *dlog, short *item)
{
    WindowPtr w;
    DialogPeek peek;
    short where;
    Handle h;
    Rect r;
    TEHandle text;
    char c;
    short index;
    short length;
    Point pt;
    long tmp;
    
    /*
     *  Determine the dialog window that is being used here.
     */
    
    switch (event->what) {
        case mouseDown:
        case mouseUp:
            where = FindWindow(event->where,&w);
            if (where != inContent) w = NULL;
            break;
        case updateEvt:
        case activateEvt:
            w = (WindowPtr)(event->message);
            break;
        default:
            w = MFrontWindow();
            break;
    }
    if (w == NULL) return 1;		// Not my event...
    if (((WindowPeek)w)->windowKind != dialogKind) return 1;
    
    /*
     *  Now, actually do this event as appropriate
     */
    
    *dlog = w;				// The dialog I was handling.
    *item = 0;				// Default item (0)
    peek = (DialogPeek)w;		// So I can get at internal stuff
    switch (event->what) {
    
        /*
         *  Activate/Deactivate
         *
         *	This activates or deactivates the text edit field
         *  if it is present in the dialog box.
         */
        
        case activateEvt:
            SetPort(w);
            text = peek->textH;
            if (text) {
                if (event->modifiers & activeFlag) {
                    TEActivate(text);
                } else {
                    TEDeactivate(text);
                }
            }
            return 0;			// Further processing not needed
        
        /*
         *  Update
         *
         *	This simply draws the contents of this thing
         */
        
        case updateEvt:
            SetPort(w);
            BeginUpdate(w);
            UpdateDialog(w,w->visRgn);
            EndUpdate(w);
            return 0;			// Further processing not needed
        
        /*
         *  Null event processing
         *
         *	Blink the cursor
         */
        
        default:
        case nullEvent:
            SetPort(w);
            if (peek->textH) TEIdle(peek->textH);
            return 0;			// Further processing not needed
        
        /*
         *  Key events
         *
         *	This handles keyboard events by processing the enter/
         *  escape keys as buttons 1 and 2; otherwise, pass to the
         *  current edit box, if any.
         */
        
        case keyDown:
        case autoKey:
            SetPort(w);
            c = (unsigned char)(event->message & charCodeMask);
            
            /*
             *  Enter, escape processing
             */
            
            if ((c == 0x03) || (c == 0x0D) || (c == 0x1B)) {                
                if ((c == 0x03) || (c == 0x0D)) {
                    *item = 1;
                } else {
                    *item = 2;
                }
                
                GetDialogItem(w,*item,&where,&h,&r);
                HiliteControl((ControlHandle)h,inButton);
                Delay(5,&tmp);
                HiliteControl((ControlHandle)h,0);
                return 1;		// Further processing needed
            }
            
            /*
             *  Tab processing
             */
            
            if (c == 0x09) {		// Horizontal tab key
                if (peek->textH == NULL) return 0;	// Can't deal with it.
                length = *((short *)(*(peek->items))) + 1;
                index = peek->editField+2;		// Skip this one
                
                /*
                 *  Find the next edit item and select it
                 */
                
                while (index <= length) {
                    GetDialogItem(w,index,&where,&h,&r);
                    if ((0x7F & where) == 16) {		// This is an edit item
                        SelIText(w,index,0,32767);	// Move edit, select me
                        *item = index;
                        return ((where & 0x80) == 0) ? 1 : 0;
                    }
                    index++;
                }
                index = 1;				// Wrap to beginning
                while (index <= length) {
                    GetDialogItem(w,index,&where,&h,&r);
                    if ((0x7F & where) == 16) {		// This is an edit item
                        SelIText(w,index,0,32767);	// Move edit, select me
                        *item = index;
                        return ((where & 0x80) == 0) ? 1 : 0;
                    }
                    index++;
                }
                *item = 0;
                return 0;				// Huh? Dunno...
            }
            
            /*
             *  Normal keyboard processing
             */
            
            text = peek->textH;
            if (text == NULL) return 0;			// No edit item to do
            
            *item = peek->editField+1;			// Item ID we're doing
            TEKey(c,text);				// Do character process
            
            GetDialogItem(w,*item,&where,&h,&r);	// Return appropriate
            return ((where & 0x80) == 0) ? 1 : 0;	// for enable flag
        
        /*
         *  Mouse down:
         *
         *	track the controls or the edit fields as appropriate
         */
        
        case mouseDown:
            SetPort(w);
            pt = event->where;
            GlobalToLocal(&pt);
            
            /*
             *  Determine where the mouse went down
             */
            
            index = FindDItem(w,pt)+1;
            if (index == 0) return 0;		// Not on anything
            GetDialogItem(w,index,&where,&h,&r);
            *item = index;
            
            /*
             *  Handle inactive objects
             */
            
            if (where & 0x80) {
                if (where == 0x90) {		// Edit item here.
                
                    /*
                     *  Handle edit selection even if inactive
                     */
                    
                    if (peek->editField + 1 != index) {
                        SelIText(w,index,0,32767);
                    }
                    TEClick(pt,(event->modifiers & shiftKey) ? 1 : 
0,peek->textH);
                }
                return 0;
            }
            
            /*
             *  Process according to where I'm at
             */
            
            switch (where) {
                default:
                    return 1;			// Just return the ID.
                case 4:
                case 5:
                case 6:
                case 7:
                    /*
                     *  Click on a standard control object
                     */
                    
                    if (TrackControl((ControlHandle)h,pt,NULL)) return 1; // do 
it.
                    return 0;			// don't do it.
                case 16:			// Handle edit box
                    if (peek->editField + 1 != index) {
                        SelIText(w,index,0,32767);
                    }
                    TEClick(pt,(event->modifiers & shiftKey) ? 1 : 
0,peek->textH);
                    return 1;			// Return where I am now. 
            }
    }
    return 0;		// Not one of these; can't deal with it at all...
}

- -CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---

I hope this helps. Permission is granted to use this message and the
code contained herein in any way you want, redistribute it, fold it,
spindle it, or mutulate it, so long as you don't sue me if the code
crashes. Given away as is, without warranty of any kind. If you don't
like this, my lawyer can mud-wrestle your lawyer in the nude for 15
rounds at the local mud-wrestling bar for brownies. (This assumes,
of course, that your lawyer and my lawyer look good in the nude. :-)

						- Bill
-- 
o William Edward Woody	  | "I'm shying from the light
  In Phase Consulting	  |  I always loved the night
  337 West California #4  |  And now you offer me eternal darkness"
  Glendale, CA 91203	  |  		- Depeche Mode, "One Caress"

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

End of C.S.M.P. Digest
**********************