From: pottier@clipper.ens.fr (Francois Pottier) Subject: csmp-digest-v3-067 Date: Mon, 14 Nov 1994 15:53:04 +0100 (MET) C.S.M.P. Digest Mon, 14 Nov 94 Volume 3 : Issue 67 Today's Topics: (Q) AppleScript & XCMD's Can anyone help me with the Time Manager? Dynamic Dialogs? How to install your own templates using Macsbug 6.5d6??? IM: Networking book question INIT Writing FAQ [1-3] INIT Writing FAQ [2-3] INIT Writing FAQ [3-3] Linking 68k object files to PPC program Network Programming Stuck in SyncWait again having trouble with AEInteractWithUser & drag manager 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 Tom_Brodhurst-Hill@intouch.mpx.com.au (Tom Brodhurst-Hill) Subject: (Q) AppleScript & XCMD's Date: 31 Oct 1994 19:07:41 GMT Organization: MacInTouch BBS Can anyone tell me whether XCMD's (typically for HyperCard) can be included in and accessed by a compiled AppleScript application, without running a separate HyperCard process? Thanks, Tom please email to tombh@intouch.mpx.com.au and post too for others. MacInTouch BBS info@intouch.mpx.com.au Ph. 61 2 541 1287 BBS. 61 2 541 0799 *** Sent by FirstClass the graphical email system by SoftArc. Inc. *** +++++++++++++++++++++++++++ >From lai@apple.com (Ed Lai) Date: Mon, 31 Oct 1994 17:20:39 GMT Organization: Apple In article <29224926.900353@intouch.intouch.mpx.com.au>, Tom_Brodhurst-Hill@intouch.mpx.com.au (Tom Brodhurst-Hill) wrote: > Can anyone tell me whether XCMD's (typically for HyperCard) can be included in > and accessed by a compiled AppleScript application, without running a > separate HyperCard process? > Thanks, > Tom > please email to tombh@intouch.mpx.com.au > and post too for others. > MacInTouch BBS > info@intouch.mpx.com.au Ph. 61 2 541 1287 BBS. 61 2 541 0799 > *** Sent by FirstClass the graphical email system by SoftArc. Inc. *** It depends on the XCMD, a lot of them can be used, but if they are very dependent on HyperCard specifc callback or globals, then they cannot. Try to download the XCMD OSAX. Generally the place to look for AppleScript related stuff is in gaea.kgs.ukans.edu. If it is just for the XCMD OSAX, you may try ftp.apple.com in /pub/lai/osax. It is an adaptor for AppleScript to use XCMDs. It also comes installed with a number of XCMDs by Rinaldi as examples. In theory you can try it with any other XCMD/XFCNs you got. However to do that requires writing certain resources and that is not a easy job if you are doing it the first time. -- /* Disclaimer: All statments and opinions expressed are my own */ /* Edmund K. Lai */ /* Apple Computer, MS303-3A */ /* 20525 Mariani Ave, */ /* Cupertino, CA 95014 */ /* (408)974-6272 */ zW@h9cOi --------------------------- >From anthonym@puree.ugcs.caltech.edu (Anthony Molinaro) Subject: Can anyone help me with the Time Manager? Date: 21 Oct 1994 08:09:59 GMT Organization: California Institute of Technology, Pasadena I worked on this piece of code for a friend using Symatec THINK C which turns on the power to a digital I/O board, delays for a certain number of ticks, and then turns the power off. This was my first time programming on a Macintosh and so I had to search a little bit to find out about Delay. Now, he tells me he needs a delay time smaller than one tick. I know that the time manager can do this but I have been unable to get it to work. I guess my confusion arises in the type declarations and getting all of the types to match for functions InsXTime(), PrimeTime(), and such. The Inside Macintosh doesn't have any examples in C and I have not been able to accurately port the Pascal functions with the proper type settings. My midterms are quickly approaching but I promised I would help him out, so any help that anyone could give would be . /* Here is the original code */ void Play(int note, unsigned long time) { long finalTicks; short error; /* turn on power for port,line: portout, lineout */ error = DIG_Out_Line(4, notes[note].portout, notes[note].line, 1); chkerr("DIG_Out_Line",error); /* if power is on delay */ if(error == 0) Delay(time,&finalTicks); /* turn off power */ error = DIG_Out_Line(4, notes[note].portout, notes[note].line, 0); chkerr("DIG_Out_Line",error); } /* Here is what I tryed */ /* global variables */ int note; TMTask tblah; pascal void MyTimeTask(void) { DIG_Out_Line(4, notes[note].portout, notes[note].line, 0); } void MyDelay(unsigned long time) { tblah.tmAddr = &MyTimeTask(); tblah.tmWakeUp = 0; tblah.tmReserved = 0; InsXTime(&tblah); PrimeTime(&tblah,time); } This didn't work, and I don't have a lot of time to figure out why, so if anyone has any ideas I'm open to them. Thanks in advance. Reply through e-mail if possible. ===================================================================== Anthony Molinaro anthonym@ugcs.caltech.edu +++++++++++++++++++++++++++ >From Carl R. Osterwald Date: Fri, 21 Oct 1994 17:23:44 GMT Organization: National Renewable Energy Laboratory In article <387t0n$3rr@gap.cco.caltech.edu> Anthony Molinaro, anthonym@puree.ugcs.caltech.edu writes: >Now, he tells me he needs a delay time smaller than one tick. >I know that the time manager can do this but I have been >unable to get it to work. I guess my confusion arises in the >type declarations and getting all of the types to match for >functions InsXTime(), PrimeTime(), and such. The Inside Here is an example of a Time Manager task: typedef struct { TMTask tm_task; long A5; } time_info; Initialization: timer_rec.tm_task.tmAddr = (TimerProcPtr)&time_task; timer_rec.tm_task.tmWakeUp = 0; timer_rec.tm_task.tmReserved = 0; timer_rec.A5 = SetCurrentA5(); InsXTime( (QElemPtr)&timer_rec ); PrimeTime( (QElemPtr)timer_rec, period ); <<-- This starts the task static void time_task (void) { time_info *timer_rec; long current_A5; asm { MOVE.L A1,timer_rec MOVE.L A5,current_A5 }; SetA5(timer_rec->A5); PrimeTime( (QElemPtr)timer_rec, period ); <<-- This restarts the task SetA5(current_A5); } // time_task You can access your globals between the SetA5 calls. Because the time task runs as an interrupt, it is best to minimize processing inside. In your case, I would just set a global flag that is polled in the main event loop to see if it is time to turn the device on or off. +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Fri, 21 Oct 1994 18:48:34 +0100 Organization: Royal Institute of Something or other In article <387t0n$3rr@gap.cco.caltech.edu>, anthonym@puree.ugcs.caltech.edu (Anthony Molinaro) wrote: >Now, he tells me he needs a delay time smaller than one tick. >I know that the time manager can do this but I have been >unable to get it to work. I guess my confusion arises in the All you need is the system call Microseconds. You can write your own Delay. Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden Not speaking for the Microsoft Corporation. +++++++++++++++++++++++++++ >From gbolsinga@aol.com (GBolsinga) Date: 24 Oct 1994 17:20:05 -0400 Organization: America Online, Inc. (1-800-827-6364) In article <387t0n$3rr@gap.cco.caltech.edu>, anthonym@puree.ugcs.caltech.edu (Anthony Molinaro) writes: >pascal void MyTimeTask(void) >{ DIG_Out_Line(4, notes[note].portout, notes[note].line, 0); >} Look at the other sample code: it looks good. Another problem might be that this function DIG_Out_Line can't move memory. MyTimeTask executes at interupt time, so just set a global, and in your idle in your event loop check for the global changing and then call your function. Greg Bolsinga MPI Multimedia +++++++++++++++++++++++++++ >From Tim Dorcey Date: 25 Oct 1994 19:01:49 GMT Organization: Cornell University In article Jon W{tte, h+@nada.kth.se writes: >All you need is the system call Microseconds. You can write >your own Delay. Do anyone know where the Microseconds call is documented? I stumbled upon it in , but can't find documentation for it anywhere. Is it safe to assume that it is available on any system that has the "Revised Time Manager?" I had written my own version, using InsTime/RmvTime, which seems to work fine, but I'd just as soon use the system call if it's equally available. Tim Dorcey Tim_Dorcey@cornell.edu --------------------------- >From joey@caseware.com (Joey Caturay) Subject: Dynamic Dialogs? Date: Thu, 13 Oct 1994 15:15:23 GMT Organization: CaseWare I seem to recall a MacTutor/Tech article about writing dynamic dialogs (i.e. dialogs in which controls change based on a selection in the dialog. The Metrowerks Project Preference dialog is an example). Is there source anywhere for dynamic dialogs? Thanks, joey +++++++++++++++++++++++++++ >From johns@efn.org (John Selhorst) Date: Fri, 14 Oct 1994 01:07:40 GMT Organization: hisself In article , joey@caseware.com (Joey Caturay) wrote: > I seem to recall a MacTutor/Tech article about writing dynamic dialogs (i.e. > dialogs in which controls change based on a selection in the dialog. The > Metrowerks Project Preference dialog is an example). > > Is there source anywhere for dynamic dialogs? > > Thanks, > > joey There are some nice snippets with dynamic dialogs on the developer CD and probably on ftp.apple.com or whatever it's called now. Johnny johns@efn.org +++++++++++++++++++++++++++ >From gurgle@dnai.com (Pete Gontier) Date: Sat, 15 Oct 1994 02:39:20 -0800 Organization: Integer Poet Software In article , joey@caseware.com (Joey Caturay) wrote: > I seem to recall a MacTutor/Tech article about writing dynamic dialogs (i.e. > dialogs in which controls change based on a selection in the dialog. The > Metrowerks Project Preference dialog is an example). > Is there source anywhere for dynamic dialogs? Just get creative with HideDItem and ShowDItem. I recently implemented a NewsWatcher-style dialog this way (and it was no coincidence...). There's a popup menu at the top from which the user can select a set of dialog items. The items always exist, but most of them are hidden most of the time. Creating this dialog can be a pain unless you have a cool dialog editor like the one in Resorcerer which actually lets you show and hide ranges of items in the same way the Dialog Manager will do at run-time. (It's been This all said, if you're contemplating doing this, it may also be the case that you are running into other limitations of the Dialog Manager. Consider using something else, like any one of the several commercial view-management systems (off the top of my head, QuickApp, AppsToGo, MacApp, TCL, PowerPlant, FaceIt), or roll your own. (It's not all that hard if all you want is a list of items like the Dialog Manager tracks. Trees get messy, of course.) -- Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com "A Princeton Review executive said the whole affair was not that important and offered to relinquish the Kaplan domain name 'for a case of beer'." -- Chris Gulker, SF Examiner +++++++++++++++++++++++++++ >From gurgle@dnai.com Date: 14 Oct 94 21:39 GMT+0300 Organization: (none) In article , joey@caseware.com (Joey Caturay) wrote: > I seem to recall a MacTutor/Tech article about writing dynamic dialogs (i.e. > dialogs in which controls change based on a selection in the dialog. The > Metrowerks Project Preference dialog is an example). > Is there source anywhere for dynamic dialogs? Just get creative with HideDItem and ShowDItem. I recently implemented a NewsWatcher-style dialog this way (and it was no coincidence...). There's a popup menu at the top from which the user can select a set of dialog items. The items always exist, but most of them are hidden most of the time. Creating this dialog can be a pain unless you have a cool dialog editor like the one in Resorcerer which actually lets you show and hide ranges of items in the same way the Dialog Manager will do at run-time. (It's been This all said, if you're contemplating doing this, it may also be the case that you are running into other limitations of the Dialog Manager. Consider using something else, like any one of the several commercial view-management systems (off the top of my head, QuickApp, AppsToGo, MacApp, TCL, PowerPlant, FaceIt), or roll your own. (It's not all that hard if all you want is a list of items like the Dialog Manager tracks. Trees get messy, of course.) -- Pete Gontier // CTO, Integer Poet Software // gurgle@dnai.com "A Princeton Review executive said the whole affair was not that important and offered to relinquish the Kaplan domain name 'for a case of beer'." -- Chris Gulker, SF Examiner +++++++++++++++++++++++++++ >From ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) Date: 18 Oct 1994 15:49:43 GMT Organization: Avid Technology, Inc. In article , gurgle@dnai.com (Pete Gontier) wrote: > In article , joey@caseware.com (Joey > Caturay) wrote: > > > I seem to recall a MacTutor/Tech article about writing dynamic dialogs (i.e. > > dialogs in which controls change based on a selection in the dialog. The > > Metrowerks Project Preference dialog is an example). > > Is there source anywhere for dynamic dialogs? > > Just get creative with HideDItem and ShowDItem. I recently implemented a > NewsWatcher-style dialog this way (and it was no coincidence...). There's > a popup menu at the top from which the user can select a set of dialog > items. The items always exist, but most of them are hidden most of the > time. Creating this dialog can be a pain unless you have a cool dialog > editor like the one in Resorcerer which actually lets you show and hide > ranges of items in the same way the Dialog Manager will do at run-time. > (It's been I thought NewsWatcher used AppendDITL, RemoveDITL, etc. I do remember John's sample code from disinfectant containing routines along the lines of AppendDITL and RemoveDITL to allow you to append and remove items to the dialog (the Sys7/CTB routines of the same names work as long as you DON'T use 'ictb' resources - otherwise they can crash horribly). I don't have any source, but you might also want to look at either the QuickTime Sequence Grabber Panel Component API or the Sound Control Panel Component API for some pointers and ideas - it defines a clean layer between a main piece of code that you write that controls the main dialog (ie the NW popup menu or the "scrolling icon item" list in CW) and "plug-in" subcomponents that control the independent panels. -Ivan - -- Ivan Cavero Belaunde (ivan_cavero_belaunde@avid.com) Avid VideoShop Lead Avid Technology, Inc. Disclaimer: All views expressed are entirely my own and do not reflect the opinions of Avid Technology, Inc. +++++++++++++++++++++++++++ >From reed@medicine.wustl.edu (Thomas Reed) Date: Tue, 18 Oct 1994 11:21:13 -0500 Organization: Washington University In article , gurgle@dnai.com (Pete Gontier) wrote: >In article , joey@caseware.com (Joey >Caturay) wrote: > >> I seem to recall a MacTutor/Tech article about writing dynamic dialogs > >Just get creative with HideDItem and ShowDItem. The method I like better is to set up your dialog with a "base" DITL, containing whatever controls are going to be static for all settings. This might contain your OK and Cancel buttons and a pop-up, if that's the method you want to use to switch to a different set of controls. Then, you define a separate DITL for each setting (say you have an options dialog with three different options topics selectable on a pop-up menu, you use 3 different DITLs, one for each topic). Make sure that the new DITL can be overlayed on the "base" DITL the way you want it. I believe that you may also want to specify that the "base" DLOG is not initially visible. Then, in your program, you use AppendDITL to overlay the DITLs. Just open your base DLOG, then call AppendDITL to overlay the current setting on the base DITL. The item numbers for the one you're adding will be bumped up by the number of items in your base DITL. Then, when the user switches to a different set of controls, you use ShortenDITL to remove the old controls and AppendDITL to add the new set. You've of course also got to take into account which set of controls you're using in your dialog handling routines, as item #5 under one setting may not be the same as item #5 under another. However, this is not too hard to do. I believe that this is the way that NewsWatcher does things. -Thomas ===================================================== Thomas Reed Washington University reed@telesphere.wustl.edu Medical School reed@medicine.wustl.edu Saint Louis, MO - --------------------------------------------------- Clothes make the man. Naked people have little or no influence on society. -- Mark Twain ===================================================== Opinions posted are not the opinions of Wash. U. +++++++++++++++++++++++++++ >From bb@lightside.com (Bob Bradley) Date: Mon, 17 Oct 1994 03:22:02 -0800 Organization: SS Software Inc. In article , ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) wrote: > I thought NewsWatcher used AppendDITL, RemoveDITL, etc. I do remember > John's sample code from disinfectant containing routines along the lines > of AppendDITL and RemoveDITL to allow you to append and remove items to > the dialog (the Sys7/CTB routines of the same names work as long as you > DON'T use 'ictb' resources - otherwise they can crash horribly). Any dialog with an ictb resource can't use AppendDITL/ShortenDITL? Is there any other way to get the functionality of those two routines when using dialogs with ictb resources without modifying the DITL in memory directly? I had a lot problems in the past with AppendDITL and ShortenDITL and could never figure it out until you mentioned they didn't work with ictb resources. I end up using the Show/Hide method but, when working with dialogs with a lot of items, it gets difficult. +++++++++++++++++++++++++++ >From rmah@panix.com (Robert Mah) Date: Tue, 18 Oct 1994 18:15:26 -0500 Organization: One Step Beyond Jason_Titus@odsnet.com wrote: ) I have been trying to work out a solution to a problem where I have a ) base window and can have a thousand or so possible midifications. It ) sounds like having these numerous DITL's and appending them would be ) the best solutions,but - ) ) how do I create DITLs? I can't find real descriptions of their format.. ) My goal is to be able to create DITLs from text files of information ) (ie - a text file made up of checkbox titles) so I can easily create ) thousands of windows. The usual way is to use ResEdit's or Resorcerer's graphical editors. However given that you want to parse a text file to create user interfaces, and assuming that the text file is not in rez format, I think you're going to have to write a parser and create windows on the fly. That is, don't use DITL and DLOG resources, but instead operate directly at the Window Manager, Control Manager, List Manager and TextEdit levels. Depending upon the complexity of your "interface description language", this might not be too hard or it might be a royal pain in the... Cheers, Rob _____________________________________________________________________ Robert S. Mah Software Development +1.212.947.6507 One Step Beyond and Network Consulting rmah@panix.com +++++++++++++++++++++++++++ >From leonardr@netcom.com (Leonard Rosenthol) Date: Wed, 19 Oct 1994 21:47:29 GMT Organization: Aladdin Systems, Inc. In article , bb@lightside.com (Bob Bradley) wrote: > In article , > ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) wrote: > > > I thought NewsWatcher used AppendDITL, RemoveDITL, etc. I do remember > > John's sample code from disinfectant containing routines along the lines > > of AppendDITL and RemoveDITL to allow you to append and remove items to > > the dialog (the Sys7/CTB routines of the same names work as long as you > > DON'T use 'ictb' resources - otherwise they can crash horribly). > > Any dialog with an ictb resource can't use AppendDITL/ShortenDITL? Is > there any other way to get the functionality of those two routines when > using dialogs with ictb resources without modifying the DITL in memory > directly? > That info about 'ictb's is NOT true. The System routines AppendDITL and ShortenDITL will work just fine with ictb's GIVEN THE LIMITATIONS of ictb resources (like they suck big time!). Leonard - ------------------------------------------------------------------------ Leonard Rosenthol Internet: leonardr@netcom.com Director of Advanced Technology AppleLink: MACgician Aladdin Systems, Inc. GEnie: MACgician +++++++++++++++++++++++++++ >From ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) Date: 21 Oct 1994 14:44:58 GMT Organization: Avid Technology, Inc. In article , bb@lightside.com (Bob Bradley) wrote: > In article , > ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) wrote: > > I thought NewsWatcher used AppendDITL, RemoveDITL, etc. I do remember > > John's sample code from disinfectant containing routines along the lines > > of AppendDITL and RemoveDITL to allow you to append and remove items to > > the dialog (the Sys7/CTB routines of the same names work as long as you > > DON'T use 'ictb' resources - otherwise they can crash horribly). > > Any dialog with an ictb resource can't use AppendDITL/ShortenDITL? Is > there any other way to get the functionality of those two routines when > using dialogs with ictb resources without modifying the DITL in memory > directly? > > I had a lot problems in the past with AppendDITL and ShortenDITL and could > never figure it out until you mentioned they didn't work with ictb > resources. I end up using the Show/Hide method but, when working with > dialogs with a lot of items, it gets difficult. Yeah, I had a lot of problems with those as well. Some of the problems (text items changing colors, for example) hinted at a confused 'ictb', so I stopped using one and everything was fine (it meant I had to use useritems for some stuff, though). This suspicion was confirmed by someone on the net who had worked on the AppendDITL/ShortenDITL code for Apple - 'ictb's are not supported by those calls. Upon rereading my post above, I realize I imply John Norstad's DITL-manipulation code supports 'ictb'. I actually don't know whether that's the case or not - but it'd be easy to check if you need that functionality. -Ivan - -- Ivan Cavero Belaunde (ivan_cavero_belaunde@avid.com) Avid VideoShop Lead Avid Technology, Inc. Disclaimer: All views expressed are entirely my own and do not reflect the opinions of Avid Technology, Inc. +++++++++++++++++++++++++++ >From Peter_Gontier@novell.com (Pete Gontier) Date: Mon, 24 Oct 1994 20:05:03 -0800 Organization: Novell, Inc., Walnut Creek Macintosh Site In article , ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) wrote: > In article , gurgle@dnai.com > (Pete Gontier) wrote: > > > Just get creative with HideDItem and ShowDItem. I recently implemented a > > NewsWatcher-style dialog this way... > > I thought NewsWatcher used AppendDITL, RemoveDITL, etc... I don't know for sure what NewsWatcher uses, but what I remember of the way he stored his DITLs supports the notion that he's using AppendDITL, etc. When I said "NewsWatcher-style" I only meant the user interface is similar. -- Views expressed here do not necessarily reflect the views of Novell. +++++++++++++++++++++++++++ >From ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) Date: 31 Oct 1994 19:43:51 GMT Organization: Avid Technology, Inc. In article , leonardr@netcom.com (Leonard Rosenthol) wrote: > In article , bb@lightside.com > (Bob Bradley) wrote: > > > In article , > > ivan_cavero_belaunde@avid.com (Ivan Cavero Belaunde) wrote: > > > > > I thought NewsWatcher used AppendDITL, RemoveDITL, etc. I do remember > > > John's sample code from disinfectant containing routines along the lines > > > of AppendDITL and RemoveDITL to allow you to append and remove items to > > > the dialog (the Sys7/CTB routines of the same names work as long as you > > > DON'T use 'ictb' resources - otherwise they can crash horribly). > > > > Any dialog with an ictb resource can't use AppendDITL/ShortenDITL? Is > > there any other way to get the functionality of those two routines when > > using dialogs with ictb resources without modifying the DITL in memory > > directly? > That info about 'ictb's is NOT true. The System routines AppendDITL > and ShortenDITL will work just fine with ictb's GIVEN THE LIMITATIONS of > ictb resources (like they suck big time!). Are you sure? I had an exchange on the net about a year/year and a half ago with someone (his name slips me) that had worked on the Append/RemoveDITL routines at Apple, and he explicitly mentioned that they didn't support 'ictb's. This was at the time when I was having problems with them: I kept getting items coming up in funny colors and fonts when I appended them, as well as stray crashes inside UpdateDialog. Nuking the 'ictb's got rid of all those problems. On a related note, how do they suck big time? My only beef is that they are hard to edit unless you have Resorcerer, which is another one of the bazillion reasons to get Resorcerer and skip ResEdit... -Ivan - -- Ivan Cavero Belaunde (ivan_cavero_belaunde@avid.com) Avid VideoShop Lead Avid Technology, Inc. Disclaimer: All views expressed are entirely my own and do not reflect the opinions of Avid Technology, Inc. --------------------------- >From hsieh@netcom.com (Julia Hsieh) Subject: How to install your own templates using Macsbug 6.5d6??? Date: Mon, 31 Oct 1994 17:25:57 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) i've just started playing with custom templates in Macsbug, but since the new version doesn't have a separate Debugger Prefs file with the resources in it, how do i add my own custom templates? also, i'm confused from one of the recent threads, is the Debugger Prefs a file or a folder. thanks. -julia -- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% If each day falls inside each night, there exists a well where clarity is imprisoned. We need to sit on the rim of the well of darkness and fish for fallen light with patience. -Pablo Neruda %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +++++++++++++++++++++++++++ >From johns@efn.org (John Selhorst) Date: Tue, 1 Nov 1994 14:29:33 GMT Organization: hisself In article , hsieh@netcom.com (Julia Hsieh) wrote: > i've just started playing with custom templates in Macsbug, but since > the new version doesn't have a separate Debugger Prefs file with the > resources in it, how do i add my own custom templates? > > also, i'm confused from one of the recent threads, is the Debugger > Prefs a file or a folder. > > thanks. > -julia > You've almost answered your own question. Yes, Debugger Prefs is a file that goes into the system folder. It still works with MacsBug 6.5. If you don't have one, make one yourself. You can make one with ResEdit. Johnny johns@efn.org +++++++++++++++++++++++++++ >From jonasw@lysator.liu.se (Jonas Wallden) Date: 1 Nov 1994 16:50:44 GMT Organization: (none) hsieh@netcom.com (Julia Hsieh) writes: >i've just started playing with custom templates in Macsbug, but since >the new version doesn't have a separate Debugger Prefs file with the >resources in it, how do i add my own custom templates? I'm running 6.5d6 and it uses a Debugger Prefs file. You can also drop your templates and macros into the MacsBug file itself. Just open it in ResEdit and paste them. >also, i'm confused from one of the recent threads, is the Debugger >Prefs a file or a folder. It's a resource file, and should be located at the top level of your System Folder. >thanks. >-julia BTW, welcome on board! You just doubled the female/male ratio of Mac hackers posting in this newsgroup... :-) ............... ....................... ........... ............... jonas wallden internet applelink phone/fax mac hacker jonasw@lysator.liu.se sw1369 +46-13-176084 +++++++++++++++++++++++++++ >From devon_hubbard@taligent.com (Devon Hubbard) Date: Mon, 31 Oct 1994 18:57:56 GMT Organization: Taligent, Inc. In article , hsieh@netcom.com (Julia Hsieh) wrote: >i've just started playing with custom templates in Macsbug, but since >the new version doesn't have a separate Debugger Prefs file with the >resources in it, how do i add my own custom templates? Since most of the dcmds/templates in the old 'Debugger Prefs' were always shipped with Macsbug, someone got smart at Apple (you know who you are :-) and just put that stuff in Macsbug itself and then there was no need for the separate prefs file. This didn't eliminate the usage of that prefs file though. So if you want to add your own templates, macros, etc. go right ahead and create a file called 'Debugger Prefs' and put your stuff in there. The file type/creator is usually 'rsrc'/'RSED' but it really doesn't matter to Macsbug as it'll open the rsrc fork of any type file called 'Debugger Prefs'. Also note that because Apple ships Macsbug this way, there is no need to merge their prefs with yours when a new release comes out. dEVoN - ----------------------------------------------------------------------- Devon Hubbard Silicon Pilot devon_hubbard@taligent.com Taligent, Inc - ----------------------------------------------------------------------- "No amount of genius can overcome a preoccupation with detail." -Einstein --------------------------- >From schultz@iastate.edu (Jonathan Schultz) Subject: IM: Networking book question Date: 28 Oct 94 07:08:51 GMT Organization: Iowa State University, Ames, Iowa Does IM: Networking totally supercede Inside AppleTalk? Jonathan schultz@iastate.edu -- - ----------------- Jonathan Schultz schultz@iastate.edu +++++++++++++++++++++++++++ >From jumplong@aol.com (Jump Long) Date: 29 Oct 1994 21:32:03 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , schultz@iastate.edu (Jonathan Schultz) writes: >Does IM: Networking totally supercede Inside AppleTalk? No it doesn't. IM: Networking replaces the AppleTalk chapters of Inside Macintosh volumes II, IV, V, and VI (the old Inside Macintosh volumes). IM: Networking describes the Macintosh AppleTalk API. Inside AppleTalk describes the AppleTalk *protocols* - not the API for any particular implementation of AppleTalk. While Inside AppleTalk isn't required to use most parts of the Macintosh AppleTalk API, it is useful when debugging AppleTalk problems you may have when using the Macintosh API because it describes the network packets and describes how the protocol was designed to be used. To use some parts of the Macintosh API, you must have Inside AppleTalk because the Macintosh API doesn't build the request packets or disassemble the reply packets for you. An example of that is using the .XPP driver to send AFP requests. Since the system doesn't build those packets for you, you'll have to use the information in Inside AppleTalk to know how to build them yourself. - Jim Luther --------------------------- >From Jaeger@fquest.com (Brian Stern) Subject: INIT Writing FAQ [1-3] Date: 28 Oct 1994 00:37:24 GMT Organization: The University of Texas at Austin, Austin, Texas Answers to Frequently Asked Questions about writing System Extensions on the Macintosh Computer. Version 1.0 10/94 This document is Copyright © 1994 by Brian Stern. I can be contacted by email at on Internet. The purpose of this FAQ list is to provide information on the writing of system extensions. This arcane art is difficult to learn and the existing information on the subject is spread around in various places. Hopefully the information here will help new and old INIT writers to write better INITs in less time. The questions in this document are broken into two sections: System Extensions and Trap Patches. While most extensions contain trap patches these subjects seemed different so I have separated them. FAQ lists like this one are an integral part of Usenet. When I started reading Usenet news I assure you that I knew nothing about writing extensions. I learned by posting questions to comp.sys.mac.programmer and by reading other's questions and responses. Let me take this space to give you a few tips on phrasing of questions to newsgroups. When asking a question try to make the title as descriptive as possible. Most people don't have time to read every question posted and will ignore posts whose titles are unclear or meaningless. Don't post questions titled 'HELP, My program doesn't work', or worse 'URGENT NEED HELP with program'. I'm sure it's urgent to you, but not to me. Always indicate that you're asking a questing by including a (you guessed it) question mark. Consider these titles: 'Programmers make big salaries' and 'Programmers make big salaries?' Don't waste people's time with the former when you mean the latter. Another way to indicate a question is like this: '[Q] Programmers make big salaries?'. Try to include one of the words 'who, what, when, where, why, or how' in the titles of your questions. Your questions are much more likely to be answered by someone who actually knows the answer if your title is clear. The code samples in this document were developed with Think C. You may need to make some changes to use them with other development systems. I've used inline assembly in many of the code samples. To my eye this makes things more clear since it's obvious what's going on. Not everyone agrees with this and not all development environments provide inline assembly. It's possible to rewrite most or all of this code by use of inline functions. If you're writing in Pascal or using CodeWarrior you'll have to do it that way. You'll be able to find information on general questions of Mac programming in the FAQ list maintained by Jon Watte at: ftp://nada.kth.se/pub/hacks/mac-faq/CSMP_PD_FAQ If you have questions about writing extensions that aren't addressed in this document or any comments about it feel free to send them to me. If I know the answer or can find it out it may find its way into a later version. This document may be distributed freely as long as no changes are made to it. It may not be distributed in ways in which the user must pay for the document, other than reasonable download costs or costs for the medium, without the consent of the author. Thanks to the following people who provided sample code and made constructive comments: Pete Gontier, Dair Grant, Chelly Green, Devon Hubbard, Peter Lewis, Jim Walker, Jim Wintermyre. - ------------------------------------------------------------------- System Extension Writing FAQ Outline: System Extensions: [1] What is an INIT, exactly? [2] Should I write an INIT? [3] Can I write an INIT that makes the application menu into a hierarchical menu? [4] Do I need to know assembler to write an INIT? [5] Can you show me a sample INIT? [6] Can I have global variables in my INIT? [7] How do I debug an INIT? [8] How do I write a Control Panel-INIT combination? [9] How do I capture keystrokes? [10] How can my extension get time periodically? [11] How should an INIT manage memory? [12] How do I get my INIT to turn itself off? [13] How do I get my INIT to show its icon like all the other cool INITs do? [14] How do I show a dialog from my INIT? [15] How do I maintain compatibility with future systems? [16] Any tips for INIT writing? Trap Patches: [17] What exactly is a trap patch? [18] What's the difference between a head patch and a tail patch? [19] How do I patch a trap? [20] How do I patch a register-based trap? [21] Can you show me an example tail patch? [22] How do I patch a selector-based trap? [23] How do I patch a trap on the PPC? [24] Can I write a fat trap? [25] Tips? [26] What other sources of information are available? - ------------------------------------------------------------------- [1] What is an INIT, exactly? An INIT is a type of code resource that is loaded into memory and executed during the startup process. They're called INITs because they're resources of type 'INIT'. INITs load at the end of the startup process, after the hardware checks have been done and the system has been started. The span of time during which INITs load and execute is known as INIT time. Applications don't load until after INIT time and in most cases the first application to load is the Finder. Because they load before all applications, INITs can modify the system in a way that affects all applications. They can add new functionalities and modify the way in which many processes occur on the Mac. Apple often supplies new additions and updates to system software as INITs. This includes things such as the Drag-and-Drop Manager, Thread Manager, Speech Manager, and Sound Manager 3.0. At some point these new features are rolled into a new software release and eventually they are included in new ROMs, but they all start life as INITs. Apple recommends that the term 'system extension' be used when communicating with non-programmers. This name carries the implication that they extend the functionality of the system. You'll see the terms 'INIT', 'extension', and 'system extension' used to mean the same thing throughout this document. Extensions are loaded in a defined order. Resources of type 'INIT' can be found in files of type 'INIT' (System Extension), 'cdev' (Control Panel), 'RDEV' (Chooser Device), 'appe' (application extension), and 'scri' (script system extensions). In order to be loaded, the INIT resource must be in one of these file types in one of several locations in the System Folder. Under system 7 INITs are loaded first from the Extensions Folder in alphabetical order. INITs present in script system extension files (filetype 'scri') load before INITs present in system extension files (filetype 'INIT'). Next, any INITs in the Control Panels folder are loaded in alphabetical order. Any INITs present at the root level of the System Folder are loaded after that. This order of loading is important if an extension is dependent on the presence of another extension. For example, if an INIT resource in an INIT file named 'SpeakAll' is dependent on the presence of the 'Speech Manager' extension, it either needs to have its name changed to something that sorts after 'Speech Manager' or it has to be located in the Control Panels folder, since extensions in the Control Panels folder load after extensions in the Extensions Folder. In system 6 the Extensions Folder and Control Panels Folders don't exist. Extensions are simply loaded in alphabetical order from the root level of the System Folder. -- [2] Should I write an INIT? System extensions are not easy to write. If this is your first attempt at Mac programming, the answer to this question is NO. Many experienced Mac programmers have never written one and don't intend to. There are a number of other ways to add functionality without writing an extension. If you want to add functionality to a single application then think about writing an FKEY. These are invoked by hitting cmd-shift-number and perform an action at that time only. The standard screen shot (cmd-shift-3) is one example. Another user-invokable means of adding functionality is plug-in modules. A number of commercial software packages support plug-ins that can add functionality in a straightforward manner. This includes PhotoShop, Quark Express, Hypercard and others. Another means of adding functionality is the use of a background-only application, AKA faceless-background application (fba). Fbas are applications without a user interface. One type of fba is known as an application extension. These are applications whose resource files are of type 'appe'. They are placed in the extensions folder (or the Startup Items Folder) and are started up after INIT time. They can communicate with other processes by Apple Events and by Gestalt selectors. If you don't need to patch a trap then an fba may be the way to add functionality to the system. Since an fba runs as a normal process there are some things that it can do that system extensions cannot do (or at least cannot do safely), like launch applications and send and receive Apple Events. An INIT resource in the resource fork of an application extension in the Extensions Folder will load normally at INIT time. See issue 9 of develop and the Tech Note PS 2 - Background-Only Applications for more info. Also consider an application that is started up by being placed in the startup items folder. The Screen Saver 'Dark Side of the Mac' is written in this way. Screen Savers are traditionally written as extensions because extensions can have access to the mouse location and all keyboard events. However an intelligently written application can do the same and be more compatible. If none of these things seems like it will work for you and you are thinking something like 'I want X to happen every time a resource is loaded', or otherwise add to or replace the system's functionality in some way then an extension is probably what you need. Remember that when developing system extensions you will be working without a net. -- [3] Can I write an INIT that makes the application menu into a hierarchical menu? Every couple of weeks someone posts a message on comp.sys.mac.programmer entitled 'Neat idea for an init'. These posts go on to describe some non-programmer's idea of a great INIT. Invariably these posts fall into two groups: those that have already been done, and those that should never be done. Think long and hard about the design of an extension before starting to write it. Consider your target audience. If it's only yourself then you can do what you want. My first couple of extensions were just tests to see if I could actually do it. The answer to the above question is: Maybe you can but probably you shouldn't. -- [4] Do I need to know assembler to write an extension? Yes. Strictly speaking, the simplest extension that just beeps at startup and doesn't hang around past INIT time requires no assembler. However, any extension that does anything useful will require some assembler in order to patch a trap or install a jGNEFilter. The extension can be written mostly in a high level language like C or Pascal, but there will be bits and pieces that need to be written in assembler to keep the stack happy or to access parameters passed in registers. Hopefully there will be enough sample code in this document to get you on your way if your assembler is weak. You will often need to inspect the disassembled source of your extension. If your development environment doesn't allow this the ResEdit Code Viewer will also allow you to inspect code resources. It can be found at ftp://ftp.apple.com/dts/mac/tools/resedit/resedit- extensions.hqx. -- [5] Can you show me a sample INIT? Here's the code for the 'Hello World' of INITs. void main(void) { SysBeep( 5 ); } Not very complicated is it? There are a number of additional things that are required to make this work: 1) Set the project type to code resource. 2) Set the resource type to 'INIT'. 3) Set the resource ID to something (>= 128), and set the resource name if desired. 4) Set the resource attributes to 'System Heap'. 5) Set the resource attributes to 'Locked'. 6) Set the filetype of the built code resource file to 'INIT' with any creator signature. 7) Set the filename of the built code resource file to 'Hello World'. Let me explain what each of these things does. 1) Because you're building a standalone code resource your compiler needs to know this. This is how the compiler knows to use A4 addressing, rather than the A5 addressing used in applications. 2) As mentioned above, extensions are code resources of type 'INIT'. 3) Like any other resources they have IDs and can have names. 4) Setting the system heap flag places the code resource in the system heap. While not strictly required for this sample, in most other extensions we will want the code resource to remain in the system heap so this flag must be set. During the process that loads and executes INITs a small heap is created. Any memory allocation done by the INIT will, by default occur in this heap. Also any resources read into memory will, by default, go into this heap. If the system heap flag isn't set for the INIT itself then the INIT will be loaded into this temporary heap. When the INIT exits the heap is disposed and anything in it is lost. If an INIT intends to stay around past INIT time then it must have the system heap flag set. 5) The code resource should never move in memory so the Locked bit is set. When a resource with the Locked bit is loaded into memory it is loaded as low in the heap as possible. This is what we want since the INIT resource will never be unlocked. It is poor design to not set the Locked bit and to rely on the INIT to lock itself. In that case the INIT will not be loaded low in the system heap. This isn't fatal but will lead to fragmentation of the system heap. Some INITs try to use MoveHHi/HLock to move themselves or associated resources high in the system heap. MoveHHi is disabled for the system heap. Since the system heap is dynamically sizable the concept of the top of the heap is invalid. For this reason MoveHHi does nothing when the handle being referred to is within the system heap. 6) The filetype of 'INIT' gives you the generic extension icon, and of course allows the extension to load and execute at INIT time. 7) Set the file name to something like 'Hello World'. Once these things have been done you can build the code resource and drag its file to the System Folder. The Finder should place it in the Extensions Folder for you and it should have the generic extension icon. When you restart you will hear the beep when the extension is loaded. Every extension must have a routine called 'main'. When the INIT resource is loaded into memory during INIT time the system jumps to the beginning of the code resource. The header of the code resource will normally contain a branch instruction that branches to the main routine. This routine does whatever it needs to do and then returns. In this 'Hello World' extension all that the main routine does is call SysBeep. In more substantial extensions the main routine will do things like patch traps, install gestalt selectors, and load resources into memory. -- [6] Can I have global variables in my INIT? Yes you can. The Think environment and the CodeWarrior environment use A4-based addressing for global variables in code resources. The base address of the extension is found in register A0 on entry to the extension, and routines are provided to save this value and to set up and restore register A4 when the INIT is entered later. (In fact the standard header installed by Think C in code resources loads the address of the code resource into A0 by use of pc-relative addressing.) See the A4-Addressing section of your development environment's manual for more information. When writing extensions with the MPW compilers you may need to use an A5-based method for accessing global variables. See the Apple tech note 'StandAlone Code, ad nauseam' (#256) for more information on this method. ftp://ftp.apple.com/dts/mac/tn/platforms.tools.pt/pt- 35-stand-alone-code.hqx and "Another take on Globals in Standalone Code", Keith Rollin ftp://ftp.apple.com/dts/mac/docs/develop/develop.12.code/globals-in- standalone-code.hqx Here is some sample code using the Think C routines to illustrate this: /****Main*****************************************************/ void main(void) //Main entry point of the extension { void *pToMe; Boolean initedOK; pToMe = GetA0(); //Save our address locally RememberA0(); //Save our base address SetUpA4(); //Set up A4-based addressing initedOK = InitAll(); //Patch traps etc. if ( initedOK ) { //Make sure we stay around DetachResource( RecoverHandle( pToMe) ); } RestoreA4(); //Reset A4 to its value on entry } This code sample also illustrates one method extensions can use to remain in memory after INIT time. Since extensions are code resources they will be removed from memory when their resource files are closed. This happens when the main routine exits. To avoid this, DetachResource must be called with the handle to the code resource. One common mistake with this is not having the code resource marked system heap. If it's not marked system heap it will be lost when the temporary heap is destroyed, whether it was detached or not. The GetA0 routine used above is defined in the tips section farther down in this document. Here are a few other methods for an extension to detach itself: void main(void) //Another method { asm { RecoverHandle //A0 already holdss our address move.L A0, -(A7) //DetachResource is stack-based DetachResource //so push A0 onto the stack } } void main(void) //This method uses no assembler { DetachResource( Get1Resource( 'INIT', kOurResID ) ); } -- [7] How do I debug an INIT? Debugging is generally the most time consuming, difficult, and all- around pain-in-the-neck part of producing good code. That goes double for INITs. Unfortunately many parts of INITs must be debugged with low level debuggers. The low level debuggers that I know about are MacsBug, TMON, and Jasik's Debugger. MacsBug is free and is available at ftp://ftp.apple.com/dts/mac/tools/macsbug/macsbug-6- 5d6.hqx. The two other low level debuggers are commercialware. Jasik's debugger has the ability to do source level debugging of code resources, like system extensions. In most cases, your low level debugger of choice will load before INIT time so it can be used to debug initialization of INITs. One exception to this is Jasik's Debugger, which loads in two parts. One of these is an extension that must load before your extension. The debugger can be invoked by calling the Debugger() or DebugStr() traps. Placing these trap calls in your code will drop you into the low level debugger so that you can step through your code and inspect registers or memory as needed. One useful technique is to take advantage of Macsbug's ability to process commands after a semicolon in a DebugStr call. The following function can display information that you would otherwise have to hunt down using hex offsets: pascal void SomeFunction (arguments) { // ... asm { MOVE.L fooP, A0 } // fooP can be any type asm { MOVE.L sizeof(*fooP), D0 } DebugStr ("\p ; dm rA0 rD0"); // dump (*fooP) in hex // ... } If you haven't placed Debugger() calls in your code then you will have to set a breakpoint in order to step through any trap patches or other parts of your extension. Here are a couple of methods to do that. If you have patched a trap, say GetResource, if you drop into MacsBug and type 'il GetResource' MacsBug will begin to disassemble at your patch. You can then set a breakpoint by typing 'br GetResource' or br theaddress' where theaddress is the address in hex of your patch or some part of it. Type 'brc' when you want to clear all breakpoints. Using the A-trap commands will also work. 'atb GetResource' will set a break and 'atc' will clear all A-trap breakpoints. If you want to set a breakpoint in some other part of your extension, say in a jGNEFilter, then you need another way of finding its location in memory. In MacsBug type 'hx syszone^' or just 'hx' to set the current heap to the system heap (where your extension is located). Type 'br ' (don't hit return yet) and then type cmd-D to view the names of all the routines in the system heap that were compiled with MacsBug names turned on (like yours, right?) Scroll down until you find the name of your routine. Hit enter and the command line should look like 'br yourRoutineName'. Hit enter again and the breakpoint will be set. You can also simply type 'br yourRoutineName' and MacsBug will find it for you. The zone must be set to the zone containing the routine that you want to break on for MacsBug to find it, so make sure to set the zone to the system zone. Identifying your extension in the system heap is dependent on compiling it with the MacsBug symbols option turned on. This inserts Ascii versions of the names of each function in the compiled code in such a way the MacsBug , and other debuggers can find these names. Jasik's debugger uses a different method for identifying your code that is based on SYM files, which are generated by your compiler. The SYM files allows Jasik's debugger to do source level debugging of INITs and other code resources. I have used a two-project method, when developing INITs and other code resources, that helps to cut down debugging time. Any extension consists of essentially two parts: the initialization portion and the implementation portion. The initialization portion detaches the resource as described above, shows the icon, and often patches traps. The implementation portion contains the actual trap patches. It is quite possible, and desirable, to test the implementation portion in the context of an application, rather than as an INIT. To accomplish this your project consists of three parts, which for a simple case would be three files. TesterApp Project: SetUpApplication.c Simple application shell that sets up the trap patches and provides a mechanism to call the traps TrapPatches.c Code for the trap patches INIT Project: SetUpINIt.c Standard INIT setup; contains main entry point; patches all necessary traps TrapPatches.c Code for the trap patches; same file as in the TesterApp Project The mechanism for calling the traps in SetUpApplication.c is usually a menu item. In some cases it might be a dialog with several buttons, each of which calls a particular trap. It isn't always necessary to patch traps in your TesterApplication. Simply calling the routines that implement the guts of the trap patches will often be just as good. Having two projects, one that builds the tester application and the other that builds the extension, allows you to save time debugging and to be able to build the extension at any time. Writing and testing extensions involves multiple rounds of 'compiling-installing the INIT-rebooting-Stepping through the INIT in a low level debugger'. Use of the two-project method will cut down this time. -- [8] How do I write a Control Panel-INIT combination? System extensions generally have no interface. They do what they do quietly and the user doesn't want to hear from them. In many cases the user needs to set certain preferences. The natural mechanism for this is to couple a control panel with an INIT. The problem of course is how does the control panel communicate the changes to the INIT. I won't discuss the general mechanisms of control panel authoring here (see NIM: More Macintosh Toolbox, Chapter 8), but there are several mechanisms available for communicating between extensions and control panels. The simplest mechanism and one that will work in the vast majority of cases is for the extension to install a Gestalt selector. This selector returns the address of a block of memory that holds variables that control the actions of the extension. The control panel calls the Gestalt selector, retrieves the address of the memory block, and alters the values stored in the block as needed. In some cases the memory block can contain a function pointer to a function in the extension that needs to be called from the control panel. Here is some sample code: typedef struct CommonInfo{ void (*ResetINIT) (void);//function pointer to reset //func Boolean On; }; #define kSignature 'BLAH' //Should be the sig of the INIT static CommonInfo gInfo; /**InstallGestaltSelector****************************************/ //In the INIT; runs at INIT time OSErr InstallGestaltSelector(void) { OSErr err; err = NewGestalt( kSignature, OurSelector ); if ( err == noErr ) { gInfo.ResetINIT = (void *) ResetFunction; gInfo.On = TRUE; } return err; } /**OurSelector**************************************************/ //In the INIT pascal OSErr OurSelector( OSType theSelector, long *theResponse ) { SetUpA4(); *theResponse = (long) &gInfo; RestoreA4(); return noErr; } /**ResetFunction***********************************************/ //In the INIT void ResetFunction(void) { SetUpA4(); //Do something here RestoreA4(); } /**Close********************************************************/ //In the Control Panel void Close( Boolean IsOn ) { long result; CommonInfo *Info; //Get address of globals struct from init err = Gestalt( kSignature, &result ); if ( err == noErr ) { Info = (GlobalsType *) result; Info->On = IsOn; //Reset OnOff Boolean ( * (*Info).ResetINIT) (); //Jump to INIT } } If it is possible for an error to occur that prevents the extension from resetting itself the ResetFunction should return an error code and the control panel should display an alert indicating the problem. Two additional methods are sometimes used to accomplish communication between an extension and a control panel: The first of these is to write a driver that is installed by the extension. The driver holds global variables and will return the address of the block of memory holding these variables in response to i/o, status, or control calls to the driver. Sample code showing how to do this is available in a package called driver-22 written by Pete Resnick to be found at: ftp://sumex-aim.stanford.edu/info-mac/dev/src/driver-22-c.hqx.gz The second additional method is to use the PPC toolbox for direct communication. There is sample code demonstrating this at: ftp://ftp.apple.com/dts/mac/sc/7.0.samples/init-cdev.hqx. -- [9] How do I capture keystrokes? This is accomplished by writing a jGNEFilter function. jGNEFilter functions are called from GetNextEvent and WaitNextEvent just before those traps return to an application. They are passed a pointer to the event record that will be returned to the application. In order to capture keystrokes the jGNEFilter would simply check the what field of the event record looking for keyboard events and would extract the information from the message field if one were found. The jGNEFilter mechanism is very powerful and is one way that screensavers can be implemented. The filter would save the time of any keyboard events and would compare the location of the mouse against its previous location on null events. If the preset time had elapsed during which no keyboard events or mouse movement had occurred then the screen saver would activate. A more complete discussion of the jGNEFilter is in the next section. If you are thinking of patching WaitNextEvent or PostEvent in order to capture keystrokes or other events, don't. Use a jGNEFilter instead. It's easier, it's compatible. It's even documented. See the Tech Note 'GetNextEvent; Blinking Apple Menu' (#85). ftp://ftp.apple.com/dts/mac/tn/toolbox.tb/tb-11-getnextevent.hqx -- Brian Stern :-{)} Toolbox commando and Menu bard Jaeger@fquest.com --------------------------- >From Jaeger@fquest.com (Brian Stern) Subject: INIT Writing FAQ [2-3] Date: 28 Oct 1994 00:42:44 GMT Organization: The University of Texas at Austin, Austin, Texas -- [10] How can my extension get time periodically? Installing a jGNEFilter is one method of obtaining periodic time. Since the jGNEFilter mechanism is dependent on the event processing mechanism, one problem is that no events may be posted if the mouse is held down for an extended time. If your INIT only needs to get time every once in a while then I recommend that it only do its thing on null events. On other events it should just return. This will have the least impact on the machine's performance. Remember that your jGNEFilter will be called for EVERY event on the machine. Do not do a lot of processing on every event or you will be slowing down the machine needlessly. Another way to reduce the frequency of your extension's processing is to use a simple timer, based on TickCount(). In this way your processing is only done, say, every 30 or 60 ticks, on null events of course. Sample code demonstrating jGNEFilters can be found in a package called jGNE Helper by Pete Gontier in the alt.sources.mac archive at: ftp://ftpbio.bgsu.edu/ftp/pub/alt.sources.mac/vol- 01/jgnehelper.cpt.hqx. Another sample in MPW assembler is at ftp://ftp.apple.com/dts/mac/sc/snippets/toolbox/jgnefilter.hqx. Here's another example that works in Think C: static ProcPtr gOldGNEFilter; /****InstallFilter***********************************************/ //Run this at INIT time void InstallGNEFilter (void) { /*Save the ProcPtr to the previous jGNEFilter and insert ours*/ gOldGNEFilter = JGNEFilter; JGNEFilter = (ProcPtr) StripAddress( FilterProc ); } /****FilterProc**************************************************/ void FilterProc(void) { EventRecord *theEvent; long SaveD0; theEvent = GetA1(); //Move the eventPtr to a variable SaveD0 = GetD0(); //Preserve D0 SetUpA4(); switch ( (*theEvent).what ) { case nullEvent: //Do our thing break; case keyDown: //Do something else break; } //Execute the previous jGNEFilter SetA1( theEvent ); //Restore A1 for the next jGNEFiler SetD0( SaveD0); //Restore D0 SetA0( gOldGNEFilter ); //Put next jGNEFilter in A0 RestoreA4(); asm{ Unlk A6 Move.W D0, 4(A7) ;Set Function result on the stack JMP (A0) ;Jump to the next jGNEFilter } } Since a jGNEFilter has access to the actual event record that will be returned to the application, the filter can alter the event. The most common thing to do is to 'cancel' an event by changing it to a null event (Ex. theEvent->what = nullEvent). In this case it should also set the value in register D0 to False, or zero. Here are some additional methods for an extension to get time periodically: If your extension needs more frequent or regular time then can be provided by a jGNEFilter then you can install a VBL task or a time manager task. Since these run at interrupt time they cannot do anything that could move or purge memory. Other methods include patching a trap that is called frequently, like SetPort. A faceless Notification Manager request is another method to get time. This is a request that has all the fields in the notification record set to NULL except the nmResp field that holds the address of your routine to be executed. Your notification response routine will be called soon and will be able to move memory. If necessary the routine can reinstall itself. This technique is useful for tasks that need to be executed once or intermittently. For those tasks that need to be executed regularly use one of the other techniques. You could of course have a faceless NM request that is installed by a VBL task or a time manager task. Use of a faceless background application in concert with an extension is yet another method to get time. The fba would do its work on its null events. -- [11] How should an INIT manage memory? In general, at INIT time extensions will want to allocate memory in the system heap. If you are allocating pointers or handles, use the SYS variants, like NewHandleSys() and NewPtrSys(). It is a common error to forget this and then to wonder why the INIT crashes. If you call NewHandle at INIT time, the handle will be allocated in the temporary heap allocated for your extension. If your INIT attempts to use it after INIT time the temporary heap will be long gone, along with any handles or pointers that had been allocated in it. Any attempt to use handles or pointers that no longer exist are predictably unpredictable :-) NewHandle and NewPtr will allocate their memory blocks in the system heap if the zone has been set to the system heap, as shown in the next paragraph. If you need to read in resources you can ensure that they go into the system heap with something like the following code: THz saveZone = GetZone(); SetZone( SystemZone() ); //read in resources SetZone( saveZone ); You will of course need to detach the resources if they need to remain in memory after your extension exits. The resource file containing your extension will be closed when your extension exits. If you need to read resources into memory after INIT time you need to decide which heap they should go into, either the application heap or the system heap. It's a bit hard to make a specific recommendation on this but if the resource is something that the application is expecting to be read in then it should go into the application heap. This would include things like WIND resources in a trap patch to GetNewWindow(). The problem of course is that the application heap may not have enough room. However, if the resources are private to the extension then they should go into the system heap. It should go without saying that you should always check the error codes on memory allocating calls and resource manager calls. If your extension is doing something in response to a user action, say making a network connection, then it is appropriate to report such errors. In many cases however, your extension will simply do nothing in the case of out of memory errors or missing resource errors. It is best to attempt to allocate all of these things at INIT time and if unsuccessful to bail out then. As mentioned above, MoveHHi doesn't work in the system heap. If you intend to allocate a handle that will remain locked for extended periods, then call ResrvMem before allocating and locking the handle. This will place the handle low in the system heap and help to prevent heap fragmentation. Many toolbox calls are documented as not moving or purging memory and as being safe to call at interrupt time. If you are patching one of these traps then you must preserve this property. You are guaranteed to cause other software to crash if you don't, and your users will hate you (once they figure out that it's you). Be aware that the only memory manager routine safe to call under these circumstances is BlockMove. Also be aware that it is unsafe to access an unlocked handle at interrupt time. It is possible that the memory manager is in the midst of moving it from one place to another in the heap, and the master pointer may not be updated yet. -- [12] How do I get my INIT to turn itself off? An extension might want to turn itself off at INIT time based on its preferences setting, or based on a key being pressed or the mouse button being pressed, or due to an error during initialization. Extensions usually show an icon with a red X through it in this case. An extension might also want to turn itself off temporarily after INIT time in response to its Control Panel. For instance GateKeeper has an on/off switch that turns off virus checking for a set time. The strategy for temporarily turning off an extension is simply to set a global flag and to check it from within the trap patches or other parts of the extension. If the flag is off then the trap patch simply executes the previous trap. It is generally unsafe to unpatch or patch traps after INIT time from an extension. The reason for this is that if another extension patches the same trap after you have, then it will be jumping to your patch when it has completed its work. If you have removed your patch then this calling chain will be disrupted and bad things will happen. Also, the Finder patches various traps when it loads, which is after INIT time. Disrupting those patches would be a very bad thing. If an extension determines at INIT time that it isn't going to stay around then it shouldn't call DetachResource on itself. It's best that your extension determine that anything it's dependent on, such as resources, specific system Managers, and sufficient memory, are present *before* it starts to patch traps and install drivers, jGNEFilters and so on. It would be a very bad idea for an extension to not detach itself after it had already patched a trap if the trap patch resided in the extension. Many extensions use a particular key press as a signal to indicate that the user wants them not to run. Of course the system uses the shift key as a signal not to turn on any extensions so you can't use that. Some extensions use the option or command keys for this purpose. The problem with using those keys is that every time I rebuild the desktop those extensions are needlessly inactivated. I recommend that the space bar be used for this purpose. Here's some sample code: Boolean SpaceBarIsDown(void) { KeyMap theKeys; GetKeys( theKeys ); if ( theKeys[1] & 0x00000200 )//Check for spacebar return TRUE; else return FALSE; } -- [13] How do I get my INIT to show it's icon like all the other cool inits do? This is easy. There is code available that does this for you. Get a package written by Jim Walker called ShowIcon7 at: ftp://mac.archive.umich.edu/mac/development/source/showicon7.sit.hqx You use it essentially as a plug-in. Just pass in the icon's resource ID and it does everything for you. It also shows how to set up an A5 world in an extension. You might also take a look at Dair Grant's Extension shell package. This one shows how to do animated icons. If your extension decides that it can't install itself then it passes the resource ID of an icon that has a red X through it to the showicon7 code resource. Some extensions include the ShowIcon code within their own code resources. This code is only about 1K but it seems pointless to me for this code to sit in the system heap when it doesn't have to be. Use it as a plug-in for your extensions. -- [14] How do I show a dialog from my INIT? First of all, I hate windows of any kind during the startup process. If all you want to do is show an alert then use the Notification Manager. Your alert will show up when the Finder starts but the user will see it and will get whatever message you need to send. The problem I have with windows at INIT time is that they slow down this process and require user interactivity in a process that shouldn't do so. Consider the computer that is on 24 hours a day doing something important unattended. The power goes off and when it comes back on the machine reboots. The user returns several hours later to find that the machine is still in the middle of its startup because your alert is waiting for a response. Consider also the hapless INIT writer who has to reboot his machine 20 times a day. Your INIT will not last long on my, um, his machine. One additional annoyance is that you need to call InitWindows to show your window and this erases all the nice INIT icons on the screen. I hate that. Here are a few possible alternatives. * Play a sound or use the Speech Manager to communicate the information. * Show a different icon during startup to indicate an error. An icon with a red X through it is one way to do this. You could also use animated icons. * If you must put up an alert then use a timer so that the alert goes away by itself, even if the OK button isn't clicked. * If you need to interact with the user to get some information, say a password for a network connection, then do this once and save the results in a preferences file. Provide a Control Panel to change the information. Think of Control Panels as the interface for extensions. * Store descriptions of any errors that occur in a preferences file. Have the Control Panel display this information. Remember to clear this information on each restart and to indicate to the user by sound or icon that an error has occurred. * If you need to communicate error information to the user after INIT time then you should definitely use the Notification Manager. For example, MacSLIP uses the NM to show an alert indicating that the carrier has been lost. If you still want to show a dialog at INIT time then you need to set up an A5 world first. The ShowIcon7 code mentioned above shows how to do this. Also see the Tech Note 'Stand-Alone Code' (#256) for an explanation and sample code for this and 'Giving the (Desk)Hook to INITs' (247) discusses a bug that can appear when showing windows from extensions. ftp://ftp.apple.com/dts/mac/tn/operating.system.os/os-02-deskhook- and-init.hqx If you do use the Notification Manager from an extension to indicate that the extension couldn't load you should use a self-disposing Notification request. There are several strategies for doing this. I have some code samples for this that will be (have been?) posted to alt.sources.mac soon. -- [15] How do I maintain compatibility with future systems? This is tough, and the short answer is that you probably don't. You'll notice that Apple comes out with new versions of its extensions with each revision of the system. Apple's extensions also eventually disappear as their functionality is rolled into the system. In all likelihood you'll have to come out with new versions of your extensions as new versions of the system come out as well. Having said all that, there are things you can do to minimize this problem. Here are a few suggestions: * Minimize your reliance on undocumented features of the system. * Minimize your reliance on low memory globals. Use the Universal Header access 'functions' for accessing the low memory globals if necessary. * Use system features like Gestalt, the Process Manager, and the Notification Manager to get information about the system, and to communicate with the user. * Try to patch as few traps as possible and use non-patching methods whenever possible (e.g., use a jGNEFilter instead of patching WaitNextEvent; the filter is more likely to remain compatible than your patch). * Don't use self-modifying code. Self-modifying code changes the instructions from what they were compiled as, to something else, at run-time. The classic example is to change the address in a JMP instruction at run-time so that it jumps to the address of the previous trap. This may seem faster than using a global variable but it is only slightly faster. It is harder to write, debug, and maintain self-modifying code, and it is definitely more likely to break with new system releases. If you do use self-modifying code, remember to flush the cache. See the tech note 'Cache As Cache Can' (#261) for more information on that subject. * Use the Universal Headers for writing your extensions. This will help to ease the transition when it comes. -- [16] Any tips for INIT writing? You may not want your INIT to actually do anything until after INIT time. You can find the end of INIT time if you have a jGNEFilter installed when the first null event occurs. The Notification Manager doesn't usually start processing requests until INIT time is over so posting a faceless notification request is another method to find the end of INIT time (probably the best if you don't need a jGNEFilter for something else). You can also patch Launch to find the end of INIT time but this is trickier. Unfortunately some extension writers do put up windows during INIT time. Because of this it's possible that events will occur before INIT time is over. To fail-safe the above approaches you also need to check for the presence of the Process Manager with a Gestalt call. The Process Manager isn't available until after INIT time. If Gestalt reports that the Process Manager is not available then you need to reinstall your NM request, or simply wait for another event to be reported to your jGNEFilter when the Process Manager is available. Here are some utility routines that can reduce the need for 68K assembler in your extensions: pascal void SetA0( void* ) = { 0x205F }; pascal void SetA1( void* ) = { 0x225F }; void * GetA0( void ) = { 0x2008 }; void * GetA7( void ) = { 0x200F }; - ------------------------------------------------------------------- Trap Patches: -- [17] What exactly is a trap patch? A trap patch is a method for changing the functionality of a trap. The addresses of all the traps are maintained in the two trap dispatch tables. By using the routine NSetTrapAddress and friends you can change the address of a particular trap to code that you provide. When this is done at INIT time, all calls to the patched trap from all applications will go to your code, which in most cases will do something and then call through the existing trap in the ROMs. Be warned that the Finder patches some traps when it starts up in a way that prevents previously-installed patches from executing. I recommend that you read the descriptions of the trap dispatch mechanism in the 'Using Assembly Language' chapters in IM I and IV and also in the 'Trap Manager' chapter in NIM Operating System Utilities. Traps come in several types based on their parameter passing conventions. Most toolbox traps use pascal calling conventions, which means that all parameters are passed on the stack and the return value, if any, is placed on the stack. Some traps use register-based calling conventions. In these traps the parameters are passed in registers and the return value is returned in a register, usually D0. For example all the Memory Manager traps are register-based and the File Manager traps are also register-based. Some traps are selector-based. There are only so many spots in the trap-dispatch tables. In order to preserve space in these tables selector-based traps have been developed. In these traps a single trap serves as the front end for a number of system routines. The parameters of these traps are passed in the usual manner, either on the stack or in registers, and a selector is also passed, usually in a register. When the trap is called it checks the selector and then dispatches to the appropriate routine. Patching each of these types of traps involves different mechanisms. We'll look at samples of each one. Patching traps on the PowerMac is a bit different than on the 68K Macs. Most of the discussion here is aimed at patching traps on the 68K Macs. Hopefully I'll learn some more about this subject soon and there will be some better info here on patching traps on the PowerMac. -- [18] What's the difference between a head patch and a tail patch? It is most common to add some functionality to a trap when patching it rather than just replacing the existing trap. For instance I've written an extension that speaks the text in alerts by using the Speech Manager. This works by patching Alert and friends. When Alert is called the patch gets the text that appears in the alert and passes it to the Speech Manager. The patch then calls the existing Alert trap that is in the ROMs. A patch that works in this way is called a head patch; it does its business and then it calls the previous trap. A tail patch is a bit different. A virus-checking program might want to patch GetResource and then examine the resource that was read in to see if it contains a virus. In order to do this the patch must first call the existing trap and then do its processing, and finally return to the application. This is a tail patch because some processing occurs after the existing trap is called. In order for a patch to be a head patch you must use a jmp instruction to jump to the previous trap. If you use a jsr or a C function pointer to jump to the previous trap you have a tail patch. The reason that this head and tail patch business has been so important in the past is because of an Apple invention called the come-from patch. Patches were invented, of course, so that Apple could fix bugs in the ROMs and could update the routines in the ROMs with software. This is why you can run system 7 on a Mac Plus, whose ROMs are obviously missing most of the additions made to the toolbox in recent years. Certain ROM routines are particularly large so it is inconvenient to patch them if they have bugs in them. To get around this problem the Apple programmers searched for smaller routines that are called from the large buggy routines and placed patches in the smaller routines. These patches check the return address on the stack. If it is the address of the buggy routine then a fix is applied. If not then they just go on as usual. The patches to these smaller routines are known as come-from patches. If you tail patch one of these and then call the existing come-from patch, the return address on the stack will be in your patch and not the buggy routine that called you. In this case the come-from patch will not apply its fix and your system will crash. The good news is that as of system 7 it is safe to apply tail patches. The come-from patches still exist in system software, but NGetTrapAddress has been modified to return an address that is safe to use when applying tail-patches. However, if you wish your extension to run in System 6 then tail-patches are not allowed. This is documented in the Trap Manager chapter in NIM: OS Utilities. If you absolutely positively need a tail patch in System 6 then the following logic may apply: (Just don't tell anyone that I told you this :-) Apple is not releasing any new versions of System 6 so no new come-from patches will be forthcoming for System 6. If you do careful testing of the traps you wish to tail-patch you will probably be OK. In general traps not called from the ROMs, like Alert and MenuKey, will not contain come-from patches. One final thing: In system 7 it is safe to apply tail-patches to all traps except FrontWindow. -- [19] How do I patch a trap? Here is some sample code for a head patch of Alert, a stack-based trap: TrapPtr gOldAlertTrapAddress; /****InstallPatch***************************************************/ void InstallPatch (void) { gOldAlertTrapAddress = GetToolTrapAddress( _Alert ); SetToolTrapAddress( (long) AlertPatch, _Alert ); } /****AlertPatch***************************************************/ pascal void AlertPatch( short alertID, ProcPtr filterProcPtr ) { SetUpA4(); MyAlert( alertID) ; //Do our thing //store the correct alert addr //in A0 while we can still access globals via A4 asm { move.l gOldAlertTrapAddress, A0 } RestoreA4(); asm { unlk A6 //match the link generated by C jmp (A0) //jump to _Alert } } There are a number of details to note here. This patch is of course part of a code resource that is loaded at INIT time and detached as described in an earlier section. The routine InstallPatch must be called at INIT time. The routines GetToolTrapAddress and SetToolTrapAddress allow you to get and set the addresses of Tool Traps. The similar routines GetOSTrapAddress and SetOSTrapAddress allow you to manipulate the addresses of OS traps. The routines NGetTrapAddress and NSetTrapAddress allow you to manipulate the addresses of either, although they call glue code. I recommend that you use the GetXTrapAddress and SetXTrapAddress calls. There are two obsolete calls: GetTrapAddress and SetTrapAddress. Don't use them. The prototype for this patch is declared as 'pascal void' while the prototype for Alert is 'pascal short'. Because this is a head patch it will not be returning a result; the result will be returned from the real Alert trap. The pascal keyword is used to indicate pascal calling conventions. It is not strictly required in all cases but does no harm. The Think C routines SetUpA4 and RestoreA4 are called to allow access to global variables by A4 addressing. In this case gOldAlertTrapAddress is the only global variable we are addressing, unless any are used inside MyAlert. Note that this variable is moved to A0 while access to global variables is still available. In some cases one might move a global variable to a local variable, which doesn't rely on A4 addressing. A4 could then be restored and the old trap address could be loaded into A0 later in the code. Because there is a parameter list the compiler generates a Link A6 instruction at the start of this function. In order to restore the stack a matching Unlk A6 must be placed at the end of the function. Since we are exiting by the jmp (A0) we must insert the Unlk A6 ourselves. The compiler does generate an Unlk A6 and an RTS at the end of this function, but they will never be executed. The presence of the Link A6 instruction is dependent on the particular compiler you use and on its rules for generating a stack frame. It is a good idea to disassemble the code for your trap patches to see whether a stack frame has been generated in order to determine if you need to insert the Unlk A6 instruction. If you don't match the Link A6 with an Unlk A6 the stack will be screwed up. It is essential that the stack look exactly the same on exit from a head patch as it does on entry. If not you will surely crash. (If you had good reason you could modify the value of a parameter on the stack, but that's another story.) This patch saves and restores A4 but does modify A0 and A1 (SetUpA4 uses A1). In general, with head patches of stack-based traps you can modify A0, A1, D0, D1, and D2, but not any other registers. You may need to look at the disassembled code to be sure that all your registers are properly saved and restored. The design of the patch as shown here, with the patch code calling a separate function to perform the actual functionality of the patch is a good design to follow with all but the simplest of patches. You might think that you need to call StripAddress on the address of the patch routine before passing this address to SetToolTrapAddress. This is not necessary unless the address is actually a handle. If you were to load a code resource and pass its entry point to SetToolTrapAddress then it would need to be stripped. -- Brian Stern :-{)} Toolbox commando and Menu bard Jaeger@fquest.com --------------------------- >From Jaeger@fquest.com (Brian Stern) Subject: INIT Writing FAQ [3-3] Date: 28 Oct 1994 00:44:27 GMT Organization: The University of Texas at Austin, Austin, Texas -- [20] How do I patch a register-based trap? Here is the code for a sample register-based trap patch: TrapPtr gMountVolAddress; /****InstallPatch**************************************************/ void InstallPatch(void) { gMountVolAddress = GetOSTrapAddress( _MountVol ); SetOSTrapAddress( (long) MountVolPatch, _MountVol ); } /****MountVolPatch************************************************** This is a register-based trap that has A0 set to point to its parameter block on entry. The prototype for MountVol is: pascal OSErr PBMountVol( ParmBlkPtr paramBlock ) This patch beeps when a floppy or CD-ROM is inserted or when a harddrive is mounted by the Finder. *******************************************************************/ pascal void MountVolPatch(void) { //Save some registers //Save A0 since it's trashed by SetUpA4 //D1 contains the trap word asm { movem.l a0/d0-d1, -(sp) } SetUpA4(); //Allow access to global variables SysBeep( 5 ); //The guts of our head patch //store the correct MountVol addr //in A1 while we can still access globals via A4 asm { move.l gMountVolAddress, A1 } RestoreA4(); //Restore previous value in A4 asm { //Restore the registers movem.l (sp)+, a0/d0-d1 jmp (A1) //jump to _MountVol } } This head patch is similar in structure to the patch to Alert with a few differences. The prototype uses no parameters and has no return value. The single parameter is passed through A0. This patch doesn't do anything with this value but it could be moved to a local variable and then used to reference the fields in the parameter block if desired. Access to global variables is by the same A4 mechanism as in the Alert patch. Note that _MountVol is an OS trap so GetOSTrapAddress and SetOSTrapAddress are used to set up the patch. Since A0 is used to pass the parameter to this trap we jump to the real _MountVol trap through A1. Obviously A0 must be saved and restored in this patch. OS traps expect to find the trap word in D1 so it must be saved and restored as well. Three registers, A0, D0, and D1, are saved onto the stack with the movem instruction, and restored at the end of the patch. Think C doesn't generate a 'Link A6' at the start of this function because there are no parameters and no local variables. Because of this no 'Unlk A6' is needed at the end of the function. -- [21] Can you show me an example tail patch? Here is another example of a patch to a register-based trap. This sample is a tail patch and is dependent on the CodeWarrior environment. Because CW allows you to specify that parameters are passed in registers this trap patch requires no assembly. extern pascal OSErr (*Old_MountVol)( ParmBlkPtr pb : __A0 ) : __D0; pascal OSErr My_MountVol( ParmBlkPtr pb : __A0 ) : __D0 { OSErr err; long saveA4 = SetCurrentA4(); err = Old_MountVol( pb ); DoSomthingFunc(); SetA4( saveA4 ); return err; } -- [22] How do I patch a selector-based trap? Here is a sample patch to PrGlue. This trap is the front end for all the Printing Manager routines. Its selector is pushed on the stack typedef struct { long Selector; THPrint hPrint; } PrJobDialogStack; TrapPtr PrGlueAddress; /****InstallPatch**************************************************** / void InstallPatch(void) { PrGlueAddress = GetToolTrapAddress( _PrGlue ); SetToolTrapAddress( (long) PrGluePatch, _PrGlue ); } /****PrGluePatch**************************************************** This is a stack-based trap with a long word selector also pushed onto the stack. On entry the selector is at 4(A7). The return address is at 0(A7). After the 'Link A6' the selector is at 12(A7). *******************************************************************/ #define kSelectorOffset 12 #define kPrJobDialogSelector 0x32040488 pascal void PrGluePatch(void) { PrJobDialogStack *StackPtr; //Get address of the stack frame //and save it in a local variable asm { lea kSelectorOffset(A7), A0 move.l A0, StackPtr } SetUpA4(); //Allow access to global variables //Check the selector if ( StackPtr->Selector == kPrJobDialogSelector ) { SysBeep( 5 ); //Pass hPrint to our function to do something DoSomethingFunc( StackPtr->hPrint ); } //Store the correct PrGlue addr //in A0 while can still access globals via A4 asm { move.l PrGlueAddress, A0 } RestoreA4(); //Restore previous value in A4 asm { unlk A6 //match C's Link A6 jmp (A0) //jump to _PrGlue } } In order to access the selector and the parameters for PrGlue we use a pointer to a struct. Once the pointer is initialized correctly we can access the selector and any parameters from C easily. According to NIM: PPC System Software it is not safe to patch selector-based traps with PPC native code. All patches of selector- based traps on the PowerMac should be written in 68K code. -- [23] How do I patch a trap on the PPC? See NIM 'PowerPC System Software' for a more complete discussion. There is also a new book by Tom Thomson called 'Power Macintosh Programming Starter Kit' that has examples of how to patch traps on the PowerMac. Patching traps on the PowerMac is similar to patching on the 68K architecture. Of course you must generate a UniversalProcPtr for each of your patches in the system heap, and these are then passed to the SetXTrapAddress routines. Since code fragments have their own globals the use of A4 or A5-based mechanisms for accessing global variables isn't needed. In order to call the previous trap you need to call CallUniversalProc or CallOSTrapUniversalProc and return its result from your patch. As a result all patches on the PowerMac are tail patches. You may find an application called 'Traps Check' useful. This app supplies a report about all the traps on a Powermac, indicating whether each trap is emulated or native. Another way to do this is to drop into MacsBug and disassemble from the address of the trap you're interested in (e.g., 'il CopyBits' ). For traps that are native you'll see a routine descriptor that begins with the MixedModeMagic trap (AAFE). This of course won't tell you if the trap has been patched. You can identify a patch by whether it's in RAM or ROM, from its address. Determining whether a patched trap is PPC native or not may take some additioinal sleuthing. You can find Traps Check at: ftp://sumex-aim.stanford.edu/info-mac/dev/traps-check- 10.hqx Here is a sample PowerMac trap patch for GetResource: UniversalProcPtr gGetResourceUPP; UniversalProcPtr gGetResourcePatchUPP; /****InstallPatch**************************************************/ void InstallPatch(void) { gGetResourceUPP = GetToolTrapAddress( _GetResource ); gGetResourcePatchUPP = NewRoutineDescriptor( (ProcPtr) GetResourcePatch, kPascalStackBased, GetCurrentISA() ); SetToolTrapAddress( gGetResourcePatchUPP, _GetResource ); } /****GetResourcePatch*********************************************/ Handle GetResourcePatch( ResType theType, short theID ) { Handle result; //We don't need no 'DUMB' resources if ( theType == 'DUMB' ) result = NULL; else result = (Handle) CallUniversalProc( gGetResourceUPP, kGetResourceProcInfo, theType, theID ); return result; } -- [24] Can I write a fat trap? //Under construction -- [25] Tips? If your patch isn't called you may have guessed wrong on whether it's a ToolTrap or an OSTrap. The high bit of the second byte of the trap word is set for ToolTraps. The following function can be used to get the correct trap address for both ToolTraps and OSTraps. pascal void * GetCurrentTrapAddress( unsigned short trapWord ) { if ( trapWord & 0x0800 ) return GetToolTrapAddress ( trapWord & 0x07FF ); else return GetOSTrapAddress ( trapWord & 0x07FF ); } If the machine crashes after leaving your patch you have probably munged the stack or not saved and restored all the registers that you must. The Finder patches a number of traps when it loads in a way that prevents earlier trap patches from functioning. If your patch doesn't appear to be called it may be one of these patches. -- [26] What other sources of information are available? Knaster 'How to Write Macintosh Software' Knaster and Rollin, 'Macintosh Programming Secrets'. These books on Mac programming has some excellent info on trap patching. Tom Thomson 'Power Macintosh Programming Starter Kit' This book has some example code for writing trap patches and extensions on the PowerMac. The Extension Shell package at: ftp://sumex-aim.stanford.edu/info-mac/dev/src/extension-shell-13.hqx Dair's email address has changed to: dair.grant@ucl.ac.uk. Usenet Macintosh Programmers Guide ftp://sumex-aim.stanford.edu/info-mac/dev/info/usenet-mac-prog-guide- msw.hqx All of the Apple Tech Notes have been made available on Apple's web server: http://www.info.apple.com/dev/technotes/Main.html -- Brian Stern :-{)} Toolbox commando and Menu bard Jaeger@fquest.com --------------------------- >From shawnl@andyne.on.ca (Dave Charlesworth) Subject: Linking 68k object files to PPC program Date: Thu, 27 Oct 1994 19:26:03 GMT Organization: Andyne Computing I want to link some third party code to a PowerPC program. Can someone point me to documentation on how to make this work? I don't have source for the third party stuff. I'm using MPW (ETO 15) cross- platform tools (PPCLink, PPCC), and have the Inside Mac volume "PowerPC System Software". I haven't been able to find anything in it or in the ETO documentation, but it must be somewhere! Thanks. Shawn Leclaire +++++++++++++++++++++++++++ >From zellers@pokey.basilsoft.com (Steve Zellers) Date: Fri, 28 Oct 1994 20:52:49 -0800 Organization: BasilSoft, Inc. In article , shawnl@andyne.on.ca (Dave Charlesworth) wrote: > I want to link some third party code to a PowerPC program. Can someone > point me to documentation on how to make this work? Assuming you mean that the third party code is 68k, you can't. You'll have to write a stub code resource that re-exports all the symbols you need through a paramblock as some sort using route descriptors. --smz +++++++++++++++++++++++++++ >From wdh@fresh.com (Bill Hofmann) Date: Sat, 29 Oct 1994 18:27:36 GMT Organization: Fresh Software In article , shawnl@andyne.on.ca (Dave Charlesworth) wrote: > I want to link some third party code to a PowerPC program. Can someone > point me to documentation on how to make this work? > > I don't have source for the third party stuff. I'm using MPW (ETO 15) > cross- platform tools (PPCLink, PPCC), and have the Inside Mac volume > "PowerPC System Software". I haven't been able to find anything in it > or in the ETO documentation, but it must be somewhere! > Nope, not really. Maybe some of the MacTech articles have mentioned it. But what you have to do is: * find out which routines *you* call in the library * write some 68k code that wraps the library in a way that you can call it: either use a selector-based approach (ie, if message==1, call function 1, etc) or make a routine that returns a table of procptrs * compile/link the wrapper with the library * create proc infos and stub code to call your 68k wrapper in your PowerPC program * debug :-> Or, yell at the third party until they produce a PowerPC version (shared library, or whatever). -Bill -- 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 rjkmehta@bu.edu (Ravi Mehta) Subject: Network Programming Date: 19 Oct 1994 16:20:21 GMT Organization: Boston University I want to write some networkable software, but am completely new to network programming. Besdies IM: Networking ( which I will pickup ) is there anything else that would help? Will IM: Networking discuss programming for BOTH AppleTalk and Ethernet? If not, what would be a good source for learning how to write Ethernet and AppleTalk compatible software. Thanks in advance. Ravi J. K. Mehta Terminal Sunset Software +++++++++++++++++++++++++++ >From andym96@aol.com (AndyM96) Date: 20 Oct 1994 01:13:05 -0400 Organization: America Online, Inc. (1-800-827-6364) In article <383h05$a37@news.bu.edu>, rjkmehta@bu.edu (Ravi Mehta) writes: << Will IM: Networking discuss programming for BOTH AppleTalk and Ethernet? If not, what would be a good source for learning how to write Ethernet and AppleTalk compatible software.>> yes, IM networking discusses how to do that. Also, a good book is "Programming with AppleTalk" by Michael Peirce -code samples are in Pascal, though, but it is a thorough and detailed description of how AppleTalk protocols work & how to use 'em. BTW, if you dicover a code sample how to write a requester-responder pair using ATP in C, <> e-mail me @ andym96@aol.com -I've been trying to get this info for a couple of weeks now with no avail. Andy +++++++++++++++++++++++++++ >From ntuck@muddcs.cs.hmc.edu (Nathan D. Tuck) Date: 20 Oct 1994 20:02:38 GMT Organization: Harvey Mudd College, Claremont CA >In article <383h05$a37@news.bu.edu>, rjkmehta@bu.edu (Ravi Mehta) writes: > >Will IM: Networking discuss programming >for BOTH AppleTalk and Ethernet? If not, what would be a good >source for learning how to write Ethernet and AppleTalk compatible >software.>> For both AppleTalk and Ethernet? AppleTalk is a software protocol while Ethernet is the physical format that AppleTalk runs over. If you mean LocalTalk and Ethernet, the two should be equivalent so far as ATP API's are concerned. If you mean to run transparantly over different protocol stacks such as ATP and IPX/SPX or TCP/IP, that is another question entirely. Nate ntuck@hmc.edu +++++++++++++++++++++++++++ >From Yorick_Ph*nix,MacTel_Iconex@metro.mactel.org (Yorick Ph*nix,MacTel_Iconex) Date: 29 Oct 1994 02:48:38 GMT Organization: MacTel Metro BBS, London, England. Ravi > I want to write some networkable software, but am completely new to > network programming. Besdies IM: Networking ( which I will pickup ) > is there anything else that would help? There is a very good book called something like Introduction to AppleTalk Programming - I have a copy at the office and I learnt all my Network Programming from it. It is possibly published by Addison-Wesley and is one in a series where Scott Knaster is the Series Editor. AppleTalk programming is what you should be doing (ATP, NBP, ADSP, PAP, etc) whereas LocalTalk and EtherNet are the phsyical mediums over which the network data travels - you shouldnt need to get involved at this level or even know which phsyical medium your program is dealing with. Yorick - sent via an evaluation copy of BulkRate (unregistered). -- **************************************************************************** MacTel Metro - Europes largest Mac specific BBS The views expressed in this posting those of the individual author only. Send mail to this user at either :- INTERNET:User_Name@metro.mactel.org [use underline] between first FIDONET:User.Name@f202.n254.z2.fidonet.org [use fullstop ] & last names **************************************************************************** --------------------------- >From walkerj@math.scarolina.edu (James W. Walker) Subject: Stuck in SyncWait again Date: Sat, 15 Oct 1994 21:39:18 -0500 Organization: Dept. of Mathematics, Univ. of South Carolina When an application freezes, dropping into MacsBug often reveals that it is stuck in SyncWait. When that happens, typing es to MacsBug or using force-quit does nothing. Is there any hope for someone with debugger skills slightly below those of "Kon & Bal" to get the app out of SyncWait and make it die a clean death, or should I just restart the Mac? -- Jim Walker +++++++++++++++++++++++++++ >From jonasw@lysator.liu.se (Jonas Wallden) Date: 16 Oct 1994 09:57:15 GMT Organization: (none) walkerj@math.scarolina.edu (James W. Walker) writes: >When an application freezes, dropping into MacsBug often reveals that it >is stuck in SyncWait. When that happens, typing es to MacsBug or using >force-quit does nothing. Is there any hope for someone with debugger >skills slightly below those of "Kon & Bal" to get the app out of SyncWait >and make it die a clean death, or should I just restart the Mac? >-- > Jim Walker The SyncWait loop waits for a parameter block error code to drop below +1 (which is the value used while the call is in progress), and as we all know this error code is 0 (noErr) for a successful request and negative for errors. So, look at the SyncWait code to see which word it tests (usually something like 10(A0)) and set this word to an error code (e.g. FFD5 for fileNotFound) and it will often get you out of the lock. I've used it successfully in Mosaic several times where it seems to hang when I abort a connection, and at other times when the computer won't reboot after a crash. BTW, I have a MacsBug dcmd which lists error strings from error codes. This is great as it's rather difficult to use ObiWan at these times... Can't remember if I got it from sumex or a Developer CD, though. -- `.`. Jonas Wallden `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`. Internet: jonasw@lysator.liu.se `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`.`. AppleLink: sw1369 `.`.`.`.`.`.`.`.`.`.`.`.`.`.`. +++++++++++++++++++++++++++ >From wysocki@netcom.com (Chris Wysocki) Date: Sun, 16 Oct 1994 16:31:58 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) In article , James W. Walker wrote: >When an application freezes, dropping into MacsBug often reveals that it >is stuck in SyncWait. When that happens, typing es to MacsBug or using >force-quit does nothing. Is there any hope for someone with debugger >skills slightly below those of "Kon & Bal" to get the app out of SyncWait >and make it die a clean death, or should I just restart the Mac? Here's a MacsBug dcmd that I wrote a few weeks ago that simply does a KillIO for a specified driver. You might be able to use this when you're stuck in _SyncWait to kill the pending request and get out safely. Since it's so small, I've attached it below, along with the source code to it; hope you find it useful. Chris. - ------ (This file must be converted with BinHex 4.0) :$dYTE'a*6b"NBfeN,R0TG!"6594%8dP8)3#3"!`[!*!%r2T6593K!!-!!!`[FNa KG3,r!*!$&[rr$3d)5fPXE%P2,Q1Gm9!"8)H!!"8BQJ#3!i!!N!3"@**J4()!N"3 %R!#3"2q3"&4&@&408&-J!3#UUh$bUUYlc3!!!D`!!!F8!!!"%3!!!`8KNZFl!*! 'P&84!!JFl(B)BP9k**AKrPcJ1V9Vp)Y)6-*K36-cDDB[,XlVjq(F(52TkHdlqe, 528kFPY3cj!m%XHl!BBHmiNQm1dk-[J53!+ZSdrTSIqk,mhTa[FiTXQ&$R%R#AZp J%C'5-PeA5k21&&hTI(#%T@*rS!G1i4NCK)8cm@"R"EPI9L3pM+@6dTk5%FD1N3A d$XA1E2eFqc+pj4*T[kc89#T`30$qQH9`rdJka4&Q8TZ(CNTR%"@FBEY*#SIZ2"h 9fMXDeZAACHmJpa[Df"Z%R"!,95(&3f,U3"Z(Ym@d21(%V@i%L*f5MGaVHQmS26m &RBReV@XMPA-rAE+RSe"S$Z"F6FJ*%'1Q+$8VMjpUY##U5Kq`#Ni"b1-*-S$*bXK 4JLr#EMe#Ml!M[ailMaacd#PK!b98pT)")`1!&5$A8l)#j$1!VjF`XK,d-B*q"!" hAB-N6-+1(#0--Q$N'%%6)`a2$JrX`!#kK`Pj*56[%r*'5$QilV!N)HGDH5U8kcF Lb&L4`84EH%HC1bZRk(&VKIGF`EMUNr2F#JHhPG0X*U+rUDbBjVj2[X&4VrF8SS2 A*ZF@EMTVU`kmP"+LN`2,(EGcRR9#J*bU+BHVi'NV5![Y2"S`VMa-K(@qh8FA!Lq 16JRdZXI2ZVfRK0N&)HH@8mqa,+X,q+4Pk21`Qb52K'+bc$Lmq&!ClMVjk8jb`HH #hBX#&YmPPpCU'c9E85Z`dFPE1i8TI4!NhHl*2`FqM)4`&399fDAbY[Sh3F6%8-H SK,N@'Gb&6826Ca,"234$,5f'hVD6V`NjdeTbUN$2i!3Q9$Vq2#&5UbNL1m(6-*K &ia[1`)a4FMe#PS"Eqa`jGJ[K@3lT1Y568mZrP"`T6`J!"L5-1Kj(D+#%lk1!M*( c@6$IDUqi0&%EMKH@,Yi+aG2@Cp1-'*DKbU,9a[Jr2!"Ji"b'"JU0(d)J`@[`1HD cBSl6K8APm6l&XrUED,q,m!51Rm')'amRXA(pfH1&(Y3GKq0S3FfYYM*c+4S'94V !E%HRepbrjdYrZ63iRNjSP4jJ*BrK3-mD-c'"&)rK&$JLa)`l3NFJmIq'6pkA"8+ EZPaEhfjia3r*40R`V%CK9#Q@(TKaA4Q*2m25$dIHl[K#9"T-QQk$amFV[X6qXK5 MhGQ(BQ,)%e!DYb"@Y%m&VQ3ibQj5bR8HMY-5$h@AHcI,I@N9,MqQ`SI+fR,I`ET QY'Mi)*[a#CTDdB5VJ@6i&,*DBN-4bI[8k9EIhN6H8,h,-DEC4pbZKaaErCmFC6! TM+mHNY`jr-QLY,mfA$dNfHTrjeM&he@0%RV(lDZYSR3$l2diiU*iZUaC$GPqcGe q(c-qSD@XPh&A8kPQ5Lr#&XFR`aVmJ2d&CcrI&'[jVUYeT3#VC*Am"`!0$3Y,D@a X58mZE@&VC3&3Ki!!&4LD!*!$J!#3"!&BNQ!-d`#3%4B!!!H+!*!%rj!%9%9B9%e 38b!"!+UVH01UUhSa!!!"V!!!!NN!!!%K!!!"AA@DY)S!N!B0#"%!#"cXGJKLe6K CXcV%MX[FG-ra@EM-Q*1JqQRRHDD'!FE8USiQY*ZBYf-N2EepCem''8Jp6U#@e$2 N$`3a!Z8mCMMKX0iG*`kj(F$6hQPp0(R#e8GeIJ%+eS4fkG!QqH5mj@Eb5J'&SF- f2IHXLC)Rh(G9"qMC168fkZRVLD,5%1MFep-UPejSIKqSAS9"2M5KC&YdF44UJT2 VUSRD-6A0`HGUqL"IcAc*%fEiUN1YTKkBb+#`dhG'kSD9Um1'9DY$D@F3&EaqcNJ +Krk4G&5rae5"XdH@`bNCiEMbFH@pN!!6BL%!f*2KHAX@[q2%BI(1MNACD0i4kc1 HBUp[A4ZT0(jFbCk13U%jJ(-e)5G!M*NbjfliU8B,SLT[(QS"!*!$8E@%YC*-rU" 2Qj68cKm-QZh*@Hk!6mM($"M#ERmSV%fbNSK()*!!!4()aB$ANqA0`C`L2mDq%%M 2eLET'H32JdlCBHJ*q'-5`fcNcf5`0QNL509S'S!F4J*CaSH!-cN1di%Z'!3j*!k 3!#rX3a'I0cPASHm1CIT!'jiDC`0a&JaMJV"p)3`br#L-*GSF$MkJ85JE+M30NM` SQT5N4cihpZ@fe)A!!(N1%qB@U#40R4U[h%k'X9TPqiV&(`U!HPUqBl$idj%EqAh KR22p)1G,GLI$HN"V6qrMmq#`GSR%%q53!-0mm$B3$8L%TL)R&m,q,"m"PZ,L,+N 9j`pk$6`qA9K&U@`S6$*k'1,PKca"cZX$SYaXS8Np-"!iIIf"h-dl&!DNCBHa,mX %JeiI'Q6`TA1CQ@4IEH6,#)[LP9-6bZ,5VbShJ"`"H6U3!2[M,6C$f)Fbh"j5iqd ib`DmlV2UfAi0!!C,D@aX58pH3*ha8!&3Ki!!&4LD!*!$J!#3"!&BNQ#bS3#3%!5 F!*!)rj!%FR0bBe*6483"!+UVGE5UUh[D!!!(@`#3"J3e!*!%6D`!N!Mf(#0%$L) UV5%U359,L)ir2,PP8%TR&'k`ZDaG08a*8EM1j[X@-!H9V*B9TEeVY40LeBBHkik d""f8``-#qHkTril9mECq)[ZJMDJqD&Y$,kRKF%G[EjmqVDQJ'YKb9*Epd-r)f80 lCrk#pNeprZ(hI,RIi`m5d[MlTja#6SFVp"EjQhp'Xk8C8Sh%T#R5bG+*dQ6T1'Q L0&kUNXC*&9+j9#D95#l*'GV%TJEHbMfhqq+AGV%0+kLqM+A*&6S3@TZlTqd94eQ Y5Q9qAqi6$AAN5K)GLM3PCk$b286IDY[X1"ak1(F6qXI4hi2qE[3V`$dSH"1[E&0 cpk*q#fMG+VM)li+(9F[9h(fja`1[jHjRlAY+cL$SQN-21e2e[YbpSBH,DPDY$(F P+X!+!LYhI9I2@Q!%@%C$DG[qHS'd0C5kQR)r$(FP'clFP'4)a(K@8m,AYTNH"cX )QL(!`!dl(PJ!-%L',3'Q"9BGHYMae[SZG0NpCF$c3`mI4Q*YVrDF#$3H[0G&hU* AEM,`X("AafY9`lRE3ZIiEJeP,`YdGABfKi)YS@Mh@H3SUFUUIDSfS$+GEmTb`f4 8%4P56@Q3!(&Geh6bXPT9-lXbA'h4p9P%PD`fUmTQ5cTM$YN-8#L5iQX%5FCRD+U TDiU0'f'Y*UZV2'jE%XM$M'`XaJdMN9@)UZeG*TJDLqYb2hBFSDQ-X8"+P`ffEXM 3BRdbGQ$F3KEK'C-e,PQbJ1Kd+)`e$%3Q5#c[B!Ef'0US5I'#PIQbQE,`QB!aj&) eQdC'NU+-CkmPUUpSreQ1@!HVk"kZD@*c$arDij[mbF1jqSV3`fpR-M5RkI#K@M9 h+(41+$ZQ"cUjRcamk)6lb%0dK&r&a!cD[PA!,Dm8P3R&5"p9q(`B#pK2U,lr-VK 9l[&p(bi+A&"ml[0!+YjSQ([iX"p*`r3fjRijkN,FE)YTbX3-e90pD8e&prCk"h6 A@A2H2+TN%&k0m+TM2LTc$Q20'YU'frE2*S'IfP9,bFQX*$*F6ka8G0(#rHkZRe0 &6fhNSP8lY3V"@cGXT4,eL*9+3AQQ3H6DGRKp9f5RqRUQr2i,Be@X@'miX0hLRF5 QdJ0rIVH0(eU2r8-1jJk1c!@N9ZfUGjLd`%IPp8jibcf5@35bSCNTp2,3`h505#b FmQK4(5@VmQNTSE`hh08cHFe1N9$ECIEF9%fhI%pIhm9F)kRNr,X8SZ%8203,6NJ pZ6#`kZDhU(cH&R+'$PjpZ+HNSjNFd0Y*-aMk$c683Z2CTP"fKD1YH99ciZ3DR$# @jQ6jqGpZDfjVDR#d03fr-)rm6@h3X$5IFAjpd3)keD%l"!0ZKC3'Tdipach6c-F rkrrkm2dAm&rZ[Z#CjV*(LH+[R6Te`G43pMrG6jj3AXH&c-`qqm@6,J0LSRQBP"R T1$#YkiQm9X6CHr)hmP8!N!2-eJ!!: +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Sun, 16 Oct 1994 20:15:31 +0100 Organization: Royal Institute of Something or other In article , walkerj@math.scarolina.edu (James W. Walker) wrote: >When an application freezes, dropping into MacsBug often reveals that it >is stuck in SyncWait. When that happens, typing es to MacsBug or using >force-quit does nothing. Is there any hope for someone with debugger >skills slightly below those of "Kon & Bal" to get the app out of SyncWait >and make it die a clean death, or should I just restart the Mac? Usually this means a SCSI request isn't being served (or an Ethernet request, or a Serial Port request, or...) This is usually caused because of buggy drivers (like early Applied Engineering drivers, some CD-ROM and MO drivers and version 1.x of the Digidesign card drivers) When something hangs in _vSyncWait, it waits for the word at (a0)+10 to go 0 or negative (this is ioResult in the parameter block) One thing you can TRY is: atba sw a0+10 ffff g atc es This will make the app halt as soon as it gets to an A-trap (so it won't just get stuck again) Then it fakes an interrupt service routine that sets the result to -1 (an error code) Run with this; and as soon as an A-trap is hit, clear breaks and exit. However, since this is a driver that got hosed, chances are you'll run into the same problem an instant later, so it's usually not terribly helpful. There are also several conditions which can make this fail: - If some idiot masked interrupts, that's the reason you're waiting for an interrupt that's never serviced. Check with TD and look at the Int= figure - should be 0. 7 is real bad. - If this was because of a file manager request; the file manager is now in a meeting for the rest of the day, which means you earned just about nothing by breaking out. - If the driver makes interesting assumptions about the return value you use (ffff==-1 in this case) OR wants a completion routine to be called, you're probably hosed anyway. There should be a law only competent people can write drivers. Unfortunately it seems to be the other way around with some people "Hey, we've got this interesting hardware we can sell. However, hiring someone expensive to write the drivers would eat into our margin way too much. Isn't Joes 13-year-old kid into computers? Have him whip something up and we'll give him a Happy Meal." Hardware without drivers is pretty useless. Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden -- I don't fear death, it's dying that scares me. +++++++++++++++++++++++++++ >From jumplong@aol.com (Jump Long) Date: 17 Oct 1994 00:44:01 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , walkerj@math.scarolina.edu (James W. Walker) wrote: >When an application freezes, dropping into MacsBug often reveals that it >is stuck in SyncWait. When that happens, typing es to MacsBug or using >force-quit does nothing. Is there any hope for someone with debugger >skills slightly below those of "Kon & Bal" to get the app out of SyncWait >and make it die a clean death, or should I just restart the Mac? Here are a couple of paragraphs from the article "Asynchronous Routines on the Macintosh" in develop issue #13 that explain deadlock conditions and SyncWait: - ---- Avoid SyncWait. Does your Macintosh just sit there not responding to user events? Drop into the debugger and take a look at the code that's executing. Does it look like this? MOVE.W $0010(A0),D0 BGT.S -$04,(PC) That's SyncWait, the routine that synchronous calls sit in while waiting for a request to complete. Register A0 points to the parameter block used to make the call, offset $10 is the ioResult field of the parameter block, and SyncWait is waiting for ioResult to be less than or equal to 0 (noErr). The ioResult field is changed by code executing as a result of an interrupt. If interrupts are disabled (because the synchronous call was made at interrupt time) or if the synchronous call was made to a service that's busy, you'll be in SyncWait forever. Take a look at the parameter block and where it is in memory, and you'll probably be able to figure out which synchronous call was made at interrupt time and which program made it. - --- Deadlock is a state in which each of two or more processes is waiting for one of the other processes to release some resource necessary for its completion. The resource may be a file, a global variable, or even the CPU. The process could, for example, be an application's main event loop or a Time Manager task. When deadlock occurs on the Macintosh, usually at least one of the processes is executing as the result of an interrupt. VBL tasks, Time Manager tasks, Deferred Task Manager tasks, completion routines, and interrupt handlers can all interrupt an application's main thread of execution. When the interrupted process is using a resource that the interrupting process needs, the processes are deadlocked. For example, suppose a Time Manager task periodically writes data to a file by making a synchronous Write request, and an application reads the data from its main event loop. Depending on the frequency of the task and the activity level of the File Manager, the Time Manager task may often write successfully. Inevitably, however, the Time Manager task will interrupt the application's Read request and deadlock will occur. Because the File Manager processes only one request at a time, any subsequent requests must wait for the current request to complete. In this case, the synchronous request made by the Time Manager task must wait for the application's Read request to complete before its Write request will be processed. Unfortunately, the File Manager must wait for the Time Manager task to complete before it can resume execution. Each process is now waiting for the other to complete, and they will continue to wait forever. Synchronous requests at interrupt time tend to produce deadlock, because the call is queued for processing and then the CPU sits and spins, waiting for an interrupt to occur, which signals that the request has been completed. If interrupts are turned off, or if a previous pending request can't finish because it's waiting to resume execution after the interrupt, the CPU will wait patiently (and eternally) for the request to finish - until you yank the power cord from the wall. - --- Read the rest of that article, it'll help you write code that doesn't end up in SyncWait. - Jim Luther +++++++++++++++++++++++++++ >From walkerj@math.scarolina.edu (James W. Walker) Date: Mon, 17 Oct 1994 23:41:46 -0500 Organization: Dept. of Mathematics, Univ. of South Carolina In article <37sveh$t0t@newsbf01.news.aol.com>, jumplong@aol.com (Jump Long) wrote: > Read the rest of that article, it'll help you write code that doesn't end > up in SyncWait. I guess I didn't make it clear in my original post, but it's not *my* code that gets stuck in SyncWait. It's usually Internet apps like Anarchie. I was just wondering whether there was anything I could do when it happens, other than restart, and this thread has given me some ideas. Gee, I can hardly wait for the next freeze. :-) -- Jim Walker +++++++++++++++++++++++++++ >From bierman@caelab1.cae.wisc.edu (Peter Bierman) Date: Tue, 18 Oct 1994 14:36:31 -0600 Organization: Happy Frogs, Inc. In article , walkerj@math.scarolina.edu (James W. Walker) wrote: > In article <37sveh$t0t@newsbf01.news.aol.com>, jumplong@aol.com (Jump > Long) wrote: > > > Read the rest of that article, it'll help you write code that doesn't end > > up in SyncWait. > > I guess I didn't make it clear in my original post, but it's not *my* code > that gets stuck in SyncWait. It's usually Internet apps like Anarchie. I > was just wondering whether there was anything I could do when it happens, > other than restart, and this thread has given me some ideas. Gee, I can > hardly wait for the next freeze. :-) Well, all of the ideas are good and accurate, but here's an easy fix. Do a step (oa-T) till Macsbug says "Will [not] branch". Then type: pc=pc+2 g That will jump you out of the loop. It's faster than "fixing" the loop condition. Just note that what John said is true: it'll probobly happen again withing a short time. Restart right away. -Peter -- Peter Bierman \ The Metropolis \ The most primitive part of the bierman@caelab1.cae.wisc.edu\ (614)-846-1911 \ the brain concerns itself \ 600MB Mac Files \ with the "Four F's": "I've changed my mind, Hobbes.\ FirstClass GUI \ Feeding, Fighting, Fleeing, people are scum." --Calvin \ Info-Mac CD-ROM \ and Reproduction. +++++++++++++++++++++++++++ >From richardb@cocytus.demon.co.uk (Richard Buckle) Date: Wed, 19 Oct 1994 06:37:42 GMT Organization: none In article , h+@nada.kth.se (Jon W{tte) wrote: >>When an application freezes, dropping into MacsBug often reveals that it >>is stuck in SyncWait. When that happens, typing es to MacsBug or using >>force-quit does nothing. Is there any hope for someone with debugger >>skills slightly below those of "Kon & Bal" to get the app out of SyncWait >>and make it die a clean death, or should I just restart the Mac? To be honest you can often get away with stepping over the SyncWait test if you restart *immediately* you regain control. In MacsBug, do a T 40. This should pop you out of any subroutines you're in and leave you in the 2-step SyncWait loop; if not, keep doing T 40 until you are. If you're at the TST instruction, do one more T to get to the branch instruction. Then do PC=PC+2;G to exit the loop. You may need to repeat this process one or more times to regain control. Once you have control, go straight to the Finder and to a Restart before the driver can bite you again. No guarantees and YMMV. However, 90% of the tine this lets be save my work :-| - ----------------------------------------------------- Richard Buckle richardb@cocytus.demon.co.uk Using this darned fine NewsHopper thingy. +++++++++++++++++++++++++++ >From quinn@cs.uwa.edu.au (Quinn "The Eskimo!") Date: Fri, 28 Oct 1994 10:13:36 +0800 Organization: Department of Computer Science, The University of Western Australia In article , walkerj@math.scarolina.edu (James W. Walker) wrote: >I guess I didn't make it clear in my original post, but it's not *my* code >that gets stuck in SyncWait. It's usually Internet apps like Anarchie. For reliable program (like Anarchie :) disappearing into SyncWait normally means that your networking on your machine is stuffed up somehow. To get out try this in MacsBug... sm a0+10 ffff g What it does is set the ioResult field of the paramblock to -1, indicating an error. You often have to do it a *lot* of times before it comes back and often it doesn't work at all. But it makes you feel like you've got control (: Share and Enjoy. -- Quinn "The Eskimo!" "I wasn't the one who fired the heat seeking population annihilator out the window!" Amaze your friends! Learn some cool MacsBug or MicroBug commands today (: +++++++++++++++++++++++++++ >From devon_hubbard@taligent.com (Devon Hubbard) Date: Fri, 28 Oct 1994 16:20:48 GMT Organization: Taligent, Inc. In article , quinn@cs.uwa.edu.au (Quinn "The Eskimo!") wrote: >In article , >walkerj@math.scarolina.edu (James W. Walker) wrote: > >>I guess I didn't make it clear in my original post, but it's not *my* code >>that gets stuck in SyncWait. It's usually Internet apps like Anarchie. > >For reliable program (like Anarchie :) disappearing into SyncWait normally >means that your networking on your machine is stuffed up somehow. > >To get out try this in MacsBug... > > sm a0+10 ffff > g > >What it does is set the ioResult field of the paramblock to -1, indicating >an error. You often have to do it a *lot* of times before it comes back >and often it doesn't work at all. But it makes you feel like you've got >control (: Ouch! OUCH! This is assuming that reg A0 really points to the cntrlParamBlockRec, which I hate to say doesn't always! I recently ran into a vSyncWait problem (on an 8100av) that lead to fingering the offending driver by looking at the data moved off D2 and matching that as a DCE entry with the help of Macsbug's 'drvr' dcmd. In every case of vSyncWait hang, a0 WAS NOT pointing to a valid paramblock so do a dm a0 cntrlparamblockrec before the 'sm' and make sure it looks like a valid paramblock, or you'll surely be rebooting thereafter. dEVoN - ----------------------------------------------------------------------- Devon Hubbard Silicon Pilot devon_hubbard@taligent.com Taligent, Inc --------------------------- >From macrshap@bbn.com (Richard Shapiro) Subject: having trouble with AEInteractWithUser & drag manager Date: 9 Oct 1994 17:09:27 GMT Organization: Bolt, Beranek and Newman Inc. I'm in the process of adding some drag-support to an application. It's working ok when the application is selected, so the underlying drag management seems fine. But usually, I want to drag when another application is selected (ie I'll be dragging from that other application). In this case, when my app receives the drag, it needs to interact with the user before proceeding. This is where I'm stuck. I've set the InteractionAllowed flag to kAEInteractWithLocal (the default, I know, but I thought I'd be explicit), and I carefully call AEInteractWithUser before attempting any interaction. I'm calling it without a timeout (kNoTimeOut), without a notification rec (should be OK since I have the relevant BNDL, FREF and ICN# resources defined), and with a very simple idle procedure which essentially does nothing (since at the moment nothing in my app cares about update or activate events). What I expected to happen was the usual flashing in the current-application icon (on the right edge of the menubar), which would allow me to bring my app to the front. What actually happens is...nothing: no flashing, no process paying attention to mouse clicks, hence no way to select my application (which has received the drop and is waiting in the call to AEInteractWithUser) so that I can interact with it. All I can do is cmd-opt-escape to force a quit. What am I doing wrong? I'm assuming it must be one of two things: either it's illegal to have user interaction after receiving a drop but before acknowledging receipt; or I need to handle something in my idle function which I'm not currently handling. Any suggestions? If it matters, I'm using CW 4.5 C, and running System 7.1 on a q660av with drag extensions and the drag-ware Finder (7.1.3). The drag flavors I'm handling at the moment are 'hfs ' and 'TEXT'. Please copy followups to email -- thanks. -- rs/macrshap@bbn.com +++++++++++++++++++++++++++ >From Jens Alfke Date: Mon, 10 Oct 1994 22:12:55 GMT Organization: Apple Computer Richard Shapiro, macrshap@bbn.com writes: > What am I doing wrong? I'm assuming it must be one of two things: either > it's illegal to have user interaction after receiving a drop but before > acknowledging receipt Bingo -- more specifically, it's illegal to cause a process switch while inside a drag handler, since the drag handlers are called via a lightweight process switch that is not compatible with the regular kind of process switch. While you're in a drag handler, WNE is hacked to do nothing for compatibility, but other ways to interact (such as calling AEInteractWithUser or SetFrontProcess) will choke your machine. Moral: Wait until after the drag finishes to try to interact with the user. --Jens Alfke jens_alfke@powertalk.apple.com "A man, a plan, a yam, a can of Spam ... Bananama!" +++++++++++++++++++++++++++ >From macrshap@bbn.com (Richard Shapiro) Date: 11 Oct 1994 01:54:10 GMT Organization: Bolt, Beranek and Newman Inc. In article <1994Oct10.221255.26429@gallant.apple.com>, Jens Alfke wrote: > Bingo -- more specifically, it's illegal to cause a process switch while > inside a drag handler, since the drag handlers are called via a lightweight > process switch that is not compatible with the regular kind of process > switch. While you're in a drag handler, WNE is hacked to do nothing for > compatibility, but other ways to interact (such as calling AEInteractWithUser > or SetFrontProcess) will choke your machine. > > Moral: Wait until after the drag finishes to try to interact with the user. OK, I eventually came to that conclusion myself. I guess it's good to have it validated... Problem is, I really need user interaction to complete the processing of the drop. So, I tried to get around it by stashing the DragReference in a global, setting a flag, returning from the handler, and then dealing with the stashed DragReference when I'm back in the main event loop (depending on the flag, of course). This doesn't work either. I can interact with the user, but it looks as though the information associated with the DragReference vanishes once the handler is exited. At least, I can't get CountDragItems and the like to work properly outside the handler context. Are these supposed to work outside the handler? That seems to leave me with one final option: I have to get *all* the data out of the DragReference while I'm in the handler, stash the whole pile somewhere, exit the handler, and process the data later. Yucch, that's pretty awful. Is there another possibility I'm missing here? For now, I "fixed" the application to run without user-interaction when it isn't in the foreground (which can only happen as a result of a drop). It's better than nothing, but really not what I want... -- rs/macrshap@bbn.com +++++++++++++++++++++++++++ >From Jens Alfke Date: Tue, 11 Oct 1994 17:28:36 GMT Organization: Apple Computer Richard Shapiro, macrshap@bbn.com writes: > That seems to leave me with one final option: I have to get *all* the data > out of the DragReference while I'm in the handler, stash the whole pile > somewhere, exit the handler, and process the data later. Yucch, that's > pretty awful. Is there another possibility I'm missing here? Since you can't possibly use the DragReference after the sender disposes of it, I think this is your only option. Is it that bad? Get the data you want to use, stash it somewhere temporary, and when you get back into your event loop ask the user what to do with it. --Jens Alfke jens_alfke@powertalk.apple.com "A man, a plan, a yam, a can of Spam ... Bananama!" +++++++++++++++++++++++++++ >From macrshap@bbn.com (Richard Shapiro) Date: 11 Oct 1994 22:25:03 GMT Organization: Bolt, Beranek and Newman Inc. In article <1994Oct11.172836.17257@gallant.apple.com>, Jens Alfke wrote: > Since you can't possibly use the DragReference after the sender disposes of > it As expected. > I think this is your only option. Is it that bad? Get the data you want > to use, stash it somewhere temporary, and when you get back into your event > loop ask the user what to do with it. No, it's not as bad as I thought. In fact it's already done and the result is cleaner than my original plan :) Now on to my next drag-manager question: receiving promise-hfs drags in an application other than the Finder. Details in another posting... -- rs/macrshap@bbn.com +++++++++++++++++++++++++++ >From leonardr@netcom.com (Leonard Rosenthol) Date: Wed, 19 Oct 1994 22:01:35 GMT Organization: Aladdin Systems, Inc. In article , macrshap@bbn.com (Richard Shapiro) wrote: > > I think this is your only option. Is it that bad? Get the data you want > > to use, stash it somewhere temporary, and when you get back into your event > > loop ask the user what to do with it. > > No, it's not as bad as I thought. In fact it's already done and the result > is cleaner than my original plan :) > What I've been doing in this case is to get all the info from the Drag, and then send it back to myself in an Apple event (but NOT in sendToSelf mode). This works quite nicely... Leonard - ------------------------------------------------------------------------ Leonard Rosenthol Internet: leonardr@netcom.com Director of Advanced Technology AppleLink: MACgician Aladdin Systems, Inc. GEnie: MACgician +++++++++++++++++++++++++++ >From jonpugh@netcom.com (Jon Pugh) Date: Wed, 26 Oct 1994 07:08:53 GMT Organization: Will hack for food Leonard Rosenthol (leonardr@netcom.com) wrote: > What I've been doing in this case is to get all the info from the Drag, > and then send it back to myself in an Apple event (but NOT in sendToSelf > mode). This works quite nicely... I actually send the event twice. Once to myself as record only, and then again with signature addressing so that it goes through the event loop. That way you can record the event too. Jon --------------------------- End of C.S.M.P. Digest **********************