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 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@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 --------------------------- >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@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@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@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 +++++++++++++++++++++++++++ >From gurgle@dnai.com (Pete Gontier) Date: Fri, 16 Sep 1994 10:42:28 -0800 Organization: Integer Poet Software In article , 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 +++++++++++++++++++++++++++ >From ferrari@netaxs.com (Darrell Turner) Date: Fri, 16 Sep 1994 23:14:48 -0500 Organization: Haha, None here In article , gurgle@dnai.com (Pete Gontier) wrote: > In article , > 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@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 +++++++++++++++++++++++++++ >From ferrari@netaxs.com (Darrell Turner) Date: Sat, 17 Sep 1994 11:46:49 -0500 Organization: Haha, None here In article , 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@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 - 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 Date: 14 Sep 1994 20:38:12 GMT Organization: Kaleida Labs, Inc. In article 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 <) { 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 - 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@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@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 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 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@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@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 - 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 - 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 , 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 , 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 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 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@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@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@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@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 #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@fresh.com (Bill Hofmann) wrote: > #ifndef powerc > > #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 --------------------------- End of C.S.M.P. Digest **********************