From: pottier@clipper.ens.fr (Francois Pottier) Subject: csmp-digest-v3-056 Date: Sat, 10 Sep 1994 13:05:29 +0200 (MET DST) C.S.M.P. Digest Sat, 10 Sep 94 Volume 3 : Issue 56 Today's Topics: A tool I could REALLY use, written it? Async FileMgr Calls Future of ASLM Review of PowerMac devtools available SetDialogDefaultItem() not doing anything! Trouble making floating windows work with modeless dialogs The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier (pottier@clipper.ens.fr). The digest is a collection of article threads from the internet newsgroup comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi- regularly and want an archive of the discussions. If you don't know what a newsgroup is, you probably don't have access to it. Ask your systems administrator(s) for details. If you don't have access to news, you may still be able to post messages to the group by using a mail server like anon.penet.fi (mail help@anon.penet.fi for more information). Each issue of the digest contains one or more sets of articles (called threads), with each set corresponding to a 'discussion' of a particular subject. The articles are not edited; all articles included in this digest are in their original posted form (as received by our news server at nef.ens.fr). Article threads are not added to the digest until the last article added to the thread is at least two weeks old (this is to ensure that the thread is dead before adding it to the digest). Article threads that consist of only one message are generally not included in the digest. The digest is officially distributed by two means, by email and ftp. If you want to receive the digest by mail, send email to listserv@ens.fr with no subject and one of the following commands as body: help Sends you a summary of commands subscribe csmp-digest Your Name Adds you to the mailing list signoff csmp-digest Removes you from the list Once you have subscribed, you will automatically receive each new issue as it is created. The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest. Questions related to the ftp site should be directed to scott.silver@dartmouth.edu. Currently no previous volumes of the CSMP digest are available there. Also, the digests are available to WAIS users. To search back issues with WAIS, use comp.sys.mac.programmer.src. With Mosaic, use http://www.wais.com/wais-dbs/comp.sys.mac.programmer.html. ------------------------------------------------------- >From Chris Russo Subject: A tool I could REALLY use, written it? Date: 24 Aug 1994 16:57:56 GMT Organization: Sonic Systems, Inc. While tracking down a nasty memory leak yesterday, I thought of something that would have been REALLY helpful. What if I patched NewHandle() so that whenever it was called it would traipse over to the end of my routine and grab the Debugger info, then tacked it onto the rear of the handle? That way, I could look at all of those loose memory fragments from ZoneRanger and determine instantly from where they had been allocated. I started working on the thing yesterday, and spent a couple of hours on it. I wrote patches for NewHandle(), GetHandleSize(), and SetHandleSize(). Those last two would naturally have to be patched to make the debugging info transparent to the calling application. Unfortunately, the routines aren't quite working and tend to crash. More unfortunately, I don't have the time to keep working on them. :-( If anyone's already written such a patch, please let me know how it went and if I could have it. If anyone would like to take this idea and run with it, by all means do so. You can even have the source that I started. There might be some issues involving the application's trap dispatch table that I'm not dealing with properly. I've never really taken the time to learn that much about it, but would be happy to learn where I went awry. btw, I have seen the leaks dcmd and don't really like to use it much. From ZoneRanger, I can usually tell which memory blocks are useless, but it's hard to correlate those to the ones captured in leaks. On top of that, leaks crashes my version of TMON. Once again, if anyone wants to continue my effort, let me know. - ------------------------------------------------------------------------ Chris Russo Macintosh Programmer Sonic Systems, Inc. (408) 736-1900 #107 chris@sonicsys.com NEVER respond to flame bait! +++++++++++++++++++++++++++ >From onyxtech@aol.com (OnyxTech) Date: 26 Aug 1994 17:43:03 -0400 Organization: America Online, Inc. (1-800-827-6364) In article <33fu6k$f5s@news.internex.net>, Chris Russo writes: >While tracking down a nasty memory leak yesterday, I thought of >something that would have been REALLY helpful. What if I patched >NewHandle() so that whenever it was called it would traipse over to >the end of my routine and grab the Debugger info, then tacked it onto >the rear of the handle? >That way, I could look at all of those loose memory fragments from >ZoneRanger and determine instantly from where they had been allocated. Mmmm. There is a version of QC(tm) that has similar leaks detection (you can use sym files as well) that will follow a native PowerPC upgrade ahead of it in the pipeline. We are working on graphical representation of heap allocations and deletions and hope to create some sort of published interface so tools like ZoneRanger can use our data to represent more information to users. After all, why should we re-create ZoneRanger type utilities when they've already done all the work. We just need to help them get at more information. If you'd like me to keep you (and whomever else is reading this) abreast of this new version of QC, drop us a line at 'onyxtech@aol.com'. dEVoN Hubbard Onyx Technology +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Sat, 27 Aug 1994 15:52:17 +0200 Organization: Royal Institute of Something or other In article <33fu6k$f5s@news.internex.net>, Chris Russo wrote: >While tracking down a nasty memory leak yesterday, I thought of something that >would have been REALLY helpful. What if I patched NewHandle() so that >whenever it was called it would traipse over to the end of my routine and grab >the Debugger info, then tacked it onto the rear of the handle? > >That way, I could look at all of those loose memory fragments from ZoneRanger >and determine instantly from where they had been allocated. It's easier to just install the "leaks" MacsBug dcmd. I don't know whether it will still work with the new memroy manager though. Anyone else know? Another thing you can do is to replace all your calls to NewHandle() etc with MyNewHandle() and have non-patches that did the tracking work; you could even define MyNewHandle to pass source file and line number information using __FILE__ and __LINE__. Then when you compile the release version, you just define MyNewHandle() to NewHandle(). This is great for validating memory as well; you can have a validation routine that traverses all of your dynamically allocated memory and checks it against a list you keep; if something's not checked on the list, you have a leak. If a pointer/handle is not on the list, you have a dangling pointer/handle. Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden Not speaking for IBM. --------------------------- >From chris-b@cs.auckland.ac.nz (Chris Burns) Subject: Async FileMgr Calls Date: Sat, 20 Aug 1994 00:58:02 +1200 Organization: AucklandUniversity:ComputerScience:HMU Hi All, I've been looking into using async file manager calls, so I started experimenting with an easy one, an indexed _PBHGetVInfoAsync call until the error returned is nsvErr (no-such-volume: -35). This works perfectly using sync calls. Things aren't so rosy on the async front tho'. Being in a PowerPC friendly kind of mood (and running on a PM8100/80), I thought "cool, I'll use UPPs for my completion routine specifiers, and compile a fat app". This aspect is fine, and in fact, the PowerPC native version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The 68K version however, does not work. The _PBHGetVInfoAsync call returns all kinds of bogus values instead of nice file manager errors. Here's the entire code: //////////////////////////////////////////// // Chris Burns ©August 1994 //////////////////////////////////////////// #include //////////////////////////////////////////// typedef struct { HVolumeParam PB; Str255 VolName; long AppA5; } VolPBRec,*VolPBPtr; //////////////////////////////////////////// short gNumDrives; volatile short gNumDrivesDone; //////////////////////////////////////////// IOCompletionUPP gCompletionProcUPP; #if USES68KINLINES #pragma parameter CompletionProc(__A0) #endif pascal void CompletionProc(HParmBlkPtr HPB) { long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5); gNumDrivesDone++; DebugStr(((VolPBPtr)HPB)->VolName); SetA5(SavedA5); } //////////////////////////////////////////// void main(void) { OSErr Err; VolPBPtr VPB; gNumDrives = 0; gNumDrivesDone = 0; gCompletionProcUPP = NewIOCompletionProc(CompletionProc); Err = noErr; while (Err != nsvErr) { gNumDrives++; VPB = (VolPBPtr)NewPtrClear(sizeof(VolPBRec)); if ((VPB == nil) || (MemError() != noErr)) DebugStr("\pMain: _NewPtrClear(VPB) FAILED"); VPB->PB.ioCompletion = gCompletionProcUPP; VPB->PB.ioVolIndex = gNumDrives; VPB->PB.ioNamePtr = VPB->VolName; VPB->PB.ioVRefNum = 0; VPB->AppA5 = SetCurrentA5(); Err = PBHGetVInfoAsync((HParmBlkPtr)VPB); switch (Err) { case noErr: break; case nsvErr: continue; default: DebugStr("\p_PBHGetVInfoAsync FAILED"); break; } } while (gNumDrivesDone != gNumDrives); DisposeRoutineDescriptor(gCompletionProcUPP); } //////////////////////////////////////////// The: #if USES68KINLINES #pragma parameter CompletionProc(__A0) #endif bit was necessary for the 68K version to realize the param block ptr was in A0 rather than on the stack. I just grabbed it from one of the Universal Headers because it looked right. It seems to work, and the asm looks right. The problem seems to be in my CompletionProc. Whatever value D0.w is upon exit, comes out as the original Err = PBHGetVInfoAsync(); This shouldn't be so because that error simply tells me if the request was queued ok. For file manager completion routines THINK Ref 2.0 says "Save and restore all CPU registers except A0,A1, and D0-D2". My code seems to do this yet doesn't run correctly. Here's the 68K asm: Hunk: Kind=HUNK_GLOBAL_CODE Name="COMPLETIONPROC"(4) Size=64 00000000: 4E56 FFF8 LINK A6,#$FFF8 00000004: 2D48 FFF8 MOVE.L A0,$FFF8(A6) 00000008: 206E FFF8 MOVEA.L $FFF8(A6),A0 0000000C: 2028 017A MOVE.L $017A(A0),D0 00000010: C18D EXG D0,A5 00000012: 2D40 FFFC MOVE.L D0,$FFFC(A6) 00000016: 526D 0000 ADDQ.W #$1,gNumDrivesDone 0000001A: 206E FFF8 MOVEA.L $FFF8(A6),A0 0000001E: 4868 007A PEA $007A(A0) 00000022: ABFF _DebugStr 00000024: 202E FFFC MOVE.L $FFFC(A6),D0 00000028: C18D EXG D0,A5 0000002A: 4E5E UNLK A6 0000002C: 4E75 RTS 0000002E: 8E43 4F4D 504C DC.B $80+$0E, 'COMPLETIONPROC', $00 4554 494F 4E50 524F 4300 0000003E: 0000 Any help, flames, guidance etc greatly appreciated. Thanks In Advance, Chris B - --------------------------------------------------------------------- NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns Internet: chris-b@cs.auckland.ac.nz Phone: +64 9 373-7599 x6194 Fax: +64 9 373-7453 Async, therefore I am. - --------------------------------------------------------------------- +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Fri, 19 Aug 1994 22:27:16 +0200 Organization: Royal Institute of Something or other In article , chris-b@cs.auckland.ac.nz (Chris Burns) wrote: >version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The >68K version however, does not work. The _PBHGetVInfoAsync call returns all >kinds of bogus values instead of nice file manager errors. That's because you're testing the return value of an asynchronous call. You're not supposed to do that, since there's no error to return there yet; instead you're supposed to test ioResult in the completion proc, or poll ioResult until it's not 1. Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden "TextEdit does everything right." ‹ Jon W{tte +++++++++++++++++++++++++++ >From chris-b@cs.auckland.ac.nz (Chris Burns) Date: Sun, 21 Aug 1994 18:19:12 +1200 Organization: AucklandUniversity:ComputerScience:HMU In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon W{tte) wrote: > In article , > chris-b@cs.auckland.ac.nz (Chris Burns) wrote: > > >version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The > >68K version however, does not work. The _PBHGetVInfoAsync call returns all > >kinds of bogus values instead of nice file manager errors. > > That's because you're testing the return value of an asynchronous > call. You're not supposed to do that, since there's no error to > return there yet; instead you're supposed to test ioResult in the > completion proc, or poll ioResult until it's not 1. Sorry Jon, I don't buy it. (I'm assuming that IM-IV Chpt 19 [File Manager] is still valid because it documents the low-level file manager routines; I havn't looked at NIM:Files) Check out IM-IV Pg 119: "Routines that are executed asynchronously return control to the calling program with the result code noErr as soon as the call is placed in the file I/O queue. This isn't an indication of successful call completion, but simply indicates that the call was successfully queued." This is the case with nearly all async calls, they return a file manager error to the calling program (typically "noErr", but possibly "paramErr" or others), and then the real error somewhere in the param block (often also in D0) at completion proc time. These two errors should not be related in any way. The fact that D0 = $stuvwxyz upon exit of the completion proc should not mean that the calling code receives an error of $wxyz (D0.w). IM-IV Pg 119: "Warning: Completion routines are executed at interrupt level and must preserve all registers other than A0,A1, and D0-D2." Surely this means my completion routine code can do what it wants with these regs without affecting anything. IM-IV Pg 119: "When your completion routine is called, register A0 points to the parameter block of the asynchronous call and register D0 contains the result code." I read this to mean that these were "read-only" values (changes are not propagated back to calling code). I based this upon the fact that the completion proc may be called _well_ after the _PBHGetVInfo call. A remote file system such as an AppleShare volume will definitely be this way for mnay types of calls. I have kind-of solved this problem, but not to my satisfaction. If I save and restore the scratch regs (A0,A1, and D0-D2) the thing works properly. However, I don't think I should need to do this, and besides, its real ugly. #if USES68KINLINES asm.... #endif yuck! Any more ideas would be wonderful. Thanks Heaps In Advance, Chris B - --------------------------------------------------------------------- NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns Internet: chris-b@cs.auckland.ac.nz Phone: +64 9 373-7599 x6194 Fax: +64 9 373-7453 Async, therefore I am. - --------------------------------------------------------------------- +++++++++++++++++++++++++++ >From Jaeger@fquest.com (Brian Stern) Date: 21 Aug 1994 14:39:41 GMT Organization: The University of Texas at Austin, Austin, Texas In article , chris-b@cs.auckland.ac.nz wrote: > Hi All, > > I've been looking into using async file manager calls, so I started > experimenting with an easy one, an indexed _PBHGetVInfoAsync call until > the error returned is nsvErr (no-such-volume: -35). This works perfectly > using sync calls. Things aren't so rosy on the async front tho'. > > Being in a PowerPC friendly kind of mood (and running on a PM8100/80), I > thought "cool, I'll use UPPs for my completion routine specifiers, and > compile a fat app". This aspect is fine, and in fact, the PowerPC native > version (MW C/C++ PPC 1.01 DR/3.5) is the one that works correctly. The > 68K version however, does not work. The _PBHGetVInfoAsync call returns all > kinds of bogus values instead of nice file manager errors. > > Here's the entire code: > #if USES68KINLINES > #pragma parameter CompletionProc(__A0) > #endif > > pascal void CompletionProc(HParmBlkPtr HPB) > { > long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5); > > gNumDrivesDone++; > DebugStr(((VolPBPtr)HPB)->VolName); > > SetA5(SavedA5); > } > Chris B > ----------------------------------------------------------------------- > NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns > Internet: chris-b@cs.auckland.ac.nz > Phone: +64 9 373-7599 x6194 > Fax: +64 9 373-7453 Async, therefore I am. > ----------------------------------------------------------------------- So why not change it to this: #if USES68KINLINES #pragma parameter __D0 CompletionProc(__A0) #endif pascal OSErr CompletionProc(HParmBlkPtr HPB) { long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5); gNumDrivesDone++; DebugStr(((VolPBPtr)HPB)->VolName); SetA5(SavedA5); return HPB->ioResult; } No Assembly Required. My reading of the passages in IM-IV that you quoted seems ambiguous about whether or not a completion routine returns a result in DO. My first guess would have been no. BTW, Use of the #pragma parameter in this way in MW works differently from Think C. In Think you can only use #pragma parameter for inline calls. This means that it's only useful for routines that you're calling, not for cases where your routines are called with parameters in registers. So when compiling your CompletionProc with Think C, the compiler ignores the #pragma parameter and assumes that HPB was passed on the stack. Oh well :-( -- Brian Stern :-{)} Jaeger@fquest.com +++++++++++++++++++++++++++ >From resnick@uiuc.edu (Pete Resnick) Date: Sun, 21 Aug 1994 13:02:57 -0500 Organization: University of Illinois at Urbana-Champaign In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon W{tte) wrote: >That's because you're testing the return value of an asynchronous >call. You're not supposed to do that, since there's no error to >return there yet; instead you're supposed to test ioResult in the >completion proc, or poll ioResult until it's not 1. No, you're wrong. Inside Macintosh: Files, page 2-6 is quite explicit: Routines that are executed asynchronously return control to your application with the result code noErr as soon as the call is placed in the file I/O queue. Return of control does not signal successful completion of the call, but simply successful queuing of the request. You could plausibly get back an error if for some reason the Device Manager determined that the call could not be queued (a screwy refNum or the like). You are perfectly correct (though maybe using a little overkill) in checking the return code from an asynchronous routine. The problem lies somewhere else. pr -- Pete Resnick (...so what is a mojo, and why would one be rising?) Doctoral Student - Philosophy Department, Gregory Hall, UIUC System manager - Cognitive Science Group, Beckman Institute, UIUC Internet: resnick@uiuc.edu +++++++++++++++++++++++++++ >From benh@fdn.org (Benjamin Herrenschmidt) Date: Mon, 22 Aug 94 11:52:45 +0100 Organization: (none) >>That's because you're testing the return value of an asynchronous >>call. You're not supposed to do that, since there's no error to >>return there yet; instead you're supposed to test ioResult in the >>completion proc, or poll ioResult until it's not 1. > >No, you're wrong. Inside Macintosh: Files, page 2-6 is quite explicit: > > Routines that are executed asynchronously return control to your > application with the result code noErr as soon as the call is placed in > the file I/O queue. Return of control does not signal successful > completion of the call, but simply successful queuing of the request. > >You could plausibly get back an error if for some reason the Device >Manager determined that the call could not be queued (a screwy refNum or >the like). You are perfectly correct (though maybe using a little >overkill) in checking the return code from an asynchronous routine. The >problem lies somewhere else. I remember something about async File Mgr. calls : unlike device manager calls, File Manager calls ALWAYS calls the completion routine to handle the result code, and the result of the async call itself MAY be garbage, event if something is wrong with the queue. The result code you should use is the one returned to the completion routine (or in the ioResult field of the paramblock) I think i read this in a technote or a Q&A... BenH. +++++++++++++++++++++++++++ >From ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) Date: 23 Aug 94 18:05:13 +1200 Organization: University of Waikato, Hamilton, New Zealand In article , chris-b@cs.auckland.ac.nz (Chris Burns) writes: > In article <9668AA7AE244.44E5E@klkmac004.nada.kth.se>, h+@nada.kth.se (Jon > W{tte) wrote: > >> In article , >> chris-b@cs.auckland.ac.nz (Chris Burns) wrote: >> >> That's because you're testing the return value of an asynchronous >> call. You're not supposed to do that, since there's no error to >> return there yet; instead you're supposed to test ioResult in the >> completion proc, or poll ioResult until it's not 1. > > Sorry Jon, I don't buy it. > > (I'm assuming that IM-IV Chpt 19 [File Manager] is still valid because it > documents the low-level file manager routines; I havn't looked at > NIM:Files) > > Check out IM-IV Pg 119: > > "Routines that are executed asynchronously return control to the calling > program with the result code noErr as soon as the call is placed in the > file I/O queue. This isn't an indication of successful call completion, > but simply indicates that the call was successfully queued." There is a technote somewhere which corrects this. Basically, you shouldn't bother checking the immediate return code from _any_ async call. I recently got burned with this doing async sound recording: my call to SPBRecord worked fine everywhere _except_ on a 500-series PowerBook, and then only when I invoked a combination of certain other recording options at the same time. There is one situation where you should be careful about polling ioResult (And I'm not talking about being stupid, sitting in a tight loop at interrupt level, blocking the completion of the call you're polling for!): the PPC Toolbox. In System 7.0, the PPC Toolbox sets ioResult some time before it dequeues the parameter block from its request queue. This means if you have an interrupt routine that periodically checks the ioResult from a PPC Toolbox request, and assumes the parameter block can be reused the moment it goes 0 or negative, you could be in for a crash. If you specify a completion routine, then the parameter block can be safely reused when this routine is called. I understand this might be fixed in later Systems, but I'm not sure which ones. If Jim Luther is reading this, he might be able to update us... Lawrence D'Oliveiro fone: +64-7-856-2889 Info & Tech Services Division fax: +64-7-838-4066 University of Waikato electric mail: ldo@waikato.ac.nz Hamilton, New Zealand 37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00 +++++++++++++++++++++++++++ >From chris-b@cs.auckland.ac.nz (Chris Burns) Date: Wed, 24 Aug 1994 12:47:36 +1200 Organization: AucklandUniversity:ComputerScience:HMU In article , Jaeger@fquest.com (Brian Stern) wrote: > So why not change it to this: > > #if USES68KINLINES > #pragma parameter __D0 CompletionProc(__A0) > #endif > > pascal OSErr CompletionProc(HParmBlkPtr HPB) > { > long SavedA5 = SetA5(((VolPBPtr)HPB)->AppA5); > > gNumDrivesDone++; > DebugStr(((VolPBPtr)HPB)->VolName); > > SetA5(SavedA5); > > return HPB->ioResult; > > } > > No Assembly Required. Yeah, good idea Brian. This actually works on both platforms and does not use any asm. Thanks for the idea, I'll end up using this. It should not be required tho'. Apple docs clearly state that D0 doesn't have to be save/restored and don't say the error should be returned in D0 either (in fact this cannot be the case because the completion proc could potentially execute _well after_ the original error has been returned. Maybe this call cannot be done truely async? Thanks Again, Chris B - --------------------------------------------------------------------- NewZealand:AucklandUniversity:ComputerScience:HyperMediaUnit:ChrisBurns Internet: chris-b@cs.auckland.ac.nz Phone: +64 9 373-7599 x6194 Fax: +64 9 373-7453 Async, therefore I am. - --------------------------------------------------------------------- +++++++++++++++++++++++++++ >From Clinton Bauder Date: Wed, 24 Aug 1994 21:02:10 GMT Organization: Apple Computer Inc. In article Chris Burns, chris-b@cs.auckland.ac.nz writes: > > Err = PBHGetVInfoAsync((HParmBlkPtr)VPB); > > switch (Err) > { > case noErr: > break; > > case nsvErr: > continue; > > default: > DebugStr("\p_PBHGetVInfoAsync FAILED"); > break; > } If you are making an async call you have to wait for it to complete. A return of noErr from an async call doesn't mean it is done. I merely means the PB was correctly filled out and has been accepted (queued) by the File Mananger. At some later point it will be completed and the ioResult field will be updated with the correct result and the completion routine called. Your application needs to either poll ioResult (wait til it is not 1 - which means in progress) or poll some other variable which is set by the completion routine. To really take advantage of async IO you should try and do something with the time in between when you make the file system call and when ioResult changes to <= noErr. Clinton - ------------------------------------------------------------- Clinton Bauder | Opinions expressed are very likely to SCSI Grunt and Chief | be entirely different from the official Herpetoculturist | party line of Apple Computer Inc. Apple Computer Inc. | Support your local herp society. - ------------------------------------------------------------- +++++++++++++++++++++++++++ >From jumplong@aol.com (Jump Long) Date: 26 Aug 1994 01:42:07 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , chris-b@cs.auckland.ac.nz (Chris Burns) writes: >Any more ideas would be wonderful. I responded to Chris via email with this: - --- Chris, You need to get a copy of develop magazine issue #13 and read the article I wrote called "Asynchronous Routines on the Macintosh". It answers many of your current questions and will answer many of the questions you're going to have in the future :-) In many cases while writing that article, I found that Inside Mac was either wrong, or just didn't describe things completely. Here's some specific information for what you observed. 1) If the File Manager isn't busy when it receives a request (asynchronous or synchronous), it doesn't queue it - it begins execution of the request immediately. If the File Manager is busy handling another request, *then* the request is queued until the all requests before it in the queue have executed. If the request is a synchronous request, then the system spins in SyncWait waiting for the synchronous request to be executed. If the request is an asynchronous request and it is queued, then control is returned to the caller after the request is queued 2) When the current request is finished executing and the File Manager has called its completion routine, the File Manager begins excution of the next request in the queue (if any). 3) Once the File Manager starts executing an asynchronous request, it doesn't give up control until it is either: a) done handling the request or b) makes an asynchronous request to a device driver to read or write block(s) of data and the device driver returns control to the File Manager while it handles the request asynchronously. The part "while it handles the request asynchronously" is important because if the driver handles all requests synchronously (like the old SCSI Manager does), then the File Manager doesn't get control back from the driver call until it has completed, and in that case, the File Manager continues with the execution of the request. So, when you call PBHGetVInfoAsync, if the File Manager isn't busy, it starts execution of the request immediately. Since GetVInfo requests don't cause calls to the driver (unless you pass a working directory number instead of real volume reference number), there is nothing to stop the File Manager from completing the request. That's why you're seeing the request complete immediately. The reason you're seeing the 5 you slam into DO in the completion routine is that the File Manager uses D0 to return function results to *synchronous* requests. With an asynchronous request, you never know what the real result of the request is until it completes, so the File Manager sets D0 to 0 when it *starts* execution of the request and doesn't worry about returning the ioResult value (which is 1 while the call is queued or executing) to the caller. Here's how we (Apple) recommend making asychronous File Manager requests (note: Device Manager calls are handled differently - read the article): /* Make an asynchronous request. */ /* Ignore the function result and look for the */ /* real result when the call completes. */ (void) PBHGetVInfoAsync(&pb); or in Pascal: if (PBHGetVInfoAsync(@pb) <> noErr) ; { do nothing, check result at completion } - --- - Jim Luther --------------------------- >From bentley@MCS.COM (Mike Bentley) Subject: Future of ASLM Date: 13 Aug 1994 17:46:25 -0500 Organization: MCSNet Subscriber Account, Chicago's First Public-Access Internet! What I meant to ask was, after finally getting something like a shared library manager out for the 680x0 machines, how does ASLM fit into the plan when building a shared library file with both 680x0 and PowerPC code in it? My guess is that this doesn't happen, that an ASLM library gets a file and the equivalent code fragment import library (a 'shlb' -- too bad, 'shlp' is funnier) is a separate file. This probably means that there is some differences in implementation detail in the source code. -Mike Bentley Crenelle Inc. +++++++++++++++++++++++++++ >From garryh@seeding.apple.com (Garry Hornbuckle) Date: 26 Aug 1994 18:39:45 GMT Organization: Apple Computer, Inc. In article <32jig1$42k@Mercury.mcs.com>, bentley@MCS.COM (Mike Bentley) wrote: > What I meant to ask was, > after finally getting something like a shared library manager out for the 680x0 > machines, how does ASLM fit into the plan when building a shared library file > with both 680x0 and PowerPC code in it? ========================================== Macintosh Dynamic Linked Libraries (DLLs) ========================================== Apple has developed a complete technology solution for shared code, shared objects, and dynamic linked libraries (DLLs) on the Macintosh. Parts of this solution are available today, with additional parts becoming available in the coming months. There are three key components to Macintosh DLL strategy: € Apple's Shared Library Manager (ASLM), € Apple's Code Fragment Manager (CFM), and € IBM's System Object Model (SOM). Here is a brief summary of ASLM, CFM, and SOM ... ASLM - ---------- Apple Shared Library Manager is the first component of Apple's DLL solution to be available, and is an integral part of our overall DLL offering. ASLM supports shared code libraries for both procedural and object oriented development efforts. A number of Apple products have already been based on ASLM, including MacSNMP and the GeoPort communications pod technology. Third parties such as Microsoft (OLE for Macintosh), Novell (AppWare), and Aldus have also adopted ASLM to support their DLL needs. In the future, additonal functionality will be added to the Macintosh operating system as ASLM libraries, including our next generation networking, the Open Transport Communications Architecture. ASLM v1.1.2 is the currently shipping release. ASLM v2.0 is under development, to provide support for native code shared libraries on Power Macintosh. ASLM 2.x sits on top of (is based on) the Code Fragment Manager. This work is expected to produce final product in 4Q CY94. As CFM becomes available on 68K Macintosh (see below), a future ASLM version (2.1) will support CFM on 68K as well, while continuing to support current 68K-style shared libraries. Thus, ASLM v2.x will provide compatibility for ASLM v1.1, v1.1.1, and v1.1.2 applications. ASLM adds higher-level object-oriented capabilities to the environment that are not a part of the Code Fragment Manager itself. ASLM is the technology of choice when you: € need DLLs on 68K today ... ASLM is shipping € want simplicity and elegance with C++ € want a simple but powerful extension mechanism using C, Pascal, or ASM € have performance sensitive (i.e., interrupt time) needs like networking € want run-time transparent dynamic loading and unloading of code € DON'T need transparent access to per-context global data € DON'T need to solve the "fragile base class" problem for C++ CFM - ---------- As a second key step in our DLL strategy, Apple has developed a new foundation layer for dynamic linking on the Macintosh known as the Code Fragment Manager (CFM). CFM will be a core part of System Software on the PowerPC Macintosh. CFM is also being developed for the Macintosh on 68K. This work is expected to produce final product in 1Q CY95. The Code Fragment Manager provides code sharing and dynamic linking, with features supporting per-context globals. CFM will be fully supported by development tools on Macintosh. CFM is the best bet when your application: € runs on PowerPC Macintosh first, and 68K Macintosh later € needs only basic dynamic loading and unloading of shared code € needs to reduce system overhead to the minimum amount € needs transparent access to per-context global data € DOES NOT need system-level OOP support SOM - ---------- Apple is in the process of licensing and porting IBM's System's Object Model (SOM) technology to Macintosh. SOM is a multi-platform standard providing for system-level sharable objects in a language-neutral way. SOM also solves the "fragile base class" problem, avoiding the need for client libraries to be recompiled when the base class they inherit from is in a different library and is changed. To offer these benefits (multi-platform support and fragile base-class resolution) SOM requires the use of an IDL as a first step in the development process. SOM runs on top of CFM, and thus will become available on both 68K and PowerPC Macintosh. SOM is a foundation technology for OpenDoc. Integration - ---------- SOM and ASLM will both live in a CFM run-time environment, and will both be available on both 68K and PowerPC Macintosh. Thus there will be no impediment to co-existence of ASLM and SOM, or to applications that use both ASLM and SOM. In fact, a SOM class could easily call an ASLM class or vice-versa. Over time, some of the functionality provided by ASLM may be supplanted by SOM. However, ASLM APIs will be preserved. As a result, applications written to the ASLM API may have some functionality transparently migrated to SOM in the future. - ----------------------------------------------------------------- Garry Hornbuckle Product Manager, Communications & Collaboration - ----------------------------------------------------------------- "If I told you that I | email garryh@seeding.apple.com spoke only for myself | applelink HORNBUCKLE1 would you believe me?" | fax (408) 974-1211 - ----------------------------------------------------------------- --------------------------- >From Jaeger@fquest.com (Brian Stern) Subject: Review of PowerMac devtools available Date: 26 Aug 1994 03:20:05 GMT Organization: The University of Texas at Austin, Austin, Texas If you haven't come across it yet, there is an interesting article titled: PUTTING THE C(++) INTO POWER MACINTOSH by Jon Lansdell (August 19th 1994), that has appeared in the current version of powerPC news. It is the first part of a two part series that will review the four native development environments for the PowerMac. In case you're wondering these are: *Symantec's Cross Development kit* *MPW* *The Absoft C/C++ SDK* *CodeWarrior * Here are a few quotes taken completely out of context: Symantec's image amongst the Macintosh developer community was somewhat tarnished by release 6.0 of Symantec C++ for the Macintosh and reports that it was somewhat buggy. MPW - tried, tested and old. ETO#15 and the MPW Pro CD both contain pre-release native versions of the MPW Shell and various tools, including PPCC. While this does compile applications around twice as fast, the Linker still has to run under emulation, so while Apple work on a new native development environment, developers have plenty of time for coffee breaks during the build process. The Absoft SDK includes a couple of extras which give it claim to be a fully rounded development environment. Although the Linker and Compiler are native, it does cry out to be part of a completely native development environment. You can find the article via your favorite web-client at: http://power.globalnews.com:8000/ -- Brian Stern :-{)} Jaeger@fquest.com --------------------------- >From scotth@jaguar.visix.com (Scott Hofmann) Subject: SetDialogDefaultItem() not doing anything! Date: Thu, 25 Aug 1994 13:42:32 GMT Organization: Visix Software, Reston, Virginia In some code I've written for a preferences dialog, I use the calls SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and "Cancel" buttons look and perform according to Apple spec, but both traps aren't doing anything- it's like they exist, but are bound to no-op. This happens both in Symantec C++ 6.0, using the glue from the THINK Ref 2.0, and in Metrowerks CW4. I'm working on a Centris 650 running System 7.1, so I'm pretty sure my ROMs contain that trap - could I be mistaken about this? Has anyone use gotten these traps to work? Thanks, scott -- - ----------------------------------------------------------------------------- J. Scott Hofmann | "You've saved humanity...once again" scotth@visix.com | -Q to Capt. Picard, ST:TNG +++++++++++++++++++++++++++ >From hanrek@cts.com (Mark Hanrek) Date: 25 Aug 1994 20:18:00 GMT Organization: The Information Workshop In article , scotth@jaguar.visix.com (Scott Hofmann) wrote: > In some code I've written for a preferences dialog, I use the calls > SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and "Cancel" > buttons look and perform according to Apple spec, but both traps aren't doing > anything- it's like they exist, but are bound to no-op. This happens both in > Symantec C++ 6.0, using the glue from the THINK Ref 2.0, and in Metrowerks CW4. > I'm working on a Centris 650 running System 7.1, so I'm pretty sure my ROMs > contain that trap - could I be mistaken about this? Has anyone use gotten these > traps to work? Thanks, There is a certain "time" that these calls should be made so that they are associated with the current dialog. Otherwise, it could cause problems in the cases in which you don't want the system to do its thing for you. In other words, the effect is not global, but rather "contextual". Example source code will show you what you need to know. Hope this helps. Mark Hanrek +++++++++++++++++++++++++++ >From dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling) Date: Fri, 26 Aug 1994 09:41:03 +0100 Organization: UniDO In article , hanrek@cts.com (Mark Hanrek) wrote: > In article , > scotth@jaguar.visix.com (Scott Hofmann) wrote: > > > In some code I've written for a preferences dialog, I use the calls > > SetDialogDefaultItem() and SetDialogCancelItem() to make my "OK" and > > There is a certain "time" that these calls should be made so that they are > associated with the current dialog. Try something like (this is Pascal, but...): myDlog := GetNewDialog(myID, nil, pointer(-1)); myErr := SetDialogDefaultItem(myDlog, OK); myErr := SetDialogCancelItem(myDlog, cancel); { here it comes: } myErr := GetStdFilterProc(filterIt); { don't use your own filter } repeat ModalDialog(filterIt, itemHit); { do something } until itemHit in [OK, Cancel]; -- | Dirk Froehling - Germany, Uni Dortmund, FB Maschinenbau, LS Mechanik | | dirk@gaga.maschinenbau.uni-dortmund.de GEnie: D.FROEHLING | +++++++++++++++++++++++++++ >From gbolsinga@aol.com (GBolsinga) Date: 26 Aug 1994 16:02:07 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling) writes: >Try something like (this is Pascal, but...): > > myDlog := GetNewDialog(myID, nil, pointer(-1)); > > myErr := SetDialogDefaultItem(myDlog, OK); > myErr := SetDialogCancelItem(myDlog, cancel); > > { here it comes: } > myErr := GetStdFilterProc(filterIt); { don't use your own filter } > > repeat > ModalDialog(filterIt, itemHit); > { do something } > until itemHit in [OK, Cancel]; You could use your own filter which pre-filters the call and then calls the standard filter proc Greg MPI Multimedia /* These are MY opinions */ +++++++++++++++++++++++++++ >From stk@uropax.contrib.de (Stefan Kurth) Date: 27 Aug 1994 18:20:16 +0200 Organization: Contributed Software GbR In article <33lhnv$m7r@search01.news.aol.com>, GBolsinga wrote: > In article , > dirk@gaga.maschinenbau.uni-dortmund.de (Dirk Froehling) writes: > > > { don't use your own filter } > > You could use your own filter which pre-filters the call and then calls > the standard filter proc Yes, but remember to call it like this: GetStdFilterProc(&theFilterProc); asm { move.l d3, -(a7) } result = theFilterProc(theDialog, &theEvent, &itemHit); asm { move.l (a7)+, d3 } return result; since the std filter proc trashes d3, which can cause strange things to happen to your local variables. ________________________________________________________________________ Stefan Kurth Berlin, Germany stk@contrib.de --------------------------- >From woody@alumni.caltech.edu (William Edward Woody) Subject: Trouble making floating windows work with modeless dialogs Date: 26 Aug 1994 06:56:43 GMT Organization: California Institute of Technology, Alumni Association I'm having a problem making modeless dialogs work with floating windows. The problem is with 'IsDialogEvent()' and 'DialogSelect()'. When I receive the event from WaitNextEvent(), I first determine if the event is for a modal dialog through 'IsDialogEvent()', and if it is, I call my subroutine which gets the calls 'DialogSelect()' to process the event, and then handle the control ID if DialogSelect returns TRUE. The problem is that it seems that the modeless dialog is not being processed correctly if there is a floating window up. I think what's going on is that as the floating window is the frontmost window in the WindowList, IsDialogEvent() and DialogSelect() do not handle mouseDown, nullEvent, or keyDown events at all. Kludging the system to put the dialog at the head of the WindowList global for processing of the IsDialogEvent() and DialogSelect() routines allows me to click on buttons, but edit fields are handled completely wrong. What I want to know is, what can I do to make IsDialogEvent() and DialogSelect() work. (I don't want to use the GhostWindow global because I may have more than one floating window up at once.) If I can't make those routines work, then how can I replace the routines with code of my own to handle dialog events? I'm really stuck here, and I don't know where to turn. This is my last hope. advTHANKSance. - Bill -- o William Edward Woody | "I'm shying from the light In Phase Consulting | I always loved the night 337 West California #4 | And now you offer me eternal darkness" Glendale, CA 91203 | - Depeche Mode, "One Caress" +++++++++++++++++++++++++++ >From woody@alumni.caltech.edu (William Edward Woody) Date: 26 Aug 1994 22:19:16 GMT Organization: California Institute of Technology, Alumni Association a while ago (yesterday?) I wrote: > I'm having a problem making modeless dialogs work with floating windows. > The problem is with 'IsDialogEvent()' and 'DialogSelect()'. > > What I want to know is, what can I do to make IsDialogEvent() and > DialogSelect() work. (I don't want to use the GhostWindow global because > I may have more than one floating window up at once.) If I can't > make those routines work, then how can I replace the routines with > code of my own to handle dialog events? Well, without a solution I could use fast enough, I bit the bullet and wrote the routines MIsDialogEvent() and MDialogSelect() to replace IsDialogEvent() and DialogSelect() to solve my problem. I have attached the code I wrote below, so others can also do modeless dialogs and floating windows at the same time. NOTE: In these routines below, MFrontWindow() is the replacement to FrontWindow() which figures out the frontmost non-floater window. NOTE: These routines are not well-tested. They work for me, but they may have bugs (some severe) which prevent their adequate use. Note that they were written to be used together, and are not compatable with their 'IsDialogEvent()/DialogSelect()' counterparts. I don't know why this is; it just is. Code follows: - -CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE--- /* MIsDialogEvent * * Is this an event for this dialog box? */ Boolean MIsDialogEvent(EventRecord *event) { WindowPtr w; short where; switch (event->what) { case mouseDown: where = FindWindow(event->where,&w); if (where != inContent) w = NULL; else if (w != MFrontWindow()) w = NULL; break; case updateEvt: case activateEvt: w = (WindowPtr)(event->message); break; case keyDown: case autoKey: default: w = MFrontWindow(); break; } if (w == NULL) return 0; if (((WindowPeek)w)->windowKind == dialogKind) return 1; return 0; } /* MDialogSelect * * Do the dialog select routines. This does all of the dialog * processing stuff for this dialog window if it is one. */ Boolean MDialogSelect(EventRecord *event, DialogPtr *dlog, short *item) { WindowPtr w; DialogPeek peek; short where; Handle h; Rect r; TEHandle text; char c; short index; short length; Point pt; long tmp; /* * Determine the dialog window that is being used here. */ switch (event->what) { case mouseDown: case mouseUp: where = FindWindow(event->where,&w); if (where != inContent) w = NULL; break; case updateEvt: case activateEvt: w = (WindowPtr)(event->message); break; default: w = MFrontWindow(); break; } if (w == NULL) return 1; // Not my event... if (((WindowPeek)w)->windowKind != dialogKind) return 1; /* * Now, actually do this event as appropriate */ *dlog = w; // The dialog I was handling. *item = 0; // Default item (0) peek = (DialogPeek)w; // So I can get at internal stuff switch (event->what) { /* * Activate/Deactivate * * This activates or deactivates the text edit field * if it is present in the dialog box. */ case activateEvt: SetPort(w); text = peek->textH; if (text) { if (event->modifiers & activeFlag) { TEActivate(text); } else { TEDeactivate(text); } } return 0; // Further processing not needed /* * Update * * This simply draws the contents of this thing */ case updateEvt: SetPort(w); BeginUpdate(w); UpdateDialog(w,w->visRgn); EndUpdate(w); return 0; // Further processing not needed /* * Null event processing * * Blink the cursor */ default: case nullEvent: SetPort(w); if (peek->textH) TEIdle(peek->textH); return 0; // Further processing not needed /* * Key events * * This handles keyboard events by processing the enter/ * escape keys as buttons 1 and 2; otherwise, pass to the * current edit box, if any. */ case keyDown: case autoKey: SetPort(w); c = (unsigned char)(event->message & charCodeMask); /* * Enter, escape processing */ if ((c == 0x03) || (c == 0x0D) || (c == 0x1B)) { if ((c == 0x03) || (c == 0x0D)) { *item = 1; } else { *item = 2; } GetDialogItem(w,*item,&where,&h,&r); HiliteControl((ControlHandle)h,inButton); Delay(5,&tmp); HiliteControl((ControlHandle)h,0); return 1; // Further processing needed } /* * Tab processing */ if (c == 0x09) { // Horizontal tab key if (peek->textH == NULL) return 0; // Can't deal with it. length = *((short *)(*(peek->items))) + 1; index = peek->editField+2; // Skip this one /* * Find the next edit item and select it */ while (index <= length) { GetDialogItem(w,index,&where,&h,&r); if ((0x7F & where) == 16) { // This is an edit item SelIText(w,index,0,32767); // Move edit, select me *item = index; return ((where & 0x80) == 0) ? 1 : 0; } index++; } index = 1; // Wrap to beginning while (index <= length) { GetDialogItem(w,index,&where,&h,&r); if ((0x7F & where) == 16) { // This is an edit item SelIText(w,index,0,32767); // Move edit, select me *item = index; return ((where & 0x80) == 0) ? 1 : 0; } index++; } *item = 0; return 0; // Huh? Dunno... } /* * Normal keyboard processing */ text = peek->textH; if (text == NULL) return 0; // No edit item to do *item = peek->editField+1; // Item ID we're doing TEKey(c,text); // Do character process GetDialogItem(w,*item,&where,&h,&r); // Return appropriate return ((where & 0x80) == 0) ? 1 : 0; // for enable flag /* * Mouse down: * * track the controls or the edit fields as appropriate */ case mouseDown: SetPort(w); pt = event->where; GlobalToLocal(&pt); /* * Determine where the mouse went down */ index = FindDItem(w,pt)+1; if (index == 0) return 0; // Not on anything GetDialogItem(w,index,&where,&h,&r); *item = index; /* * Handle inactive objects */ if (where & 0x80) { if (where == 0x90) { // Edit item here. /* * Handle edit selection even if inactive */ if (peek->editField + 1 != index) { SelIText(w,index,0,32767); } TEClick(pt,(event->modifiers & shiftKey) ? 1 : 0,peek->textH); } return 0; } /* * Process according to where I'm at */ switch (where) { default: return 1; // Just return the ID. case 4: case 5: case 6: case 7: /* * Click on a standard control object */ if (TrackControl((ControlHandle)h,pt,NULL)) return 1; // do it. return 0; // don't do it. case 16: // Handle edit box if (peek->editField + 1 != index) { SelIText(w,index,0,32767); } TEClick(pt,(event->modifiers & shiftKey) ? 1 : 0,peek->textH); return 1; // Return where I am now. } } return 0; // Not one of these; can't deal with it at all... } - -CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE---CUT HERE--- I hope this helps. Permission is granted to use this message and the code contained herein in any way you want, redistribute it, fold it, spindle it, or mutulate it, so long as you don't sue me if the code crashes. Given away as is, without warranty of any kind. If you don't like this, my lawyer can mud-wrestle your lawyer in the nude for 15 rounds at the local mud-wrestling bar for brownies. (This assumes, of course, that your lawyer and my lawyer look good in the nude. :-) - Bill -- o William Edward Woody | "I'm shying from the light In Phase Consulting | I always loved the night 337 West California #4 | And now you offer me eternal darkness" Glendale, CA 91203 | - Depeche Mode, "One Caress" --------------------------- End of C.S.M.P. Digest **********************