From: pottier@clipper.ens.fr (Francois Pottier)
Subject: csmp-digest-v3-062
Date: Tue, 4 Oct 1994 02:13:22 +0100 (MET)

C.S.M.P. Digest             Tue, 04 Oct 94       Volume 3 : Issue 62
 
Today's Topics:
 
        (Q)Patched Traps and extention conflicts
        HELP: How does one make a GWorld for printing?
        How to call a C type code resource?
        Is there a reasonable alternative to BalloonWriter?
        Need help with MDEF UPP Question
        OpenDoc Development Environments?
        Q: Getting errors out of threads?
        Shared Memory on Mac
        Window Lists
        preloaded CODE resources in fat binaries



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 especkma@halcyon.com (Erik A. Speckman)
Subject: (Q)Patched Traps and extention conflicts
Date: Mon, 19 Sep 1994 14:49:05 -0700
Organization: The Future Fair

I am trying to track down the causes of some instabillities in my System
configuration and I would appreciate having a few questions answered.

I have used Andrew Welch's Init Tracker to give me a report of what
extensions patch what traps at startup.  I have noticed that a few traps
are patched by multiple extentions.

All of the extensions seem to do what they are supposed to so I was
wondering how it works that multiple extentions can patch the same trap? 
Do they each tag some more code like a subroutine call on to the end of the
trap when they each load?

The multi-patched trap that catches my attention is: 

_Get1IxResource

because it is patched by MacTCP DNR, among others and I have been having
problems which end up effecting DNR after the system has been up a while.

Thanks.

Erik





______________________________________________________________________
Erik A. Speckman       Seattle, Washington      Good Brain Doesn't Suck
especkma@reed.edu                                  especkma@halcyon.com

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

>From Tony Andreoli <andreoli@owens.ridgecrest.ca.us>
Date: Tue, 20 Sep 1994 01:32:36 GMT
Organization: RidgeNet - SLIP/PPP Internet, Ridgecrest, CA. (619) 371-3501

In article <9668AAA35561.106B96@blv-pm1-ip14.halcyon.com> Erik A.
Speckman, especkma@halcyon.com writes:
>All of the extensions seem to do what they are supposed to so I was
>wondering how it works that multiple extentions can patch the same trap? 
>Do they each tag some more code like a subroutine call on to the end of
the
>trap when they each load?

My understanding of patch trapping is this:

The first thing you do when patching a trap, is go to the trap dispatch
table, and get the address for the code associated with the trap, and
store this value, so you're patch can call it when it's done.  The last
thing you do is set the address of your trap in the address table as the
current address for the related trap.

Thus, if extension "A" patches a trap, then extension "B" attempts to
patch the same trap, the execution order will be B -> A -> original trap,
providing of course, that each patch calls the previously set trap
(obtained when the trap was loaded).

Hope this makes some sense.

Tony Andreoli

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

>From jscho@uclink.berkeley.edu (John S. Cho)
Subject: HELP: How does one make a GWorld for printing?
Date: Tue, 20 Sep 1994 16:43:35 -0800
Organization: University of California, Berkeley

How does one change the resolution (from 72dpi to 300dpi or more) on a
GWorld or offscreen bitmap? I need to store drawings into a GWorld to
later be outputed to a printer. The problem I'm having right now is that
all text I draw is being outputed by the printer at 72dpi which makes a
lot of sense since the version saved in the GWorld is also at 72dpi. Is
there a way to keep the resolution and use CopyBits to transfer the
drawing from the GWorld to the printer?

Johnny
         ._/ John Seungwon Cho (Koden)       ( "If not today nor yet tomorrow,
        ._/ koden@well.com                    `.   then some other day."
 ._/   ._/ jscho@{uclink,soda,ocf}.berkeley.edu )
._/._/._/ University of California, Berkeley  .'              - Dream Theater

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

>From gurgle@dnai.com (Pete Gontier)
Date: Tue, 20 Sep 1994 17:13:19 -0800
Organization: Integer Poet Software

In article <jscho-2009941643350001@de32.reshall.berkeley.edu>,
jscho@uclink.berkeley.edu wrote:

> How does one change the resolution (from 72dpi to 300dpi or more) on a
> GWorld or offscreen bitmap? I need to store drawings into a GWorld to
> later be outputed to a printer. The problem I'm having right now is that
> all text I draw is being outputed by the printer at 72dpi which makes a
> lot of sense since the version saved in the GWorld is also at 72dpi. Is
> there a way to keep the resolution and use CopyBits to transfer the
> drawing from the GWorld to the printer?

First I feel like I ought to point out that text is handled quite nicely
by most printer drivers such that you don't have to worry about resolution
if you draw the text directly into a printing GrafPort. (The printers that
don't handle text this way are the ones that are no longer on the market
and the ones that don't print any higher than 72 DPI in the first place.
:-) If you don't need high resolution for the rest of your output, allow
me to suggest you defer the text drawing until you are actually printing.
If this can't work for you, read on.

Off-screen pixel maps don't really have DPI; they just have dimensions in
terms of pixels. Theoretically, a pixel could be four feet or a single
micron across. However, when you print, a pixel does have dimensions;
namely 72 DPI, as you have discovered. (Monitors are *supposed to be* 72
DPI, but many are not. Also, printers have varying DPI, but for historical
reasons printer drivers almost universally report that they are 72 DPI
unless you go out of your way to obtain the true numbers.) Good news: you
can change the DPI recognized by the driver.

Off the top of my head, what you probably want to do is:

    a) Figure out the resolution of the current printer with PrGeneral.
    b) Create a pixel map according to the dimensions of the page and
       the resolution of the printer. It's going to be big. :-)
    c) Make sure you set the resolution of the driver when printing.
    b) CopyBits the pixel map into the printing GrafPort. You will probably
       specify a destination rectangle which appears to scale your output,
       but I suspect the printer driver QD bottleneck will know that you've
       tweaked the resolution and do the right thing.

In order to make the memory consumption reasonable, you may have to
process the pixel map in bands instead of an entire page at a time.

Anyway, I could be wrong about the details of this, but the documentation
for PrGeneral will probably be much more illuminating.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "I saw John Norstad with Elvis! And they were varnishing waffles!"
      -- Peter Cohen <flargh@tiac.net>

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

>From ferrari@netaxs.com (Darrell Turner)
Subject: How to call a C type code resource?
Date: Thu, 15 Sep 1994 15:02:39 -0500
Organization: Haha, None here

Hi, I'm trying to re-write the DNR.c for Pascal.  As far as I can tell, the
dnrp code resource uses a C type calling convention (register based), so I
must pop my stuff off the stack, and put it into the registers.  I've done
a little of the inline assembly, but I don't know how to put the second to
last paramter in d0( or whatever register C expects the first param to be
in).

 function OpenResolverProc (num: longint; fileName: string; dnr: ProcPtr):
OSErr;
 inline
  $205f, $4e90, $3E80; 

{$205f   move.l (a7)+,a0		;dnr: ProcPtr}
{$4e90   jsrs}
{$3e80   puts result in}

Thanks for any help you can be!

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

>From quinn@cs.uwa.edu.au (Quinn "The Eskimo!")
Date: Fri, 16 Sep 1994 11:04:29 +0800
Organization: Department of Computer Science, The University of Western Australia

In article <ferrari-150994150240@slip-55.netaxs.com>, ferrari@netaxs.com
(Darrell Turner) wrote:

>Hi, I'm trying to re-write the DNR.c for Pascal.

Four solutions to your problem...

#1 Use C glue.
#2 Use assembly glue.
#3 Do some horrible kludge using inlines (put the parameters in backwards
   and then use the in-line to clean up the stack)
#4 FTP Peter Lewis' sample code and figure out how he did it.
     ftp://redback.cs.uwa.edu.au//Others/PeterLewis/

Personally, I would start at the end of this list and work backwards.

Share and Enjoy.
-- 
Quinn "The Eskimo!"        "Scout in a can. Simple, cheap, easy
                            to use and it's expendable!"

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

>From ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University)
Date: 16 Sep 94 16:52:02 +1200
Organization: University of Waikato, Hamilton, New Zealand

In article <ferrari-150994150240@slip-55.netaxs.com>, ferrari@netaxs.com (Darrell Turner) writes:

> Hi, I'm trying to re-write the DNR.c for Pascal.  As far as I can tell, the
> dnrp code resource uses a C type calling convention (register based), so I
> must pop my stuff off the stack, and put it into the registers.  I've done
> a little of the inline assembly, but I don't know how to put the second to
> last paramter in d0( or whatever register C expects the first param to be
> in).
>
>  function OpenResolverProc (num: longint; fileName: string; dnr: ProcPtr):
> OSErr;
>  inline
>   $205f, $4e90, $3E80;
>
> {$205f   move.l (a7)+,a0		;dnr: ProcPtr}
> {$4e90   jsrs}
> {$3e80   puts result in}

The C convention is still stack-based for arguments, not register-based.
The difference from Pascal is that arguments are stacked from right to
left, not left to right, and everything is extended to 32 bits if it's
smaller. Also the caller pops the arguments off the stack, not the callee.
And finally, a result not exceeding 32 bits is returned in D0.

Put this all together, and the glue you seek for the above routine (nicely
formatted the way I like it) is

    Function OpenResolver
      (
	FileName : String; {?}
	dnr : ProcPtr
      ) : OSErr;

	Inline
	    $205F,			{ move.l (sp)+, a0 }
	    $2F3C, $0000, $0001,	{ move.l #OPENRESOLVER, -(sp) }
	    $4E90,			{ jsr (a0) }
	    $508F,			{ addq.l #8, sp } { pop args }
	    $3E80;			{ move.w d0, (sp) } { return result }

By the way, I'm not sure about the type of the FileName argument: since this
is C code, it probably expects a string with a terminating null, and no
length byte on the front.

Hope this helps.

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 calbear@crl.com (Howard H. Fukuda)
Date: 16 Sep 1994 03:01:34 -0700
Organization: CRL Dialup Internet Access	(415) 705-6060  [login: guest]

Darrell Turner (ferrari@netaxs.com) wrote:
> Hi, I'm trying to re-write the DNR.c for Pascal.  As far as I can tell, the
> dnrp code resource uses a C type calling convention (register based), so I
> must pop my stuff off the stack, and put it into the registers.  I've done
> a little of the inline assembly, but I don't know how to put the second to
> last paramter in d0( or whatever register C expects the first param to be
> in).
>
>  function OpenResolverProc (num: longint; fileName: string; dnr: ProcPtr):
> OSErr;
>  inline
>   $205f, $4e90, $3E80; 

> {$205f   move.l (a7)+,a0		;dnr: ProcPtr}
> {$4e90   jsrs}
> {$3e80   puts result in}

Well, I'm not familiar with DNR.c, but in general C compilers for the 
Macintosh do not put parameters in registers, although D0 is used for the 
return values. Mac C compilers usually push parameters onto the stack 
from right to left. So assuming DNR.C is:

short DNR (long num, char *fileName);

you can call it with the following assembly language code (MPW Assembler 
source)::

CallSomeCode        FUNC                EXPORT
StackFrame          RECORD              {A6Link},DECR
result              DS.W                1
ParamBegin          EQU                 *
num                 DS.L                1
fileName            DS.L                1
dnr                 DS.L                1
ParamSize           EQU                 ParamBegin-*
RetAddr             DS.L                1
A6Link              DS.L                1
LocalSize           EQU                 *
                    ENDR
                    WITH                StackFrame
                    LINK                A6,#LocalSize
                    MOVE.L              fileName(A6),-(SP)
                    MOVE.L              num(A6),-(SP)
                    MOVEA.L             dnr(A6),A0
                    JSR                 (A0)
                    UNLK                A6
                    MOVEA.L             (SP)+,A0
                    LEA                 ParamSize(SP),SP
                    JMP                 (A0)
                    ENDF

Which assembles down to:

00000000: 4E56 0000          LINK       A6,#$0000
00000004: 2F2E 000C          MOVE.L     $000C(A6),-(A7)
00000008: 2F2E 0010          MOVE.L     $0010(A6),-(A7)
0000000C: 206E 0008          MOVEA.L    $0008(A6),A0
00000010: 4E90               JSR        (A0)
00000012: 4E5E               UNLK       A6
00000014: 205F               MOVEA.L    (A7)+,A0
00000016: 4FEF 000C          LEA        $000C(A7),A7
0000001A: 4ED0               JMP        (A0)

If DNR.c is really putting parameters in registers, then just put them in 
the right registers instead of the stack.

Howard

-- 
- -----------------------------------------------------------------------------
Howard H. Fukuda                                                calbear@crl.com
Macintosh Software Engineer                                         "Go Bears!"
===============================================================================

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

>From calbear@crl.com (Howard H. Fukuda)
Date: 16 Sep 1994 03:31:41 -0700
Organization: CRL Dialup Internet Access	(415) 705-6060  [login: guest]

Howard H. Fukuda (calbear@crl.com) wrote:
> Which assembles down to:
>
> 00000000: 4E56 0000          LINK       A6,#$0000
> 00000004: 2F2E 000C          MOVE.L     $000C(A6),-(A7)
> 00000008: 2F2E 0010          MOVE.L     $0010(A6),-(A7)
> 0000000C: 206E 0008          MOVEA.L    $0008(A6),A0
> 00000010: 4E90               JSR        (A0)
> 00000012: 4E5E               UNLK       A6
> 00000014: 205F               MOVEA.L    (A7)+,A0
> 00000016: 4FEF 000C          LEA        $000C(A7),A7
> 0000001A: 4ED0               JMP        (A0)

Well, I goofed. I forgot to save the function result, so change:

0000001A: 4ED0               JMP        (A0)

to:

0000001A: 3E80               MOVE.W     D0,(A7)
0000001C: 4ED0               JMP        (A0)


Howard

-- 
- -----------------------------------------------------------------------------
Howard H. Fukuda                                                calbear@crl.com
Macintosh Software Engineer                                         "Go Bears!"
===============================================================================

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

>From gurgle@dnai.com (Pete Gontier)
Date: Fri, 16 Sep 1994 15:18:23 -0800
Organization: Integer Poet Software

In article <quinn-1609941104290001@edu-dynamic7.educ.ecel.uwa.edu.au>,
quinn@cs.uwa.edu.au (Quinn "The Eskimo!") wrote:

> #3 Do some horrible kludge using inlines (put the parameters in backwards
>    and then use the in-line to clean up the stack)

As long as we're considering using something other than Peter Lewis' code,
would it be so difficult to simply add 'pascal' keywords to "dnr.c" and
write an interface file for Pascal? I suppose it would if you didn't have
a C compiler. :-)

Anyway, my own suggestion for working with "dnr.c" is either use PL's
stuff or modify the copy of "dnr.c" which comes with the NewsWatcher
source. It evidently has siginificant fixes because, as its comments say,
it was "crap". "I had to hack it to death to get it to work," writes
Norstad. Given that NewsWatcher probably does about as many Mac-hosted DNS
lookups as anything in the world except perhaps Eudora, I wouldn't be
surprised if its "dnr.c" were more reliable.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "I saw John Norstad with Elvis! And they were varnishing waffles!"
      -- Peter Cohen <flargh@tiac.net>

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

>From gurgle@dnai.com (Pete Gontier)
Date: Fri, 16 Sep 1994 10:42:28 -0800
Organization: Integer Poet Software

In article <ferrari-150994150240@slip-55.netaxs.com>, ferrari@netaxs.com
(Darrell Turner) wrote:

> Hi, I'm trying to re-write the DNR.c for Pascal.

If Peter Lewis hasn't already done this, I'm a monkey's uncle.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "I saw John Norstad with Elvis! And they were varnishing waffles!"
      -- Peter Cohen <flargh@tiac.net>

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

>From ferrari@netaxs.com (Darrell Turner)
Date: Fri, 16 Sep 1994 23:14:48 -0500
Organization: Haha, None here

In article <gurgle-1609941518230001@dynamic-216.dnai.com>, gurgle@dnai.com
(Pete Gontier) wrote:

> In article <quinn-1609941104290001@edu-dynamic7.educ.ecel.uwa.edu.au>,
> quinn@cs.uwa.edu.au (Quinn "The Eskimo!") wrote:
> 
> > #3 Do some horrible kludge using inlines (put the parameters in backwards
> >    and then use the in-line to clean up the stack)
> 
> As long as we're considering using something other than Peter Lewis' code,
> would it be so difficult to simply add 'pascal' keywords to "dnr.c" and
> write an interface file for Pascal? I suppose it would if you didn't have
> a C compiler. :-)

I have a C compiler, so it's worth a try, what I want to know is, can you
compile a library in C that can be included in your project in Pascal?

> Anyway, my own suggestion for working with "dnr.c" is either use PL's
> stuff or modify the copy of "dnr.c" which comes with the NewsWatcher

I did start from Newswatcher's dnr.c.  And BTW, I have seen PL's coode, and
he did it via a library, and the code is UGGGGGGGGLY!, but I do appreciate
the result of his programming eforts, I just can't stand to do my own
programming with his libraries.  Magic numbers and everything, hehe... I
want to release my efforts as an alternative to his libraries.

> source. It evidently has siginificant fixes because, as its comments say,
> it was "crap". "I had to hack it to death to get it to work," writes
> Norstad. Given that NewsWatcher probably does about as many Mac-hosted DNS
> lookups as anything in the world except perhaps Eudora, I wouldn't be
> surprised if its "dnr.c" were more reliable.

I have got OpenResolver, and Close Resolver to work, now i'm working on
StrToAddr, and it's not going too well...

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

>From gurgle@dnai.com (Pete Gontier)
Date: Fri, 16 Sep 1994 21:59:33 -0800
Organization: Integer Poet Software

In article <ferrari-160994231449@slip-55.netaxs.com>, ferrari@netaxs.com
(Darrell Turner) wrote:

> > As long as we're considering using something other than Peter Lewis' code,
> > would it be so difficult to simply add 'pascal' keywords to "dnr.c" and
> > write an interface file for Pascal? I suppose it would if you didn't have
> > a C compiler. :-)
> 
> I have a C compiler, so it's worth a try, what I want to know is, can you
> compile a library in C that can be included in your project in Pascal?

Sure. Other way around, too. In MPW it's pretty clear how to do it because
everything resolves to an object file. With the THINK compilers, I seem to
remember you actually have to "Build Library" rather than expecting the
compilers to load each other's project files. (You can use project files
as libraries within THINK C and Symantec C++.) I've never done it with
CodeWarrior, but I'd be surprised if it were not possible. There's also
the possibility of mixing and matching. THINK Pascal and CodeWarrior C/C++
read MPW objects, for example, and THINK C/Symantec C++ have a converter
which allows you to use MPW objects.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "I saw John Norstad with Elvis! And they were varnishing waffles!"
      -- Peter Cohen <flargh@tiac.net>

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

>From ferrari@netaxs.com (Darrell Turner)
Date: Sat, 17 Sep 1994 11:46:49 -0500
Organization: Haha, None here

In article <gurgle-1609942159330001@dynamic-207.dnai.com>, gurgle@dnai.com
(Pete Gontier) wrote:

> Sure. Other way around, too. In MPW it's pretty clear how to do it because
> everything resolves to an object file. With the THINK compilers, I seem to
> remember you actually have to "Build Library" rather than expecting the
> compilers to load each other's project files. (You can use project files
> as libraries within THINK C and Symantec C++.) I've never done it with
> CodeWarrior, but I'd be surprised if it were not possible. There's also
> the possibility of mixing and matching. THINK Pascal and CodeWarrior C/C++
> read MPW objects, for example, and THINK C/Symantec C++ have a converter
> which allows you to use MPW objects.

I compiled dnr.c into a library, and eventually got it to link with my
project (no link errors).  But it seems to do exactly the same thing (bad
crashes, jumping to wierd places and getting address errors).  I did make
sure to convert the pascal strings to C strings, but it still doesnt
work...

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

>From peter.lewis@info.curtin.edu.au (Peter N Lewis)
Date: Sun, 18 Sep 1994 13:02:17 +0800
Organization: NCRPDA, Curtin University

In article <ferrari-150994150240@slip-55.netaxs.com>, ferrari@netaxs.com
(Darrell Turner) wrote:

>Hi, I'm trying to re-write the DNR.c for Pascal.  As far as I can tell, the

Well, that's an easy thing to fix:
   Peter.

unit DNR;

interface

   uses
      TCPTypes;

   type
      ResultProcPtr = ProcPtr;
{ procedure ResultProc(hip:hostInfoPtr; userdata:ptr); }
      ResultProc2Ptr = ProcPtr;
{ procedure ResultProc2(hmxip:HMXInfoPtr; userdata:ptr); }
      EnumResultProcPtr = ProcPtr;
{ procedure EnumResultProc(cerp:cacheEntryRecordPtr; userdata:ptr); }

   function OpenResolver: OSErr;
   procedure CloseResolver;
   function StrToAddr (host: Str255; var rtnStruct: hostInfo; completion:
ResultProcPtr; userdata: Ptr): OSErr;
   procedure AddrToStr (addr: longInt; var s: str255);
   function EnumCache (completion: EnumResultProcPtr; userdata: ptr): OSErr;
   function AddrToName (addr: longInt; var hi: hostInfo; completion:
ResultProcPtr; userdata: ptr): OSErr;
   function HInfo (host: Str255; var hi: hmxInfoRec; completion:
ResultProc2Ptr; userdata: ptr): OSErr;
   function MXInfo (host: Str255; var mxi: hmxInfoRec; completion:
ResultProc2Ptr; userdata: ptr): OSErr;

implementation

   uses
{$IFC undefined THINK_Pascal}
      Resources, Errors, Memory, 
{$ENDC}
      Folders;

   var
      code: Handle;

   procedure GetSystemFolder (var vrn: integer; var dirID: longInt);
   begin
      if FindFolder(kOnSystemDisk, kSystemFolderType, false, vrn, dirID)
<> noErr then begin
         vrn := 0;
         dirID := 0;
      end;
   end;

   procedure GetCPanelFolder (var vrn: integer; var dirID: longInt);
   begin
      if FindFolder(kOnSystemDisk, kControlPanelFolderType, false, vrn,
dirID) <> noErr then begin
         vrn := 0;
         dirID := 0;
      end;
   end;

{ SearchFolderForDNRP is called to search a folder for files that might }
{ contain the 'dnrp' resource }
   function SearchFolderForDNRP (ftype, fcreator: OSType; vrn: integer;
dirID: longInt): Handle;
      var
         pb: HParamBlockRec;
         filename: Str63;
         refnum: integer;
         i: integer;
         h: Handle;
         err: OSErr;
   begin
      h := nil;
      i := 1;
      repeat
         pb.ioNamePtr := @filename;
         pb.ioVRefNum := vrn;
         pb.ioDirID := dirID;
         pb.ioFDirIndex := i;
         i := i + 1;
         err := PBHGetFInfoSync(@pb);
         if err = noErr then begin
            if (pb.ioFlFndrInfo.fdType = ftype) &
(pb.ioFlFndrInfo.fdCreator = fcreator) then begin
               SetResLoad(false);
               refnum := HOpenResFile(vrn, dirID, filename, fsRdPerm);
               SetResLoad(true);
               if refnum <> -1 then begin
                  h := Get1IndResource('dnrp', 1);
                  if h <> nil then begin
                     DetachResource(h);
                  end;
                  CloseResFile(refnum);
               end;
            end;
         end;
      until (err <> noErr) or (h <> nil);
      SearchFolderForDNRP := h;
   end;

   function SearchForDNRP: Handle;
      var
         h: Handle;
         vrn: integer;
         dirID: longInt;
   begin
{ first search Control Panels for MacTCP 1.1 }
      GetCPanelFolder(vrn, dirID);
      h := SearchFolderForDNRP('cdev', 'ztcp', vrn, dirID);

      if h = nil then begin
{ next search System Folder for MacTCP 1.0.x }
         GetSystemFolder(vrn, dirID);
         h := SearchFolderForDNRP('cdev', 'mtcp', vrn, dirID);
      end;

      if h = nil then begin
{ then search Control Panels for MacTCP 1.0.x }
         GetCPanelFolder(vrn, dirID);
         h := SearchFolderForDNRP('cdev', 'mtcp', vrn, dirID);
      end;

      if h = nil then begin
{ finally, look in any open resource file }
         h := Get1IndResource('dnrp', 1);
         if h <> nil then begin
            DetachResource(h);
         end;
      end;

      SearchForDNRP := h;
   end;

   function CallOpenResolver (code: ptr): OSErr;
   inline
      $205F, $42A7, $4878, $0001, $4E90, $504F, $3E80;

   function OpenResolver: OSErr;
      var
         err: OSErr;
   begin
      code := SearchForDNRP;
      if code = nil then begin
         err := resNotFound;
      end
      else begin
         HLock(code);
         err := CallOpenResolver(code^);
         if err <> noErr then begin
            DisposeHandle(code);
            code := nil;
         end;
      end;
      OpenResolver := err;
   end;

   procedure CallCloseResolver (code: ptr);
   inline
      $205F, $4878, $0002, $4E90, $584F;

   procedure CloseResolver;
   begin
      if code <> nil then begin
         CallCloseResolver(code^);
         DisposeHandle(code);
      end;
   end;

   procedure P2C (var name: string);
      var
         len: integer;
   begin
      len := length(name);
      BlockMove(@name[1], @name, len);
      name[len] := chr(0);
   end;

   function CallStrToAddr (userdata: ptr; completion: ProcPtr; var
rtnStruct: hostInfo; cname: ptr; code: ptr): OSErr;
   inline
      $205F, $4878, $0003, $4E90, $4FEF, $0014, $3E80;

   function StrToAddr (host: Str255; var rtnStruct: hostInfo; completion:
ResultProcPtr; userdata: Ptr): OSErr;
      var
         err: OSErr;
         len: integer;
   begin
      if code = nil then begin
         err := notOpenErr;
      end
      else begin
         P2C(host);
         err := CallStrToAddr(userdata, completion, rtnStruct, @host, code^);
      end;
      StrToAddr := err;
   end;

   procedure CallAddrToStr (cstr: ptr; addr: longInt; code: ptr);
   inline
      $205F, $4878, $0004, $4E90, $4FEF, $000C;

   procedure AddrToStr (addr: longInt; var s: str255);
      var
         len: integer;
   begin
      if code <> nil then begin
         CallAddrToStr(@s, addr, code^);
         len := 0;
         while (s[len] <> chr(0)) & (len < 255) do begin
            len := len + 1;
         end;
         BlockMove(@s, @s[1], len);
         s[0] := chr(len);
      end;
   end;

   function CallEnumCache (userdata: ptr; completion: ProcPtr; code: ptr):
OSErr;
   inline
      $205F, $4878, $0005, $4E90, $4FEF, $000C, $3E80;

   function EnumCache (completion: EnumResultProcPtr; userdata: ptr): OSErr;
      var
         err: OSErr;
   begin
      if code = nil then begin
         err := notOpenErr;
      end
      else begin
         err := CallEnumCache(userdata, completion, code^);
      end;
      EnumCache := err;
   end;

   function CallAddrToName (userdata: ptr; completion: ProcPtr; var hi:
hostInfo; addr: longInt; code: ptr): OSErr;
   inline
      $205F, $4878, $0006, $4E90, $4FEF, $0014, $3E80;

   function AddrToName (addr: longInt; var hi: hostInfo; completion:
ResultProcPtr; userdata: ptr): OSErr;
      var
         err: OSErr;
   begin
      if code = nil then begin
         err := notOpenErr;
      end
      else begin
         err := CallAddrToName(userdata, completion, hi, addr, code^);
      end;
      AddrToName := err;
   end;

   function CallHInfo (userdata: ptr; completion: ProcPtr; var hi:
hmxInfoRec; name: ptr; code: ptr): OSErr;
   inline
      $205F, $4878, $0007, $4E90, $4FEF, $0014, $3E80;

   function HInfo (host: Str255; var hi: hmxInfoRec; completion:
ResultProc2Ptr; userdata: ptr): OSErr;
      var
         err: OSErr;
   begin
      if code = nil then begin
         err := notOpenErr;
      end
      else begin
         P2C(host);
         err := CallHInfo(userdata, completion, hi, @host, code^);
      end;
      HInfo := err;
   end;

   function CallMXInfo (userdata: ptr; completion: ProcPtr; var hi:
hmxInfoRec; name: ptr; code: ptr): OSErr;
   inline
      $205F, $4878, $0008, $4E90, $4FEF, $0014, $3E80;

   function MXInfo (host: Str255; var mxi: hmxInfoRec; completion:
ResultProc2Ptr; userdata: ptr): OSErr;
      var
         err: OSErr;
   begin
      if code = nil then begin
         err := notOpenErr;
      end
      else begin
         P2C(host);
         err := CallMXInfo(userdata, completion, mxi, @host, code^);
      end;
      MXInfo := err;
   end;

end.

unit TCPTypes;

{ TCPTypes � Peter Lewis, Oct 1991 }
{ This source is Freeware }

interface

{$IFC undefined THINK_Pascal}
   uses
      Types, OSUtils;
{$ENDC}

{ MacTCP return Codes in the range -23000 through -23049 }
   const
      inProgress = 1;                     { I/O in progress }

      ipBadLapErr = -23000;               { bad network configuration }
      ipBadCnfgErr = -23001;           { bad IP configuration error }
      ipNoCnfgErr = -23002;               { missing IP or LAP
configuration error }
      ipLoadErr = -23003;              { error in MacTCP load }
      ipBadAddrErr = -23004;              { error in getting address }
      connectionClosingErr = -23005;         { connection is closing }
      invalidLengthErr = -23006;
      connectionExistsErr = -23007;       { request conflicts with
existing connection }
      connectionDoesntExistErr = -23008;     { connection does not exist }
      insufficientResourcesErr = -23009;     { insufficient resources to
perform request }
      invalidStreamPtrErr = -23010;
      streamAlreadyOpenErr = -23011;
      connectionTerminatedErr = -23012;
      invalidBufPtrErr = -23013;
      invalidRDSErr = -23014;
      invalidWDSErr = -23014;
      openFailedErr = -23015;
      commandTimeoutErr = -23016;
      duplicateSocketErr = -23017;

{ Error codes from internal IP functions }
      ipDontFragErr = -23032;          { Packet too large to send w/o
fragmenting }
      ipDestDeadErr = -23033;          { destination not responding }
      icmpEchoTimeoutErr = -23035;     { ICMP echo timed-out }
      ipNoFragMemErr = -23036;         { no memory to send fragmented pkt }
      ipRouteErr = -23037;             { can't route packet off-net }

      nameSyntaxErr = -23041;
      cacheFaultErr = -23042;
      noResultProcErr = -23043;
      noNameServerErr = -23044;
      authNameErrErr = -23045;
      noAnsErr = -23046;
      dnrErr = -23047;
      outOfMemoryErr = -23048;

{ connectionState }
   const
      CState_Closed = 0;
      CState_Listening = 2;
      CState_Opening1 = 4;
      CState_Opening2 = 6;
      CState_Established = 8;
      CState_Closing1 = 10;
      CState_Closing2 = 12;
      CState_Closing3 = 16;
      CState_Closing4 = 18;
      CState_Closing5 = 20;
      CState_PleaseClose = 14;

   type
      AddrClasses = integer;
   const
      AC_A = 1;
      AC_NS = 2;
      AC_CNAME = 5;
      AC_HINFO = 13;
      AC_MX = 15;

   const
      CTRUE = $FF;
      CFALSE = $00;

   type
      C_BOOLEAN = signedByte;
      CSTRING = ptr;
      CStr30 = packed array[0..29] of char;
      CStr255 = packed array[0..255] of char;
      ipAddr = longInt;
      ipPort = integer;
      StreamPtr = ptr;

   type
      wdsType = record        { Write block for TCP driver. }
            size: integer;          { Number of bytes. }
            buffer: Ptr;            { Pointer to bytes. }
            term: integer;          { Zero for end of blocks. }
         end;
      wdsPtr = ^wdsType;
      wdsEntry = record
            size: integer;          { Number of bytes. }
            buffer: Ptr;            { Pointer to bytes. }
         end;

      hostInfo = record
            rtnCode: longInt;
            rtnHostName: str255;
            addrs: array[1..4] of ipAddr;
         end;
      hostInfoPtr = ^hostInfo;

   type
      HInfoRec = record
            cpuType: CStr30;
            osType: CStr30;
         end;

   type
      MXRec = record
            preference: integer; { unsigned! }
            exchange: CStr255;
         end;

   type
      hmxInfoRec = record
            rtcCode: integer;
            cname: CStr255;
            case integer of
               1: (
                     addr: array[1..4] of ipAddr;
               );
               2: (
                     hinfo: HInfoRec;
               );
               3: (
                     mx: MXRec;
               );
         end;
      hmxInfoRecPtr = ^hmxInfoRec;

   type
      cacheEntryRecord = record
            cname: CSTRING;
            typ: integer;
            class: integer;
            ttl: longInt;
            case integer of
               1: (
                     name: CSTRING;
               );
               2: (
                     addr: ipAddr;
               );
         end;
      cacheEntryRecordPtr = ^cacheEntryRecord;

   const { csCodes for the TCP driver: }
      TCPcsGetMyIP = 15;
      TCPcsEchoICMP = 17;
      TCPcsLAPStats = 19;
      TCPcsCreate = 30;
      TCPcsPassiveOpen = 31;
      TCPcsActiveOpen = 32;
{    TCPcsActOpenWithData = 33;}
      TCPcsSend = 34;
      TCPcsNoCopyRcv = 35;
      TCPcsRcvBfrReturn = 36;
      TCPcsRcv = 37;
      TCPcsClose = 38;
      TCPcsAbort = 39;
      TCPcsStatus = 40;
      TCPcsExtendedStat = 41;
      TCPcsRelease = 42;
      TCPcsGlobalInfo = 43;

      UDPcsCreate = 20;
      UDPcsRead = 21;
      UDPcsBfrReturn = 22;
      UDPcsWrite = 23;
      UDPcsRelease = 24;
      UDPcsMaxMTUSize = 25;
      UDPcsStatus = 26;
      UDPcsMultiCreate = 27;
      UDPcsMultiSend = 28;
      UDPcsMultiRead = 29;

   type
      TCPEventCode = integer;
   const
      TEC_Closing = 1;
      TEC_ULPTimeout = 2;
      TEC_Terminate = 3;
      TEC_DataArrival = 4;
      TEC_Urgent = 5;
      TEC_ICMPReceived = 6;
      TEC_last = 32767;

   type
      UDPEventCode = integer;
   const
      UDPDataArrival = 1;
      UDPICMPReceived = 2;
      lastUDPEvent = 32767;

   type
      TCPTerminateReason = integer;
   const {TCPTerminateReasons: }
      TTR_RemoteAbort = 2;
      TTR_NetworkFailure = 3;
      TTR_SecPrecMismatch = 4;
      TTR_ULPTimeoutTerminate = 5;
      TTR_ULPAbort = 6;
      TTR_ULPClose = 7;
      TTR_ServiceError = 8;
      TTR_last = 32767;

   type
      ICMPMsgType = integer;
   const
      ICMP_NetUnreach = 0;
      ICMP_HostUnreach = 1;
      ICMP_ProtocolUnreach = 2;
      ICMP_PortUnreach = 3;
      ICMP_FragReqd = 4;
      ICMP_SourceRouteFailed = 5;
      ICMP_TimeExceeded = 6;
      ICMP_ParmProblem = 7;
      ICMP_MissingOption = 8;

   type
      TCPNotifyProc = procPtr;
{ procedure TCPNotifyProc(tcpStream:StreamPtr; event:TCPEventCode;
userDataPtr:ptr; }
{                                   terminReason:TCPTerminateReason;
icmpMsg:ICMPReportPtr); }

   type
      TCPIOCompletionProc = procPtr;
{ C procedure TCPIOCompletionProc(iopb:TCPControlBlockPtr); - WHY IS THIS
A C PROC???? }

   type
      UDPNotifyProc = procPtr;
{ procedure UDPProc(udpStream:StreamPtr ;
eventCode:integer;userDataPtr:ptr; icmpMsg:ICMPReportPtr) }

   type
      UDPIOCompletionProc = procPtr;
{ C procedure UDPIOCompletionProc(iopb:UDPiopb Ptr) }

   type
      ICMPEchoNotifyProc = ProcPtr;
{ C procedure ICMPEchoNotifyProc(iopb:IPControlBlockPtr) }
{ WARNING: Ignore the docs, its a C proceudre no matter what they say }

   type
      ICMPReport = record
            stream: StreamPtr;
            localHost: ipAddr;
            localPort: ipPort;
            remoteHost: ipAddr;
            remotePort: ipPort;
            reportType: ICMPMsgType;
            optionalAddlInfo: integer;
            optionalAddlInfoPtr: ptr;
         end;

   const
      NBP_TABLE_SIZE = 20;       { number of NBP table entries }
      NBP_MAX_NAME_SIZE = 16 + 10 + 2;
      ARP_TABLE_SIZE = 20;       { number of ARP table entries }

   type
      nbpEntry = record
            ip_address: ipAddr;           { IP address }
            at_address: longInt;          { matching AppleTalk address }
            gateway: Boolean;          { TRUE if entry for a gateway }
            valid: Boolean;               { TRUE if LAP address is valid }
            probing: Boolean;          { TRUE if NBP lookup pending }
            age: integer;              { ticks since cache entry verified }
            access: integer;              { ticks since last access }
            filler: packed array[1..116] of byte;        { for internal
use only !!! }
         end;
      EnetAddr = record
            en_hi: integer;
            en_lo: longInt;
         end;
      arpEntry = record
            age: integer;        { cache aging field }
            protocol: integer;      { Protocol type }
            ip_address: ipAddr;     { IP address }
            en_address: EnetAddr;      { matching Ethernet address }
         end;
      AddrXlation = record
            case integer of
               0: (
                     arp_table: ^arpEntry
               );
               1: (
                     nbp_entry: ^nbpEntry
               )
         end;
      LAPStats = record
            ifType: integer;
            ifString: CSTRING;
            ifMaxMTU: integer;
            ifSpeed: longInt;
            ifPhyAddrLength: integer;
            ifPhysicalAddress: CSTRING;
            addr: AddrXlation;
            slotNumber: integer;
         end;
      IPEchoPB = record
            dest: ipAddr;           { echo to IP address }
            data: wdsEntry;
            timeout: integer;
            options: Ptr;
            optLength: integer;
            icmpCompletion: ICMPEchoNotifyProc;
            userDataPtr: ptr;
         end;
      LAPStatsPB = record
            lapStatsPtr: ^LAPStats;
         end;
      ICMPEchoInfo = record
            params: array[1..11] of integer;
            echoRequestOut: longInt;   { time in ticks of when the echo
request went out }
            echoReplyIn: longInt;      { time in ticks of when the reply
was received }
            data: wdsEntry;      { data received in responce }
            options: ptr;
            userDataPtr: ptr;
         end;
      IPGetMyIPPB = record
            ourAddress: ipAddr;        { our IP address }
            ourNetMask: ipAddr;        { our IP net mask }
         end;

      IPControlBlock = record
            qLink: QElemPtr;
            qType: INTEGER;
            ioTrap: INTEGER;
            ioCmdAddr: Ptr;
            ioCompletion: TCPIOCompletionProc; {completion routine, or NIL
if none}
            ioResult: OSErr; {result code}
            ioNamePtr: StringPtr;
            ioVRefNum: INTEGER;
            ioCRefNum: INTEGER; {device refnum}
            case csCode : integer of
               TCPcsGetMyIP: (
                     getmyip: IPGetMyIPPB;
               );
               TCPcsEchoICMP: (
                     echo: IPEchoPB
               );
               9999: (
                     echoinfo: ICMPEchoInfo
               );
               TCPcsLAPStats: (
                     lapstat: LAPStatsPB
               );
         end;
      IPControlBlockPtr = ^IPControlBlock;

   type
      UDPCreatePB = record { for create and release calls }
            rcvBuff: Ptr;
            rcvBuffLen: longInt;
            notifyProc: UDPNotifyProc;
            localport: ipPort;
            userDataPtr: ptr;
            endingPort: ipPort;
         end;

   type
      UDPSendPB = record
            reserved: integer;
            remoteIP: ipAddr;
            remotePort: ipPort;
            wds: wdsPtr;
            checkSum: signedByte;
            sendLength: integer;
            userDataPtr: ptr;
            localPort: ipPort;
         end;

   type
      UDPReceivePB = record
            timeOut: integer;
            remoteIP: ipAddr;
            remotePort: ipPort;
            rcvBuff: ptr;
            rcvBuffLen: integer;
            secondTimeStamp: integer;
            userDataPtr: ptr;
            destHost: ipAddr;
            destPort: ipPort;
         end;

   type
      UDPMTUPB = record
            mtuSize: integer;
            remoteIP: ipAddr;
            userDataPtr: ptr;
         end;

   type
      UDPControlBlock = record
            qLink: QElemPtr;
            qType: INTEGER;
            ioTrap: INTEGER;
            ioCmdAddr: Ptr;
            ioCompletion: UDPIOCompletionProc;
            ioResult: OSErr;
            ioNamePtr: stringPtr;
            ioVRefNum: integer;
            ioCRefNum: integer;
            csCode: integer;
            udpStream: streamPtr;
            case integer of
               UDPcsCreate, UDPcsMultiCreate, UDPcsRelease: (
                     create: UDPCreatePB
               );
               UDPcsWrite, UDPcsMultiSend: (
                     send: UDPSendPB
               );
               UDPcsRead, UDPcsMultiRead: (
                     receive: UDPReceivePB
               );
               UDPcsBfrReturn: (
                     return: UDPReceivePB
               );
               UDPcsMaxMTUSize: (
                     mtu: UDPMTUPB
               );
         end;
      UDPControlBlockPtr = ^UDPControlBlock;

   const { Validity Flags }
      timeOutValue = $80;
      timeOutAction = $40;
      typeOfService = $20;
      precedence = $10;

   const { TOSFlags }
      lowDelay = $01;
      throughPut = $02;
      reliability = $04;

   type
      TCPCreatePB = packed record
            rcvBuff: ptr;
            rcvBuffLen: longInt;
            notifyProc: TCPNotifyProc;
            userDataPtr: ptr;
         end;

      TCPOpenPB = packed record
            ulpTimeoutValue: byte;
            ulpTimeoutAction: signedByte;
            validityFlags: byte;
            commandTimeoutValue: byte;
            remoteHost: ipAddr;
            remotePort: ipPort;
            localHost: ipAddr;
            localPort: ipPort;
            tosFlags: byte;
            precedence: byte;
            dontFrag: C_BOOLEAN;
            timeToLive: byte;
            security: byte;
            optionCnt: byte;
            options: array[0..39] of byte;
            userDataPtr: ptr;
         end;

      TCPSendPB = packed record
            ulpTimeoutValue: byte;
            ulpTimeoutAction: signedByte;
            validityFlags: byte;
            pushFlag: byte;
            urgentFlag: C_BOOLEAN;
            wds: wdsptr;
            sendFree: longInt;
            sendLength: integer;
            userDataPtr: ptr;
         end;

      TCPReceivePB = packed record
            commandTimeoutValue: byte;
            filler: byte;
            markFlag: C_BOOLEAN;
            urgentFlag: C_BOOLEAN;
            rcvBuff: ptr;
            rcvBuffLength: integer;
            rdsPtr: ptr;
            rdsLength: integer;
            secondTimeStamp: integer;
            userDataPtr: ptr;
         end;

      TCPClosePB = packed record
            ulpTimeoutValue: byte;
            ulpTimeoutAction: signedByte;
            validityFlags: byte;
            userDataPtrX: ptr;   { Thats mad!  Its not on a word boundary!
Parhaps a documentation bug??? }
         end;

      HistoBucket = packed record
            value: integer;
            counter: longInt;
         end;

   const
      NumOfHistoBuckets = 7;

   type
      TCPConnectionStats = packed record
            dataPktsRcvd: longInt;
            dataPktsSent: longInt;
            dataPktsResent: longInt;
            bytesRcvd: longInt;
            bytesRcvdDup: longInt;
            bytesRcvdPastWindow: longInt;
            bytesSent: longInt;
            bytesResent: longInt;
            numHistoBuckets: integer;
            sentSizeHisto: array[1..NumOfHistoBuckets] of HistoBucket;
            lastRTT: integer;
            tmrRTT: integer;
            rttVariance: integer;
            tmrRTO: integer;
            sendTries: byte;
            sourceQuenchRcvd: byte;
         end;
      TCPConnectionStatsPtr = ^TCPConnectionStats;

      TCPStatusPB = packed record
            ulpTimeoutValue: byte;
            ulpTimeoutAction: signedByte;
            unused: longInt;
            remoteHost: ipAddr;
            remotePort: ipPort;
            localHost: ipAddr;
            localPort: ipPort;
            tosFlags: byte;
            precedence: byte;
            connectionState: byte;
            filler: byte;
            sendWindow: integer;
            rcvWindow: integer;
            amtUnackedData: integer;
            amtUnreadData: integer;
            securityLevelPtr: ptr;
            sendUnacked: longInt;
            sendNext: longInt;
            congestionWindow: longInt;
            rcvNext: longInt;
            srtt: longInt;
            lastRTT: longInt;
            sendMaxSegSize: longInt;
            connStatPtr: TCPConnectionStatsPtr;
            userDataPtr: ptr;
         end;

      TCPAbortPB = packed record
            userDataPtr: ptr;
         end;

      TCPParam = packed record
            tcpRTOA: StringPtr;
            tcpRTOMin: longInt;
            tcpRTOMax: longInt;
            tcpMaxSegSize: longInt;
            tcpMaxConn: longInt;
            tcpMaxWindow: longInt;
         end;
      TCPParamPtr = ^TCPParam;

      TCPStats = packed record
            tcpConnAttempts: longInt;
            tcpConnOpened: longInt;
            tcpConnAccepted: longInt;
            tcpConnClosed: longInt;
            tcpConnAborted: longInt;
            tcpOctetsIn: longInt;
            tcpOctetsOut: longInt;
            tcpOctetsInDup: longInt;
            tcpOctetsRetrans: longInt;
            tcpInputPackets: longInt;
            tcpOutputPkts: longInt;
            tcpDupPkts: longInt;
            tcpRetransPkts: longInt;
         end;
      TCPStatsPtr = ^TCPStats;

      StreamPtrArray = array[1..1000] of StreamPtr;
      StreamPtrArrayPtr = ^StreamPtrArray;

      TCPGlobalInfoPB = packed record
            tcpParamp: TCPParamPtr;
            tcpStatsp: TCPStatsPtr;
            tcpCDBTable: StreamPtrArrayPtr;
            userDataPtr: ptr;
            maxTCPConnections: integer;
         end;

      TCPControlBlock = record
            qLink: QElemPtr;
            qType: INTEGER;
            ioTrap: INTEGER;
            ioCmdAddr: Ptr;
            ioCompletion: TCPIOCompletionProc; {completion routine, or NIL
if none}
            ioResult: OSErr; {result code}
            ioNamePtr: StringPtr;
            ioVRefNum: INTEGER;
            ioCRefNum: INTEGER; {device refnum}
            csCode: integer;
            tcpStream: StreamPtr;
            case integer of
               TCPcsCreate: (
                     create: TCPCreatePB
               );
               TCPcsActiveOpen, TCPcsPassiveOpen: (
                     open: TCPOpenPB;
               );
               TCPcsSend: (
                     send: TCPSendPB;
               );
               TCPcsNoCopyRcv, TCPcsRcvBfrReturn, TCPcsRcv: (
                     receive: TCPReceivePB;
               );
               TCPcsClose: (
                     close: TCPClosePB;
               );
               TCPcsAbort: (
                     abort: TCPAbortPB;
               );
               TCPcsStatus: (
                     status: TCPStatusPB;
               );
               TCPcsGlobalInfo: (
                     globalInfo: TCPGlobalInfoPB
               );
         end;
      TCPControlBlockPtr = ^TCPControlBlock;

implementation

end.
-- 
Peter N Lewis <peter.lewis@info.curtin.edu.au> - Macintosh TCP fingerpainter
FTP my programs from redback.cs.uwa.edu.au:Others/PeterLewis/ or
amug.org:pub/peterlewis/ or nic.switch.ch:software/mac/peterlewis/

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

>From woody@alumni.caltech.edu (William Edward Woody)
Subject: Is there a reasonable alternative to BalloonWriter?
Date: 13 Sep 1994 05:13:29 GMT
Organization: California Institute of Technology, Alumni Association


Pretty much what the subject line says.

Thus far I'm aware of three ways to write balloon help.
First, there's writing a resource script and compile that
with MPW's rez; and while that's marginally okay, (1) rez
cannot be compiled inside of CW (I have to use the toolserver),
and (2) rez scripts are a pain if the person who is writing
them is not a Macintosh programmer.

The second way is to use BalloonWriter. That'd be okay,
except the existing one is buggier than hell, won't even
run on a Quadra, and Apple seemed to have dropped it like
a hot potato.

The third way is apparently through Resourcerer. And
somehow I don't see paying $300 when for 99% of the
resources, I'm perfectly happy with ResEdit.

Is there another alternative I'm not aware of?

Or will Apple bother to finish BalloonWriter and at least
fix the bugs that prevent it from running on my Quadra 700?

						- 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 oster@netcom.com (David Phillip Oster)
Date: Tue, 13 Sep 1994 17:14:43 GMT
Organization: Netcom Online Communications Services (408-241-9760 login: guest)


I don't like BalloonWriter, because it puts the help text in the body
of the 'hmnu' and 'hdlg' resources, and since there is so much repetition,
it is better to indirect from the 'hmnu' and 'hdlg' resources to STR#s,
so you can just reference multiple instances of the same string.

I've written a program, called Balloony that works as follows:
you drop the application on to it. It makes a applicationHelp.r file that
contains 'hmnu' and 'hdlg' resources for all menus and dialogs, indirected
to dummy STR#s that are initialized with the menu text and the DITL text.
if you use CNTL resources, it indirects through to them and puts their title
string in the STR#. If there is no title, it uses a generic string like:
"icon" or "pict".  Having the help text in STR#s makes internationalization
easier.

I will license a single user copy to you for $20.00, if you are interested,
or you can always write your own.
-- 
- ------- oster@netcom.com ----------
"Wendy, you were born a ninja princess, but you were kidnapped by a
band of tax accountants who raised you as their own." -- Ninja C.P.A.

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

>From Paul Ferguson <pferguson@kaleida.com>
Date: 14 Sep 1994 20:38:12 GMT
Organization: Kaleida Labs, Inc.

In article <osterCw2vwK.7x4@netcom.com> David Phillip Oster, oster@netcom.com
writes:
> [... Balloony ...]
> I will license a single user copy to you for $20.00, if you are interested,
> or you can always write your own.

Why not release it as shareware?  It sounds like a handy little
utility.

--fergy

- ------------------------------------------------------------------
  Paul Ferguson         | "It's a sick world, I'm a happy guy..."
  pferguson@kaleida.com |  
- ------------------------------------------------------------------

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

>From peter.lewis@info.curtin.edu.au (Peter N Lewis)
Date: Fri, 16 Sep 1994 14:54:29 +0800
Organization: NCRPDA, Curtin University

In article <353cdp$7h3@gap.cco.caltech.edu>, woody@alumni.caltech.edu
(William Edward Woody) wrote:


>Thus far I'm aware of three ways to write balloon help.
>First, there's writing a resource script and compile that
>with MPW's rez; and while that's marginally okay, (1) rez
>cannot be compiled inside of CW (I have to use the toolserver),
>and (2) rez scripts are a pain if the person who is writing
>them is not a Macintosh programmer.

This can be simplified a fair bit using Perl to parse a high level
format.  This is what I do, and it automates most of the process.

**** High level balloon help data for Anarchie
DIALOG 200 Archie

1.1 Click this to begin the search.

2.1 Click this to close the window without starting a search.

4.1 Click this to save this query into a bookmark document.

5.3 Use this popup menu to select a server from a list of common servers.
5.4 Use this popup menu to select a server from a list of common servers.

6.1 Type the name of the Archie server to query here. Alternatively you
can select a server from the popup menu.

7.1 Type the text of your query here.

8.1 Click this to use a sub-string matching query.
8.3 The query will be a simple sub-string match. It will return any entry
whose name contains the Find string.
9.1 Click this to use a pattern matching query.
9.3 The Find string is interpreted as a pattern and the query returns
entries that match the pattern. * matches any sequences of characters, ?
matches any single character.
10.1 Click this to use a regular expression matching query.
10.3 The Find string is interpreted as a regular expression and the query
returns entries that match the regex. Regexes are too complicated to
explain here.

11.1 The query will be case-insensitive, thus �Frog�, �frog� and �FROG�
will be considered the same.
11.3 The query will be case-sensitive, thus �frog� and �FROG� will be
considered different.

12.1 Type the maximum number of matching entries to be returned by the
query here.

END-DIALOG

DIALOG 500 Preferences Dialog

1.1 Click this to save the preferences.

2.1 Click this to discard any changes you have made since you last saved
the preferences.

4.1 Type your Email address here. This address is used as the password
when you log into anonymous FTP servers.

5.1 Type the name of your prefered Info-Mac mirror site (host:path
format). Alternatively you can select a server from the popup menu.

6.3 Use this popup menu to select an Info-Mac mirror from a list of mirrors.
6.4 Use this popup menu to select an Info-Mac mirror from a list of mirrors.

7.1 Type the name of your prefered UMich mirror site (host:path format).
Alternatively you can select a server from the popup menu.

8.3 Use this popup menu to select an UMich mirror from a list of mirrors.
8.4 Use this popup menu to select an UMich mirror from a list of mirrors.

9.3 Select the face of the font you wish to use in new windows.
9.4 Select the face of the font you wish to use new windows.

10.1 Type the size (in points) of the font you wish to use in new windows here.

11.1 Anarchie will not open a blank Find window when it is launched.
11.3 Anarchie will open a blank Find window when it is launched.

12.1 Anarchie will not open the bookmark listing window when it is launched.
12.3 Anarchie will open the bookmark listing window when it is launched.

13.1 Click this to specify the folder in which to place downloaded files.

14.1 Anarchie will not decode fetched files.
14.3 Anarchie will use StuffIt Expander to decode fetched files.

15.1 Click here to use normal FTP when transferring files.
15.3 Normal (anonymous) FTP will be used when transferring files.
16.1 Click here to use the specified Alex server when transferring files.
16.3 The specified Alex server will be used when transferring files.
17.1 Click here to use the specified proxy firewall when transferring files.
17.3 The specified firewall will be used when transferring files.
18.1 Click here to use the specified SOCKS firewall when transferring files.
18.3 The specified SOCKS firewall will be used when transferring files.

19.1 Type the address of your preferred Alex server here.

20.1 Type the address of your personal, very own, favourite proxy firewall
server here.

21.1 Type the address of your personal, very own, favourite SOCKS firewall
server here.

22.1 This displays the country code of the country in which Anarchie
thinks you are located. Anarchie uses this to calculate the distance value
in listing windows.
22.2 This displays the country code of the country in which Anarchie
thinks you are located. Anarchie uses this to calculate the distance value
in listing windows.

23.1 You have not paid for this copy of �Anarchie�.
23.3 You have paid for this copy of �Anarchie�. Thanks!!!

END-DIALOG

DIALOG 600 FTP

1.1 Click this button to fetch the file or listing.
1.2 This buttons fetches the specified file or listing. Not available
because you have not specified a valid host and path, or you don�t have
enough free memory.

2.1 Click this button to close the window without fetching a file or listing.

4.1 Click this button to save this fetch command into a bookmark document.
4.2 This button saves this fetch command into a bookmark document. Not
available because you have not specified a valid host and path.

5.1 Type a host name here eg �redback.cs.uwa.edu.au�.
6.1 Type a path here eg �/ComSci/ReadMeAboutRedback�.
7.1 Type a username here eg �fred�.  Leave the field blank for anonymous FTP.
8.1 Type a password here eg �oihhlkhu�.  Leave the field blank for
anonymous FTP.  Characters will be displayed as ���.

9.1 Click here if the path leads to a directory. command-1 is a shortcut
for this.
9.3 The specified path should lead to directory. If the path leads to file
then you will get a listing window with just that file in it.
10.1 Click here if the path leads to a file. command-2 is a shortcut for this.
10.3 The specified path should lead to a file. If the path leads to a
directory then you will get an error.
11.1 Click here if the path leads to a text file you wish to view.
command-3 is a shortcut for this.
11.3 The specified path should lead to a text file. If the path leads to a
directory then you will get an error.
12.1 Click here to try indexing the ftp site (type a search string into
the second field). command-4 is a shortcut for this.
12.3 The specified index string will be used to search the ftp site (if it
supports SITE INDEX).

END-DIALOG

DIALOG 2004 Find

1.1 Click this button to find an entry in the listing.

2.1 Click this button to close the window without finding anything.

4.1 Type in the text to search for.

5.1 Only the first entry will be found.
5.3 All matching entries swill be selected.

END-DIALOG

MENU 129 File

0 xxxx,,,File
1 Use this menu to search for files, retrieve files, save bookmarks and
save listings.

0 arch,T,,Archie�
1 Search for a file by querying an Archie server.
2 Search for a file. Not available because there is already a Search
window open.

0 fget,E,,Get�
1 Get a file or listing from an FTP site. You must enter the host name and
path of the file
2 Get a file from an FTP site. Not available because there is not enough
free memory.

0 gets,,,Get Selection
1 Get the selected file or listing from an FTP site. The �return� key is
often a shortcut for this command.
2 Get the selected file or listing. Not available because there is nothing
selected.

0 view,L,,View Selection
1 View the selected file in your favourite text editor. This is also
useful for getting text files.
2 View the selected file. Not available because there is nothing selected.

0 rtry,R,,Retry
1 Retry a failed �Get� or �Archie� operation. Hold down the option key to
edit the request before retrying.
2 Retry a failed operation. Not available because the current window
cannot be retried.

0 obok,O,,Open Bookmark�
1 Open a saved bookmark file and fetch the results. Hold down the option
key to edit the request before acting on it.
2 Open a saved bookmark file. Not available because there is not enough
free memory.

0 obms,B,,List Bookmarks�
1 Open a window listing all the bookmarks in the Bookmarks folder.
2 Open the bookmarks window. Not available because there is not enough
free memory.

0

0 sbok,S,,Save Bookmark�
1 Save a bookmark (or bookmark list) for later use. The bookmark refers to
either the current selection or, if there is no selection, the front
window.
2 Save a bookmark (or bookmark list) for the front window. Not available
because the front window does not support bookmarks.

0 svls,,,Save Listing�
1 Save the front window to a text file which you can import into a
spreadsheet or word processor.
2 Save the front window to a text file. Not available because the front
window does not support listings.

0 clos,W,,Close
1 Close the front window. Hold down the option key to close all windows.
2 Not available because there is no window to close.

0

0 help,H,,Help�
1 Display the help window.

0

0 quit,Q,,Quit
1 Quit �Anarchie�.

END-MENU

MENU 130 Edit

0 xxxx,,,Edit
1 Use this menu to work with text or to set preferences.

0 undo,Z,,Undo
1 Undoes the previous text command.
2 Not available because the last operation cannot be undone.

0

0 cut ,X,,Cut
1 Cuts or removes the selected text. The text is put into the clipboard.
2 Not available because no text is selected.

0 copy,C,,Copy
1 Copies the selected item into the clipboard.  With the option key down,
this will often copy as a URL.
2 Not available because nothing is selected.

0 past,V,,Paste
1 Puts the current contents of the clipboard into the current selection.
2 Not available because nothing appropriate is in the clipboard or because
you can�t paste anything into the current selection.

0 clea,,,Clear
1 Remove the selected text or delete log entries. The text is lost forever.
2 Removes the selected text. Not available because nothing that can be
deleted is selected.

0 sela,A,,Select All
1 Select the entire contents of the front window.
2 Not available because you can�t select anything in the front window or
because you already have selected everything.

0

0 find,F,,Find�
1 Find a matching entry in the window.
2 Not available because the front window is not a List Window.

0 fagn,G,,Find Again
1 Find the next matching entry.
2 Not available because the front window is not a List Window.

0

0 ftch,,,Fetch Server List
1 Fetch the definitive server list from an FTP site in Texas.
2 Not available because there is not enough free memory.

0 pref,,,Preferences�
1 Modify the preferences.
2 Not available because the preferences window is already at the front.

END-MENU

MENU 150 Window

0 xxxx,,,Window
1 Use this menu to bring a window to the front.

0 logw,,,Show Log
1 Display the Log Window.
2 Not available because the log window is already at the front.

0 tran,,,Show Transcript
1 Display the Transcript Window.
2 Not available because the transcript window is already at the front.

END-MENU

END

(evaluate "{active}" =~ /(�)�1:�/ )> dev:null
directory "{�1}"
Perl.68k -Sx "Rocky:Peter:Perl:Balloons.pl"
rez -a -o "Anarchie.rsrc" -ov Balloons.r
delete Balloons.r
*****

Just change the path for Balloons.pl to point to the following file, and
change Anarchie.rsrc to be your resource file (make a copy first to be
safe).  Then edit the high level file in MPW, and select those last few
lines to update the .rsrc file.

***** Balloons.pl *****
#!perl

$balloons_strh_id = 26724;

# chdir "Rocky:Peter:Pascal:TCP Work:TCP Programs:Anarchie";

open(STDIN,"Balloons Data") || die "Failed to open input";
open(STDOUT,">Balloons.r") || die "Failed to open output";

print <<INCLUDES;
#include "Types.r"
#include "BalloonTypes.r"

INCLUDES

@strings=();

while (<>) {
  chop;
  next if /^$/;
  last if /^END$/;
  die "Bad line '$_'" unless /(DIALOG|MENU)\s+(\d+)\s*(.*)/;
  $dialog = $1 eq "DIALOG"; $id = $2; $name=$3;
  @items=();
   @menus=();
   $menuitem=0;
  while (<>) {
    chop;
    next if /^$/;
    if ($dialog) {
       last if /^END-DIALOG$/;
       die "Bad dialog line '$_'" unless /^(\d+)\.(\d+)\s+(.*)/;
       die "Quote in line" if /"/;
       $base=($1-1)*4;
       $item=$base+$2-1;
       $index = &find_string($3);
       $items[$item] = $index;
       $items[$base+0] = 0 unless $items[$base+0];
       $items[$base+1] = 0 unless $items[$base+1];
       $items[$base+2] = 0 unless $items[$base+2];
       $items[$base+3] = 0 unless $items[$base+3];
    } else {
       last if /^END-MENU$/;
       die "Quote in line '$_'" if /"/;
       die "Bad menu line '$_'" unless /^(\d) (.*)/ || /^(\d)$/;
         if ($1 == 0) {
           if ($1 eq $_) {
             $menus[$menuitem]='-';
            } else {
              $menus[$menuitem]= $2;
            }
            $menuitem++;
         } else {
            $base=($menuitem-1)*4;
            $item=$base+$1-1;
            $index = &find_string($2);
            $items[$item] = $index;
            $items[$base+0] = 0 unless $items[$base+0];
            $items[$base+1] = 0 unless $items[$base+1];
            $items[$base+2] = 0 unless $items[$base+2];
            $items[$base+3] = 0 unless $items[$base+3];
         }
    }
  }
   if ($dialog) {
   print <<"HEADER";
resource 'hdlg' ($id,"$name") {
\t2,0,0,0,0,
\tHMSkipItem { },
\t{
HEADER
   } else {
      print <<"HEADER";
resource 'hmnu' ($id,"$name") {
\t2,0,0,0,
\tHMSkipItem { },
\t{
HEADER
   }
  for $item (1..@items/4) {
    $base = ($item-1)*4;
    if ($items[$base+0] || $items[$base+1] ||
        $items[$base+2] || $items[$base+3]) {
         print "\t\tHMStringResItem { /* $item */\n";
         if ($dialog) {
         print <<"ITEM";
\t\t\t{0,0},
\t\t\t{0,0,0,0},
ITEM
         }
      for $k (0..3) {
        $index = $items[$base+$k];
        if ($index) {
          print "\t\t\t$balloons_strh_id,$index,\n";
        } else {
          print "\t\t\t0,0,\n";
        }
      }
      print "\t\t},\n";
    } else {
        print "\t\tHMSkipItem { }, /* $item */\n";
    }
  }
  print <<"TRAILER";
\t}
};

TRAILER
}

print "resource 'STR#' ($balloons_strh_id,\"Balloon Help Strings\") {\n";
print "\t{\n";
for $index (1..@strings) {
  print "\t\t/* $index */\n";
  print "\t\t\"$strings[$index-1]\",\n";
}
print "\t}\n";
print "};\n\n";

close(STDOUT);
close(STDIN);

sub find_string {
  local($s) = @_;
  local($i);
  for $i (1..@strings) {
    return $i if $s eq $strings[$i-1];
  }
  $i = @strings;
  $strings[$i] = $s;
  return $i+1;
}
*****

Enjoy,
   Peter.
-- 
Peter N Lewis <peter.lewis@info.curtin.edu.au> - Macintosh TCP fingerpainter
FTP my programs from redback.cs.uwa.edu.au:Others/PeterLewis/ or
amug.org:pub/peterlewis/ or nic.switch.ch:software/mac/peterlewis/

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

>From chrisat@ids.net (Chris Arsenault)
Subject: Need help with MDEF UPP Question
Date: 16 Sep 1994 11:26:48 GMT
Organization: Sandcastle Studios

I'm in the process of converting a 68k C application over to PowerPC and
ran into a snag. There's a menu def proc module that resides in the main
68k code segment and is patched in via the code resource stub trick. This
trick doesn't work too well on the PowerPC. 

I thought I could still keep the MDEF module in with the application
rather than as a standalone code resource, by installing a MenuDefUPP in
the (**myMenuHandle).menuDefProc. I figured this approach would handle
either PPC or 68k and would remove the self-modifying code.   The PowerPC
version isn't working.  It keeps crashing into _MoveHLow.

I'd really like to keep the menudef proc in the application as it uses
globals etc.

Is this the right approach or is there another way to do this?  Any help
would be greatly appreciated.


Chris

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

>From duga@pacersoft.com (Brady Duga)
Date: Fri, 16 Sep 1994 09:28:21 -0500
Organization: Pacer Software, Inc.

In article <chrisat-1609940719040001@pslip092.egr-ri.ids.net>,
chrisat@ids.net (Chris Arsenault) wrote:

> I thought I could still keep the MDEF module in with the application
> rather than as a standalone code resource, by installing a MenuDefUPP in
> the (**myMenuHandle).menuDefProc. I figured this approach would handle
> either PPC or 68k and would remove the self-modifying code.   The PowerPC
> version isn't working.  It keeps crashing into _MoveHLow.
> 

In your MDEF stub, how are you calling the UPP? Remember, you can't just
call it like a function, you have to use CallUniversalProc(). For an MDEF,
you would use:

CallMenuBarDefProc(userRoutine, selector, message, parameter1, parameter2);

That's #defined in Menus.h.


--Brady

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

>From sbill@informix.com (Bill Stackhouse)
Date: 16 Sep 1994 16:39:00 GMT
Organization: Informix Software, Inc.

In article <chrisat-1609940719040001@pslip092.egr-ri.ids.net> chrisat@ids.net (Chris Arsenault) writes:
>I'm in the process of converting a 68k C application over to PowerPC and
>ran into a snag. There's a menu def proc module that resides in the main
>68k code segment and is patched in via the code resource stub trick. This
>trick doesn't work too well on the PowerPC. 
>
>I thought I could still keep the MDEF module in with the application
>rather than as a standalone code resource, by installing a MenuDefUPP in
>the (**myMenuHandle).menuDefProc. I figured this approach would handle
>either PPC or 68k and would remove the self-modifying code.   The PowerPC
>version isn't working.  It keeps crashing into _MoveHLow.

Just went through the same problem. Here is the pseudo code:

#if powerpc
create handle size of UPP
create UPP
copy in the UPP
store handle in menuProc
destroy UPP
#else
create handle size 6 bytes
copy in jmp MDEF
store handle in menuProc
#endif


Bill

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

>From boyerr@bach.seattleu.edu (Robert A. Boyer)
Subject: OpenDoc Development Environments?
Date: 18 Sep 1994 12:28:50 -0700
Organization: Seattle University, Seattle, WA, USA

Does anyone have experience developing OpenDoc applications on a
Macintosh using a development environment other than MPW?  What
are the pros and cons of the following C++ development environments:
MPW, Symantec, and Metroworks?

Thanks,

Robert Boyer
boyerr@seattleu.edu

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

>From Jens Alfke <jens_alfke@powertalk.apple.com>
Date: Tue, 20 Sep 1994 00:10:43 GMT
Organization: Apple Computer

The current status is that you need cfront or scpp (the Symantec MPW tool) to
build OpenDoc A6 shared libraries. If you get the OpenDoc source code CD,
there's a folder in the Goodies folder that contains a Metrowerks project.
This is a static build, with everything linked into one app, since MW doesn't
support ASLM (more on that later.)

The future: Ever since we moved to SOM we've been using CodeWarrior PPC as
our primary development environment, and it works fine. So when the beta seed
is released RSN you'll be able to build parts with CodeWarrior -- if you have
a PowerPC. For 68k you'll need to use the Symantec compiler, until Metrowerks
releases a 68k version of CW that supports CFM68k. I know that MW plans to do
this but I will let them reveal their schedule :-)

Ken Prehoda, kenp@nmrfam.wisc.edu writes:
> ASLM seems like it is sooo much nicer than SOM.  Well I
> guess it isn't if you are not using C++ (or a C++ compiler that produces
> CFront compatible vtables, etc.).

ASLM is certainly simpler than SOM, and can be used in some niches that SOM
can't (mostly interrupt-level stuff like networking code, not surprising
since it was developed by the AppleTalk people.) But it has a lot of failings
-- not only that it's extremely compiler-dependent, but also that the
libraries are 'fragile' and any nontrivial change to an object's
implementation will break clients. It's also C++ centric, the downside of
which is that object-based libraries cannot be developed in any language but
C++.

Jason Bobier, jbobier@cybernetics.net writes:
> Why doesn't MW support the ASLM? Are they planning on supporting it?

Metrowerks doesn't support ASLM because it would require them to adopt
cfront's calling conventions, vtable format and name-mangling scheme. At
least two of these would be major steps backward for CW on 68k (the third is
the mangling; I've never understood why there was more than one name-mangling
system in the world, can someone explain?)
ASLM will continue to play a role in Mac software, but a minor one, mosty
dominated by the Open Transport networking protocols. Metrowerks (I'm putting
words in their mouths here) decided that wasn't as interesting as other stuff
they could be doing.

> Seems kinda strange that they don't when PP ships with a shared library...

That's a CFM shared library, not an ASLM library. You can sort-of do C++
object based libraries with CFM, provided you export your nonvirtual methods.
These libraries are (as with ASLM) highly dependent on the compiler and on
the exact versions of the library and its clients.

--Jens Alfke                           jens_alfke@powertalk.apple.com
                   "A man, a plan, a yam, a can of Spam ... Bananama!"

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

>From nick+@pitt.edu ( nick.c )
Date: Sun, 18 Sep 94 23:21:35 GMT
Organization: The Pitt, Chemistry

In Article <35i4di$sd@bach.seattleu.edu>, boyerr@bach.seattleu.edu (Robert
A. Boyer) wrote:

>Does anyone have experience developing OpenDoc applications on a
>Macintosh using a development environment other than MPW?  What
>are the pros and cons of the following C++ development environments:
>MPW, Symantec, and Metroworks?

    With a6, you can only use MPW or Symantec.  MW doesn't support
      ASLM, however I've heard later releases of OpenDoc will be
      supported by CodeWarrior.  I'm still sketchy on details.



                                    _/   _/  _/  _/_/_/   _/   _/  
     Interet: nick@pitt.edu        _/_/ _/  _/  _/   _/  _/_/_/    
      eWorld: nick                _/ _/_/  _/  _/       _/ _/      
         CIS: 71232,766          _/   _/  _/   _/_/_/  _/   _/     


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

>From philip@cs.wits.ac.za (Philip Machanick)
Date: 20 Sep 1994 13:20:51 GMT
Organization: Computer Science Dept, U of Witwatersrand

In article <1994Sep20.001043.28057@gallant.apple.com>, Jens Alfke
<jens_alfke@powertalk.apple.com> wrote:
 
> The future: Ever since we moved to SOM we've been using CodeWarrior PPC as
> our primary development environment, and it works fine. So when the beta seed
> is released RSN you'll be able to build parts with CodeWarrior -- if you have
> a PowerPC. For 68k you'll need to use the Symantec compiler, until Metrowerks
> releases a 68k version of CW that supports CFM68k. I know that MW plans to do
> this but I will let them reveal their schedule :-)

I hope they will.

Then it looks as if it may be worth my while to wait for the SOM/beta seed
before getting too heavily into this. I note you craftily failed to
mention the schedule for that ...
-- 
Philip Machanick                   philip@cs.wits.ac.za
Department of Computer Science, University of the Witwatersrand
2050 Wits, South Africa        (at University of Cape Town 4 July-7 Nov)
phone 27(11)716-3309  fax 27(11)339-7965

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

>From bb@lightside.com (Bob Bradley)
Subject: Q: Getting errors out of threads?
Date: Fri, 16 Sep 1994 15:16:37 -0800
Organization: SS Software Inc.

I'm using the Thread Manager to a series of long operations that can
generate errors and I'm looking for a better way to get those errors to
the user.

Right now I'm using OS Queues and when I get an error, I post an error
'event' to the OS Queue which is picked up in my main thread's event loop
(I check for events in my OS queue just like I do the regular event
queue).

One problem is that sometimes I want to give the user the option to skip
the error and resume but, I'm having problems figuring a way to do it.

It also seems like using custom event queues just to display errors is
overkill, any thoughts?

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

>From kenp@nmrfam.wisc.edu (Ken Prehoda)
Date: Sun, 18 Sep 1994 09:31:11 -0600
Organization: Univ of Wisc-Madison Dept of Biochemistry

In article <bb-1609941516370001@user50.lightside.com>, bb@lightside.com
(Bob Bradley) wrote:

> I'm using the Thread Manager to a series of long operations that can
> generate errors and I'm looking for a better way to get those errors to
> the user.
> 
> Right now I'm using OS Queues and when I get an error, I post an error
> 'event' to the OS Queue which is picked up in my main thread's event loop
> (I check for events in my OS queue just like I do the regular event
> queue).
> 
> One problem is that sometimes I want to give the user the option to skip
> the error and resume but, I'm having problems figuring a way to do it.
> 
> It also seems like using custom event queues just to display errors is
> overkill, any thoughts?

It sure does.  What I did in this situation was just to create my own
queue as an application global that I would check through the event loop.

If you are using powerplant, there is an LSharedQueue class which uses a
somewhat more elegant mechanism to solve the problem of communication
between threads.

Ken Prehoda
University of Wisconsin-Madison
Department of Biochemistry
kenp@nmrfam.wisc.edu

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

>From peter.lewis@info.curtin.edu.au (Peter N Lewis)
Date: Mon, 19 Sep 1994 09:48:34 +0800
Organization: NCRPDA, Curtin University

In article <kenp-1809940931110001@f180-096.net.wisc.edu>,
kenp@nmrfam.wisc.edu (Ken Prehoda) wrote:

>> Right now I'm using OS Queues and when I get an error, I post an error
>> 'event' to the OS Queue which is picked up in my main thread's event loop
>> (I check for events in my OS queue just like I do the regular event
>> queue).
>> 
>> One problem is that sometimes I want to give the user the option to skip
>> the error and resume but, I'm having problems figuring a way to do it.

>It sure does.  What I did in this situation was just to create my own
>queue as an application global that I would check through the event loop.

Isn't that the same as what he said?  OS queues are just queues, you can
use the Enqueue and Dequeue functions with your own queues.  Here is what
I would do:

type 
  ThisThreadInformationPtr=^ThisThreadInformation;
  ThisThreadInformation=record
    qLink:ThisThreadInformationPtr; { MUST BE AT START OF RECORD! }
    error:OSErr;
    die:boolean;
    whatever else
  end;

Create New Thread:
data:=NewPtr(SizeOf(ThisThreadInformation));
data^.error:=1; { in progress }
data^.die:=false;
Enqueue(data,@threads);
NewThread(@DoThread,data);


DoThread(data:ThisThreadInformationPtr)
do your calculations as per normal.  If data^.die becomes true, give up.
If you get a potential error, set data^.error to it, and then wait:

procedure GotAnError(err:OSErr);
data^.error:=err;
while data^.error<>1 and not die do
  Yield
end-while

When we return from that, if die is true, then give up, otherwise
continue, ignoring or handling the error as appropriate.


Init:
threads.qHead:=nil;
threads.qTail:=nil;

In the Main loop:
for each data in threads queue do
  if data^.error=noErr then begin
    Signal Success
    Remove from queue
  end else if data^.error<>1 then begin
    Signal failure
    If the user wants it to abort
      set the die field to true
    otherwise
      set data^.error to 1 again so the thread will continue
    end-if
  end;  
end-for

You'll have to be careful about exactly who removes the entry from the
queue and disposes it, but it's not too tricky.

Just be thankful we dont have preemptive multitasking.  Ughh.  It makes
this much more horrible.
   Peter.
-- 
Peter N Lewis <peter.lewis@info.curtin.edu.au> - Macintosh TCP fingerpainter
FTP my programs from redback.cs.uwa.edu.au:Others/PeterLewis/ or
amug.org:pub/peterlewis/ or nic.switch.ch:software/mac/peterlewis/


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

>From fba@cs.brown.edu (Farah B. Abbas)
Subject: Shared Memory on Mac
Date: Thu, 8 Sep 1994 16:46:20 GMT
Organization: Brown University Department of Computer Science

Hi,

Does anyone know how to implement shared memory on the Mac? I have an 
application that sets a variable that I want another app to read later. I guess
one way would be to use a code resource so that one application sets the 
variable in the resource and the other app can load the resource and 
thereby look up the variable. Is there a "Apple Suggested" way that is 
better or do I have to do this hack ? Please email any suggestions to 
fba@cs.brown.edu. Thanx in advance.

Farah

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

>From rmah@panix.com (Robert Mah)
Date: Fri, 09 Sep 1994 03:24:53 -0500
Organization: One Step Beyond

fba@cs.brown.edu (Farah B. Abbas) wrote:

) Does anyone know how to implement shared memory on the Mac? I have an 
) application that sets a variable that I want another app to read later.
) I guess one way would be to use a code resource so that one application
) sets the variable in the resource and the other app can load the resource
) and thereby look up the variable. Is there a "Apple Suggested" way that
) is better or do I have to do this hack ?

I've been working on something to do just this.

It uses Gestalt to provide tagged, shared memory between apps (and any 
other code for that matter).

I've thought about using a trap, but decided against it as Apple sort of
has a hammerlock on the A-trap market :-).

In any case, to use it, one simply registers a block of memory with the
Shared Memory Manager (tm) and then can request it again later by using
the tag.

It is all very simple.  Would you like to test/work on it with it with me?

Cheers,
Rob
_____________________________________________________________________
Robert S. Mah           Software Development          +1.212.947.6507
One Step Beyond        and Network Consulting          rmah@panix.com

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

>From lambert_l@measurex.com (Leon Lambert)
Date: Tue, 13 Sep 1994 20:04:31 GMT
Organization: measurex

In article <1994Sep8.164620.21157@cs.brown.edu>
fba@cs.brown.edu (Farah B. Abbas) writes:

> Hi,
> 
> Does anyone know how to implement shared memory on the Mac? I have an 
> application that sets a variable that I want another app to read later. I guess
> one way would be to use a code resource so that one application sets the 
> variable in the resource and the other app can load the resource and 
> thereby look up the variable. Is there a "Apple Suggested" way that is 
> better or do I have to do this hack ? Please email any suggestions to 
> fba@cs.brown.edu. Thanx in advance.
> 
> Farah

I did this by making an INIT that created a trap. But I now think a
better way to do this is to use the gestalt manager. It has the
ability to store and retrieve a 32 bit value. I haven't tried it yet
but maybe someone else has.

lambert_l@measurex.com (Leon Lambert)
lambertlb@aol.com

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

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

In article <1994Sep8.164620.21157@cs.brown.edu>, fba@cs.brown.edu (Farah
B. Abbas) wrote:

< Hi,
< 
< Does anyone know how to implement shared memory on the Mac? I have an 
< application that sets a variable that I want another app to read later.
I guess
< one way would be to use a code resource so that one application sets the 
< variable in the resource and the other app can load the resource and 
< thereby look up the variable. Is there a "Apple Suggested" way that is 
< better or do I have to do this hack ? Please email any suggestions to 
< fba@cs.brown.edu. Thanx in advance.
< 
< Farah

Hi,

This can be done by putting the information in a preferences file that
both apps can open.  

You can install a gestalt selector that returns the address of this shared
memory.  Both the gestalt selector and the shared memory should exist in
the system heap if you do this, in case of crashes.  

This can also be implemented by creating a driver that returns the address
of the shared mem or that returns the actual values in the shared mem.

Good Luck,

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

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

>From peter.lewis@info.curtin.edu.au (Peter N Lewis)
Date: Mon, 19 Sep 1994 09:33:04 +0800
Organization: NCRPDA, Curtin University

In article <1994Sep8.164620.21157@cs.brown.edu>, fba@cs.brown.edu (Farah
B. Abbas) wrote:

>Does anyone know how to implement shared memory on the Mac? I have an 
>application that sets a variable that I want another app to read later. I guess
>one way would be to use a code resource so that one application sets the 
>variable in the resource and the other app can load the resource and 
>thereby look up the variable. Is there a "Apple Suggested" way that is 
>better or do I have to do this hack ? Please email any suggestions to 
>fba@cs.brown.edu. Thanx in advance.

Use Gestalt.  Have either or both applications install a gestalt handler
that returns the variable or the address of the variable.

WARNING: Do not assume you will be able to write (or perhaps even read)
another app's memory directly.  We desperately want Apple to give us
memory protection, at least between the various app's partitions, right?! 
If you want to share memory directly, then at least allocate the memory in
the System Heap, and use a Gestalt call to get the address of the memory.

Both apps could do something like:

If the gestalt call is already installed
  use the value returned as a ptr/handle to the data.
otherwise
  create the memory in the system heap
  load the gestalt code (probably also in the system heap)
  install the gestalt
  initialize the memory
end

After that, you can assume the gestalt call is installed and the memory is
available.

Enjoy,
   Peter.
-- 
Peter N Lewis <peter.lewis@info.curtin.edu.au> - Macintosh TCP fingerpainter
FTP my programs from redback.cs.uwa.edu.au:Others/PeterLewis/ or
amug.org:pub/peterlewis/ or nic.switch.ch:software/mac/peterlewis/

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

>From chrism@col.hp.com (Chris Magnuson)
Date: 20 Sep 1994 17:05:56 GMT
Organization: HP Colorado Springs Division

  It *seems* like the PPC Toolbox might be okay for this.  There is an
  example of this on one of the developer CDs, where an INIT allocates
  some memory for shared globals and an application reads them.

  Chris Magnuson
  chrism@col.hp.com

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

>From dbradley@Netaxs.com (Dan Bradley)
Subject: Window Lists
Date: 10 Sep 1994 19:10:49 GMT
Organization: Netaxs Internet BBS and Shell Accounts

Can anyone describe the process used to get a list of all open windows
within an application? I simply want to make an on the fly menu with
all the windows in my application in it. I thought of just updating the list
within my open, close, and save handlers, but it seems like it would be
a lot easier to just cycle through a list, which I'm sure must exist, but
I simply can't find, being a newbie who just doesn't know where to look.
I've been looking through IM, Think Ref, and Dave Mark's books, but
haven't found anything. I'm using Think C 6 and no TCL.

Thanks in advance,

Dan Bradley
dbradley@netaxs.com


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

>From tnleeuw@cs.vu.nl (Leeuw van der TN)
Date: Mon, 12 Sep 1994 14:23:31 GMT
Organization: Fac. Wiskunde & Informatica, VU, Amsterdam

dbradley@Netaxs.com (Dan Bradley) writes:
: Can anyone describe the process used to get a list of all open windows
: within an application? I simply want to make an on the fly menu with
: all the windows in my application in it. I thought of just updating the list
: within my open, close, and save handlers, but it seems like it would be
: a lot easier to just cycle through a list, which I'm sure must exist, but
: I simply can't find, being a newbie who just doesn't know where to look.
: I've been looking through IM, Think Ref, and Dave Mark's books, but
: haven't found anything. I'm using Think C 6 and no TCL.
: 
: Thanks in advance,
: 
: Dan Bradley
: dbradley@netaxs.com
: 
Once I had a similar problem, when I wanted to get a list of my windows
so I could dispose of them when quitting. I came up with the AUXWinRec,
which you can call with a valid window record as a parameter, and gives
you the AuxWinRecord (sp?) for the Window *if* it is a color window.
*If* it is a color window, the owner field points to your window. Big Trick:
it also has a field pointing to the next AuxWinRec in the list,
which has of course an owner... So if you now what your first window
is (like, your about-box) you might be able to get the list.

I must admit that after I typed that code, I found the solution too scary
to really try it. I rewrote it using Frontwindow(). I've not seen it
documented anywhere what window is really next in the list. It might not
be yours.
I'm really curious how to do it.

--Tim van der Leeuw
tnleeuw@cs.vu.nl

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

>From kurisuto@babel.ling.upenn.edu (Sean Crist)
Date: 12 Sep 1994 18:59:18 GMT
Organization: University of Pennsylvania, Linguistics Department

Unless I'm mistaken, it's still kosher to write your program as if all its
windows are in one linked list.  There's so many applications that step
through their own windows this way that Apple really can't change this
without breaking an awful lot of applications.  If I remember right,
though, FrontWindow returns the first _visible_ window, and you might want
to start with invisible ones, so you've got to look in some low-memory
pointer to really start at the front of the window list.

I'm talking off the top of my head; I've got some Pascal code at home that
illustrates this but I might be wrong in a few of the details.

--Sean


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

>From cswan@actrix.gen.nz (Chris Swan)
Date: Wed, 14 Sep 1994 00:58:40 GMT
Organization: Actrix Information Exchange

> : Can anyone describe the process used to get a list of all open windows
> : within an application? I simply want to make an on the fly menu with

> Once I had a similar problem, when I wanted to get a list of my windows
> so I  [deleted - really complex answer] tting. 

theWindow := FrontWindow;
while theWindow <> nil do
  begin
   Do_Some_thing(with, theWindow);
   theWindow:= windowPtr(windowPeek(theWindow)^.nextWindow);
  end;

Ref. Inside Macintosh Volume I

-- 
Chris Swan
cswan@actrix.gen.nz
PO Box 11567, Wellington, New Zealand
--

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

>From Tim_Craycroft@PowerTalk.apple.com (Tim Craycroft)
Date: Wed, 14 Sep 1994 00:40:00 GMT
Organization: Apple Computer

In article <Cw0tB8.2IL@cs.vu.nl>, tnleeuw@cs.vu.nl (Leeuw van der TN)
wrote:
> 
> dbradley@Netaxs.com (Dan Bradley) writes:
> : Can anyone describe the process used to get a list of all open windows
> : within an application? I simply want to make an on the fly menu with
> : all the windows in my application in it. I thought of just updating the list
> : within my open, close, and save handlers, but it seems like it would be
> : a lot easier to just cycle through a list, which I'm sure must exist, but
> : I simply can't find, being a newbie who just doesn't know where to look.
> : I've been looking through IM, Think Ref, and Dave Mark's books, but
> : haven't found anything. I'm using Think C 6 and no TCL.
> : 
> : Thanks in advance,
> : 
> : Dan Bradley
> : dbradley@netaxs.com
> : 
> Once I had a similar problem, when I wanted to get a list of my windows
> so I could dispose of them when quitting. I came up with the AUXWinRec,
> which you can call with a valid window record as a parameter, and gives
> you the AuxWinRecord (sp?) for the Window *if* it is a color window.
> *If* it is a color window, the owner field points to your window. Big Trick:
> it also has a field pointing to the next AuxWinRec in the list,
> which has of course an owner... So if you now what your first window
> is (like, your about-box) you might be able to get the list.
> 
> I must admit that after I typed that code, I found the solution too scary
> to really try it. I rewrote it using Frontwindow(). I've not seen it
> documented anywhere what window is really next in the list. It might not
> be yours.
> I'm really curious how to do it.
> 
> --Tim van der Leeuw
> tnleeuw@cs.vu.nl

You want to iterate over your window list.  Get the first window by calling
LMGetWindowList().  The link field in the window record is ->nextWindow. 
If you are just interested in visible windows, you can use FrontWindow()
instead of LMGetWindowList() and then check the ->visible field of all
subsequent windows in the list.  Do NOT use the aux record list.  There is
no guarantee that the link field in the aux record is an aux record of a
window you own.


//
// Accessor macros that will someday be replace by real window mgr APIs
//

#define	GetNextWindow(w)			(((WindowPeek) w)->nextWindow)	
#define IsWindowVisible(w)	(((WindowPeek) w)->visible)


DoSomethingWithMyWindows(Boolean onlyVisible)
{
		WindowRef	currentWindow;

	 currentWindow = LMGetWindowList();

		while (currentWindow != 0)
	 {
					if (!onlyVisible || ( IsWindowVisible(currentWindow) )
				 {		
							// do something with this window...
						 DoSomethingToOneWindow(currentWindow);
				 }

			  currentWindow = GetNextWindow(currentWindow);
	 }
}

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

>From h+@nada.kth.se (Jon W{tte)
Date: Wed, 14 Sep 1994 18:36:53 +0200
Organization: Royal Institute of Something or other

In article <Cw3HDs.2qx@actrix.gen.nz>,
cswan@actrix.gen.nz (Chris Swan) wrote:

>theWindow := FrontWindow;
>while theWindow <> nil do
>  begin
>   Do_Some_thing(with, theWindow);
>   theWindow:= windowPtr(windowPeek(theWindow)^.nextWindow);
>  end;

Close, but no cigar. FrontWindow() returns the first visible 
window, but the nextWindow pointer can return an invisible 
window.

	WindowPtr window = FrontWindow ( ) ;
	while ( window )
	{
		DoSomeThing ( window ) ;
		do {
			window = ( WindowPtr ) ( ( WindowPeek ) window ) -> 
				nextWindow ;
		} while ( window && ! ( ( WindowPeek ) window ) -> visible ) ;
	}

The Window Manager is desperately in need of a lot of accessor 
functions, by the way.

Cheers,

				/ h+


--
  Jon W�tte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden
 ~r ~/.signature


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

>From larson@oahu.cs.ucla.edu (Christopher Larson)
Date: Wed, 14 Sep 94 16:26:12 GMT
Organization: UCLA, Computer Science Department

In article <Cw3HDs.2qx@actrix.gen.nz> cswan@actrix.gen.nz (Chris Swan) writes:
>> : Can anyone describe the process used to get a list of all open windows
>> : within an application? I simply want to make an on the fly menu with
>
>> Once I had a similar problem, when I wanted to get a list of my windows
>> so I  [deleted - really complex answer] tting. 
>
>theWindow := FrontWindow;
              ^^^^^^^^^^^
>while theWindow <> nil do
>  begin
>   Do_Some_thing(with, theWindow);
>   theWindow:= windowPtr(windowPeek(theWindow)^.nextWindow);
>  end;
>
>Ref. Inside Macintosh Volume I

If memory serves, FrontWindow() returns the frontmost _visible_ window. You
may miss hidden windows this way. Try starting with the LM global WindowList.

--Chris
_______________________________________________________________________________
Chris Larson -- Amateur Macintosh Geek, CoBase Research Assistant
L.A. Institute of Slowly and Painfully Working Out the Surprisingly Obvious
Death to the Trojans! Go Bruins!

(Insert disclaimer here)
Internet: larson@kingston.cs.ucla.edu

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

>From tnleeuw@cs.vu.nl (Leeuw van der TN)
Date: Thu, 15 Sep 1994 11:36:45 GMT
Organization: Fac. Wiskunde & Informatica, VU, Amsterdam

cswan@actrix.gen.nz (Chris Swan) writes:
: > : Can anyone describe the process used to get a list of all open windows
: > : within an application? I simply want to make an on the fly menu with
: 
: > Once I had a similar problem, when I wanted to get a list of my windows
: > so I  [deleted - really complex answer] tting. 
: 
: theWindow := FrontWindow;
: while theWindow <> nil do
:   begin
:    Do_Some_thing(with, theWindow);
:    theWindow:= windowPtr(windowPeek(theWindow)^.nextWindow);
:   end;
I still don't understand how I could have overlooked that field. Really stupid,
actually. Sorry. Anyway, I understand that you can get the first window by
calling FrontWindow()? It's not the window that you first created?
: 
: Ref. Inside Macintosh Volume I
: 
: -- 
: Chris Swan
: cswan@actrix.gen.nz
: PO Box 11567, Wellington, New Zealand
: --
--Tim van der Leeuw
tnleeuw@cs.vu.nl

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

>From Jens Alfke <jens_alfke@powertalk.apple.com>
Date: Mon, 19 Sep 1994 20:35:15 GMT
Organization: Apple Computer

In article <34t0bp$jkt@netaxs.com> Dan Bradley, dbradley@Netaxs.com writes:
> Can anyone describe the process used to get a list of all open windows
> within an application?

Start with FrontWindow(), then follow the nextWindow fields in each
windowRecord. Note that WindowPtr is just another name for GrafPtr, so you
won't be able to access the extra WindowRecord fields through it. You have to
cast to WindowPeek (defined as a pointer to WindowRecord).

WindowPtr w;
for( w=FrontWindow(); w; w=(WindowPtr)((WindowPeek)w)->nextWindow )
    if( ((WindowPeek)w)->windowKind >= userKind )
        /*do something with w*/;

Note that this loop intentionally skips non-document windows like dialogs,
DAs and other system windows.

--Jens Alfke                           jens_alfke@powertalk.apple.com
                   "A man, a plan, a yam, a can of Spam ... Bananama!"

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

>From paitech@hntp2.hinet.net (paitech)
Subject: preloaded CODE resources in fat binaries
Date: 9 Sep 1994 08:28:52 GMT
Organization: NCTU News Server, HiNet

In the 68k world, we usually mark the resident CODE segments LOCKED and
PRELOADED, to avoid memory fragmentation.  But under the Power Macintosh
runtime architecture, these preloaded CODE segments just waste memory.

So how should I do to these CODE resources in the fat binaries?  Currently
I put the following piece of code at the beginning of my program, and it
looks ugly.  Are there any better methods?

    #ifdef __powerc
        for (short seg_idx = Count1Resources('CODE'); seg_idx > 0; --seg_idx)
        {   SetResLoad(false);
            Handle seg = Get1IndResource('CODE', seg_idx);
            SetResLoad(true);
            if (seg)
                ReleaseResource(seg);
        }
    #endif

Hao-yang Wang
Pai Technology, Inc.
Taipei

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

>From gurgle@dnai.com (Pete Gontier)
Date: Fri, 09 Sep 1994 12:48:15 -0800
Organization: Integer Poet Software

In article <34p6c4$jqo@serv.hinet.net>, paitech@hntp2.hinet.net (paitech) wrote:

> In the 68k world, we usually mark the resident CODE segments LOCKED and
> PRELOADED, to avoid memory fragmentation.  But under the Power Macintosh
> runtime architecture, these preloaded CODE segments just waste memory.
> So how should I do to these CODE resources in the fat binaries?  Currently
> I put the following piece of code at the beginning of my program...

[code to get and release code segments omitted]

Interesting problem. I realized you have a problem just the opposite of
the one I try to solve in my code, which is that pre-loaded segments don't
work the same when your app is not an app (i.e. when it's a TPM project).
See, in that case you have to go get the code segments yourself and lock
them low in the heap.

I think this is useful information for you because (1) it's an example of
someone else doing a disgusting hack against the CODE resources and pretty
much getting away with it, and (2) it provides you with code you might
want to use instead of marking your segments pre-loaded. That way, for the
PPC version, you can simply omit the code.

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

#if defined (THINK_C) || defined (applec)

//  Note selectivity of above compilers; under Metrowerks we
//  assume the linker has been set to merge the whole app into
//  one huge resource. Probably we should later include an
//  explicit check for this, but right now I am using the
//  CD ROM drive for music and can't look up the symbols. :-/

static OSErr MacLow_Init_LoadCODEs (void)
{
    OSErr oe = noErr;

    //  This code attempts to load all the code segments low in the heap and
    //  lock them down. If we're not running under TPM, this should have been
    //  done already for us by the fact that all the code resources should be
    //  marked pre-load and lock in the resource map. If we are, we need to
    //  take extra steps.
    //  
    //  First, we check to see if we are running under TPM. Since the TPM
    //  opens an external, non-CODE resource file on top of the project file,
    //  where the CODE resources live, we can search the top resource file for
    //  CODEs to find out if the TPM has done this. And an easy way to do this
    //  is Count1Resources.

    Boolean tpmRunning = false;
    short code = Count1Resources ('CODE');

    if (!(oe = ResError ( )) && !code)
    {
        //  OK, now we know we are running under TPM.
        //  We need to get the "real" count of the CODE resources.
        //  We can do this by searching beyond the current file,
        //  which will catch the CODEs in the project.

        tpmRunning = true;
        code = CountResources ('CODE');
        oe = ResError ( );
    }

    if (!oe)
    {
        //  Now index all of
        //  them and get their IDs without loading them, reserve
        //  space for them at the bottom of the heap, load them,
        //  and lock them.

        Handle      codeH;
        Size        size;
        short       id;
        ResType     type;
        Str255      name;

        if (code)
        {
            Boolean oldResLoad = LMGetResLoad ( );
            SetResLoad (false);

            do
            {
                if (tpmRunning)
                    codeH = GetIndResource ('CODE', code);
                else
                    codeH = Get1IndResource ('CODE', code);

                oe = ResError ( ); if (oe) break;
                GetResInfo (codeH, &id, &type, name);
                oe = ResError ( ); if (oe) break;

                //  Skip the jump table and the startup code.
                //  This should be more intelligent about how
                //  various linkers handle their startup code.
                //  It's presently set up for THINK, but may
                //  work in other cases.

                if (id != 0 && id != 1)
                {
                    size = GetResourceSizeOnDisk (codeH);
                    oe = ResError ( ); if (oe) break;
                    ReserveMem (size);
                    oe = MemError ( ); if (oe) break;
                    LoadResource (codeH);
                    oe = ResError ( ); if (oe) break;
                    HLock (codeH);
                    oe = MemError ( ); if (oe) break;
                    HNoPurge (codeH); // just for paranoia
                    oe = MemError ( ); if (oe) break;
                }
            }
            while (--code);

            SetResLoad (oldResLoad);
        }
    }

    return (oe);
}

#endif

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "The need to be (or appear to be) sophisticated pervades the very
 atmosphere in which we, the Magazine Reading Class, move."
                  -- Ellis Weiner, Spy Magazine, 9/94

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

>From paitech@hntp2.hinet.net (paitech)
Date: 10 Sep 1994 18:51:43 GMT
Organization: NCTU News Server, HiNet

Pete Gontier (gurgle@dnai.com) wrote:
: much getting away with it, and (2) it provides you with code you might
: want to use instead of marking your segments pre-loaded. That way, for the
: PPC version, you can simply omit the code.

But you still have to preload the main segment (i.e. CODE 1), right?

Hao-yang Wang
Pai Technology, Inc.
Taipei

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

>From gurgle@dnai.com (Pete Gontier)
Date: Sat, 10 Sep 1994 18:14:54 -0800
Organization: Integer Poet Software

In article <34sv7v$8hr@serv.hinet.net>, paitech@hntp2.hinet.net (paitech) wrote:

> Pete Gontier (gurgle@dnai.com) wrote:
> : much getting away with it, and (2) it provides you with code you might
> : want to use instead of marking your segments pre-loaded. That way, for the
> : PPC version, you can simply omit the code.
> 
> But you still have to preload the main segment (i.e. CODE 1), right?

I'm not terribly familiar with the PPC code model, so it's possible you
might have to do this, but I think it's always a pretty safe assumption
that if your code is running, CODE 1 loaded successfully. :-)

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "The need to be (or appear to be) sophisticated pervades the very
 atmosphere in which we, the Magazine Reading Class, move."
                  -- Ellis Weiner, Spy Magazine, 9/94

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

>From paitech@hntp2.hinet.net (paitech)
Date: 11 Sep 1994 08:50:52 GMT
Organization: NCTU News Server, HiNet

Pete Gontier (gurgle@dnai.com) wrote:
: > But you still have to preload the main segment (i.e. CODE 1), right?

: I'm not terribly familiar with the PPC code model, so it's possible you
: might have to do this, but I think it's always a pretty safe assumption
: that if your code is running, CODE 1 loaded successfully. :-)

Let me make my question clearer:

You suggested that instead of marking the resident segments PRELOADED, we can
also load them manually at runtime.  This is a good idea (It cannot be bad
because MacApp has done it in a similar way since 1.0.), but when your code is
executed (under 68k), the main segment is already loaded (into the middle of
the heap?) and it is already too late to reallocate the main segment.

So the main segment should still be marked as PRELOADED and we still have to
release it under PPC, right?

Hao-yang Wang
Pai Technology, Inc.
Taipei

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

>From h+@nada.kth.se (Jon W{tte)
Date: Sun, 11 Sep 1994 19:47:54 +0200
Organization: Royal Institute of Something or other

In article <34ugdc$pqk@serv.hinet.net>,
paitech@hntp2.hinet.net (paitech) wrote:

>You suggested that instead of marking the resident segments PRELOADED, we can
>also load them manually at runtime.  This is a good idea (It cannot be bad
>because MacApp has done it in a similar way since 1.0.), but when your code is
>executed (under 68k), the main segment is already loaded (into the middle of
>the heap?) and it is already too late to reallocate the main segment.

>So the main segment should still be marked as PRELOADED and we still have to
>release it under PPC, right?


No.

The Segment Loader loads CODE 0 and whatever's referenced by 
the first jump table entry for you. At this time, the heap is 
really small (MaxApplZone() hasn't been called) and there's 
nothing else in it (what would it be? No memory allocation's 
been done) so that CODE resource is loaded snugly in the heap; 
no fragmentation.

If your main() function is not in the same segment as the 
startup loader bootstrap (runtime library) you'll have a third 
CODE resource load before you get to the start of main, and 
still MaxApplZone() isn't called and no non-permanent memory is 
allocated to there's no chance of fragmentation.

So, don't mark CODE 0 or CODE 1 (or ANY CODE) preloaded for a 
fat binary.

OR special-case for PPC to get all CODE resources and release 
them :-) :-) :-)

Cheers,

				/ h+


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

   Nothing crashes like a Macintosh.
                     -- Guy Kawasaki


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

>From paitech@hntp2.hinet.net (paitech)
Date: 12 Sep 1994 13:55:17 GMT
Organization: NCTU News Server, HiNet

Jon W{tte (h+@nada.kth.se) wrote:
: The Segment Loader loads CODE 0 and whatever's referenced by 
: the first jump table entry for you. At this time, the heap is 
: really small (MaxApplZone() hasn't been called) and there's 
: nothing else in it (what would it be? No memory allocation's 
: been done) so that CODE resource is loaded snugly in the heap; 
: no fragmentation.

There is still fragmentation.  You can break into Macsbug and check for it
yourself.  It is not caused by other memory allocations, but by the MiveHHi()
call (made by the Segment Loader).  However, the heap is really small at this
time, so the memory loss caused by this fragmentation may be no more than
several kilo bytes.  We may just ignore this fragmentation.

: So, don't mark CODE 0 or CODE 1 (or ANY CODE) preloaded for a 
: fat binary.

In CodeWarrior, this is easy.  In MPW, you may need to write a rez script for
this post-link process.  I don't know an easy way to clear the preloaded bit
under the Symantec environment.

Another related problem is the SIZE resource.  On one hand, under the PPC
runtime environment the code does not take up the application heap, on the
other hand, the PPC stack size is usually larger than the 68k one.  Anyway,
if the memory requirements for PPC and 68k are different, how can one SIZE
fit for both?

I am writing a fat 'appe', and the SIZE resource becomes a problem, because
1) users cannot change the memory partition in the "Get Info..." Finder
   dialog for the 'appe';
2) the 'appe' will always resident in background and take up memory, so I
   cannot throw away hundreds of kilo bytes here and there, as I used to do.

Maybe I should put an INIT resource into the  the appe file, to adjust the
SIZE resource dynamically at the startup time, according to the current
machine architecture.  But I think I have used up all my quota on dirty
tricks this year. :-)

Hao-yang Wang
Pai Technology, Inc.
Taipei

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

>From gurgle@dnai.com (Pete Gontier)
Date: Mon, 12 Sep 1994 10:22:25 -0800
Organization: Integer Poet Software

In article <351mk5$sus@serv.hinet.net>, paitech@hntp2.hinet.net (paitech) wrote:

> There is still fragmentation.  You can break into Macsbug and check for it
> yourself.  It is not caused by other memory allocations, but by the MiveHHi()
> call (made by the Segment Loader).  However, the heap is really small at this
> time, so the memory loss caused by this fragmentation may be no more than
> several kilo bytes.  We may just ignore this fragmentation.

Ah. After some twiddling of my own current project, I see what you are
getting at. For various technical reasons, I was not running into the
problem. My code was only intended to get around the tricky resource fork
problem in the TPM. The real solution for 68K is to have all your code
segments locked and pre-loaded, which is fine, because my TPM solution
knows whether it's running under TPM and bails out if not.

But you still have a problem -- how to make the 68K code all load and stay
loaded without fragmenting the heap while at the same time *not* loading
when the PPC code runs. Making sure the 68K code does not waste RAM while
the PPC code is running not only requires you to get and release the CODE
resources but *also* costs you startup time, because those resources take
some non-zero time to be read in from the disk, even when running under
PPC.

As you say, though, the heap is really small at that time, and you might
just want to sacrifice the wasted space to the gods of convenience.
Anyway, I will think about this some more as a mental background process,
for whatever that's worth. :-)

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "The need to be (or appear to be) sophisticated pervades the very
 atmosphere in which we, the Magazine Reading Class, move."
                  -- Ellis Weiner, Spy Magazine, 9/94

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

>From wdh@fresh.com (Bill Hofmann)
Date: Mon, 12 Sep 1994 17:36:24 GMT
Organization: Fresh Software

In article <34ugdc$pqk@serv.hinet.net>, paitech@hntp2.hinet.net (paitech) wrote:

> Let me make my question clearer:
> 
> You suggested that instead of marking the resident segments PRELOADED, we can
> also load them manually at runtime.  This is a good idea (It cannot be bad
> because MacApp has done it in a similar way since 1.0.), but when your code is
> executed (under 68k), the main segment is already loaded (into the middle of
> the heap?) and it is already too late to reallocate the main segment.
> 
> So the main segment should still be marked as PRELOADED and we still have to
> release it under PPC, right?
> 
> Hao-yang Wang
> Pai Technology, Inc.
> Taipei
No.  The system loads CODE 1 (and CODE 0) itself in the process of launching your application if it's a 68k app.  You really don't have to mark any resources preload except your error reporting resources (DLOG or ALRT, DITL, STRs or STR#s, etc).  You don't have to mark CODE 1 preload.
-- 
Bill Hofmann                                   wdh@fresh.com
Fresh Software and Instructional Design        voice: +1 510 524 0852
1640 San Pablo Ave #C Berkeley CA 94702 USA    fax:   +1 510 524 0853

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

>From gurgle@dnai.com (Pete Gontier)
Date: Mon, 12 Sep 1994 12:20:17 -0800
Organization: Integer Poet Software

In article <wdh-1209941036240001@wdh.slip.netcom.com>, wdh@fresh.com (Bill
Hofmann) wrote:

> You really don't have to mark any resources 
> preload except your error reporting resources
> (DLOG or ALRT, DITL, STRs or STR#s, etc).

I think perhaps you are missing the idea that he *wants* to pre-load all
his code resources so that he doesn't have to worry about the memory
management issues associated with code segments loading and unloading via
Segment Loader and the jump table. It's not that he thinks he must; he's
choosing to do so in order to make his memory management simpler. This is
not optimal in terms of memory usage, but code takes up a surprisingly
small amount of relative space in some apps, and making sure it's all
always loaded can simplify QA a lot.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "The need to be (or appear to be) sophisticated pervades the very
 atmosphere in which we, the Magazine Reading Class, move."
                  -- Ellis Weiner, Spy Magazine, 9/94

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

>From gurgle@dnai.com (Pete Gontier)
Date: Mon, 12 Sep 1994 12:25:50 -0800
Organization: Integer Poet Software

In article <wdh-1209941036240001@wdh.slip.netcom.com>, wdh@fresh.com (Bill
Hofmann) wrote:

> The system loads CODE 1 (and CODE 0) itself in the process of
> launching your application if it's a 68k app... You don't have to mark
> CODE 1 preload.

I forgot to note something else:

Most development systems automatically mark CODE 1 as pre-loaded. This has
the effect of forcing the segment into the lowest possible position in the
heap as soon as the app's resource file is opened. (Ordinarily this is a
good thing, because CODE 1 tends to do things like patch ExitToShell, and
you don't want it moving around.) It may be that under some systems the
process manager does the right thing to make sure this happens anyway, but
since most development systems mark CODE 1 as pre-loaded regardless, it's
still a good idea to figure out how to deal with it under PowerPC in a fat
binary situation.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "The need to be (or appear to be) sophisticated pervades the very
 atmosphere in which we, the Magazine Reading Class, move."
                  -- Ellis Weiner, Spy Magazine, 9/94
>From Pete.Gontier@f1.n100.z60.wlink.nl (Pete Gontier)
Subject: preloaded CODE resources in fat binaries
Date: Mon, 12 Sep 1994 14:25:50 -0100
Organization: (none)


In article <wdh-1209941036240001@wdh.slip.netcom.com>, wdh@fresh.com (Bill
Hofmann) wrote:

> The system loads CODE 1 (and CODE 0) itself in the process of
> launching your application if it's a 68k app... You don't have to mark
> CODE 1 preload.

I forgot to note s




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

>From wdh@fresh.com (Bill Hofmann)
Date: Thu, 15 Sep 1994 17:18:00 GMT
Organization: Fresh Software

In article <gurgle-1209941220170001@dynamic-210.dnai.com>, gurgle@dnai.com
(Pete Gontier) wrote:
> I think perhaps you are missing the idea that he *wants* to pre-load all
> his code resources so that he doesn't have to worry about the memory
> management issues associated with code segments loading and unloading via
> Segment Loader and the jump table. It's not that he thinks he must....
Well, no, I didn't miss it, but his question seemed to indicate that he thought that he *had* to.  If he's still listening, I'd suggest something like this:

#ifndef powerc
    <preload code resources>
#endif

That'll do it.  But preloading and other memory management things should be done at the end of the development process, when you can spend a lot of time staring at Macsbug heap displays.   I hold that nowadays it's much less of an issue than it was 8 years ago.
-- 
Bill Hofmann                                   wdh@fresh.com
Fresh Software and Instructional Design        voice: +1 510 524 0852
1640 San Pablo Ave #C Berkeley CA 94702 USA    fax:   +1 510 524 0853

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

>From gurgle@dnai.com (Pete Gontier)
Date: Fri, 16 Sep 1994 10:25:41 -0800
Organization: Integer Poet Software

In article <wdh-1509941018000001@wdh.slip.netcom.com>, wdh@fresh.com (Bill
Hofmann) wrote:

> #ifndef powerc
>     <preload code resources>
> #endif

He can do that, but if he does, CODE 1 and the segment which contains
'main' and the segment which contains the code which loads the rest of the
segments may already have been loaded in a sub-optimal place. (In fact,
they are almost guranteed to have been.) He wants a solution which (a)
doesn't require him to worry about what code goes where, and (b) doesn't
create any heap islands. The traditional solution of marking all the code
segments pre-loaded and locked doesn't, of course, work under PPC in a fat
binary because the code segments should *never* be loaded in that case.
That's why this is such a vexing problem.

> But preloading and other memory management things should be done at the end
> of the development process, when you can spend a lot of time...

That's precisely when when you *cannot* spend a lot of time! :-) Anyway, I
think if you are going to adopt the policy of not messing with the segment
loader at all, it's prudent to make that part of the program work right up
front. You should see the colors my face turns when I'm trying to debug
one crash and another crash happens because of something like a segment
loader error. :-)

> I hold that nowadays it's much less of an issue than it was 8 years ago.

Right. That's why he wants to dispense with that pesky Segment Loader.

-- 

 Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com

 "I saw John Norstad with Elvis! And they were varnishing waffles!"
      -- Peter Cohen <flargh@tiac.net>

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

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