Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!ut-emx!chrisj From: chrisj@ut-emx.UUCP (Chris Johnson) Newsgroups: comp.sys.mac.programmer Subject: Re: cdev resources Summary: It's not *your* bug... Message-ID: <14735@ut-emx.UUCP> Date: 1 Jul 89 10:40:04 GMT References: <1103@tasis.utas.oz> Reply-To: chrisj@emx.UUCP (Chris Johnson) Organization: U.T. Austin Computation Center Lines: 98 In article <1103@tasis.utas.oz> charles@tasis.utas.oz (Charles Lakos) writes: >I have been writing a cdev which controls a DRVR. The DRVR and the data >which constitutes its parameters are loaded into the system heap, since it >must survive application entry and exit. The cdev has a custom scroll bar >defined in a CDEF resource. > >My problem relates to the closing of the cdev, when the machine will >occasionally bomb with a corrupted system heap AFTER the cdev and the >CDEF have handled their close requests. > >I have run out of ideas on how to debug this. I have double checked all >my heap manipulation (which is not all that extensive), and I have even >removed all my dispose requests, all to no avail. The fact that the >problem is intermittent makes life even more difficult. > >At the moment, my suspicions lie with the way the Control Panel cleans up >after a cdev is finished. > (Some stuff deleted.) > >Charles Lakos. The reason it's so hard to find the bug in your code that's causing these crashes is that the bug isn't in your code - it's in Apple's. I had a similar problem (almost certainly the same one) in GateKeeper 1.0. After a few weeks of hunting and hair-pulling I figured it out. The problem occurs when the Control Panel is closed with the CDEF-bearing cdev open. It works like this: 1. The Control Panel passes the closeDev message to the cdev. 2. The Control Panel closes the cdev's resource file. 3. The Control Panel then proceeds to try to close its own window. 4. In order to close its window the Control Panel has to dispose of all of the dialog items. 5. The disposal of dialog items goes just fine *until* it comes time to call DisposeControl() for your CDEF-based control... a. DisposeControl() gets the handle to your CDEF-based control. b. It dereferences the handle and gets the handle to the control's definition procedure from the contrlDefProc field of the control record. c. Now it dereferences that handle to the definition procedure and attempts to jump to that address (the start of the CDEF), passing the dispCntl message that should tell your control to dispose of itself. d. The only problem at this point is that the CDEF that's being called here isn't in memory anymore - it was disposed of when the cdev's resource file was closed quite a few steps earlier. Of course, the area of memory last occupied by the CDEF is seldom still intact, so it's almost always executing utter rubbish (it would be a freak accident if the system *didn't* crash at this point). And one of the most impressive characteristics of this particular crash is that the System file is usually corrupted by it. To Apple's credit, this bug was fixed some time ago when System 6 was released, so Control Panel 3.3.1 won't cause this to happen although it's predecessors will. This was why the bug wasn't detected in GateKeeper 1.0 - myself and all of my testers happened to be using System 6. It wasn't until it found it's way into the real world that it bumped into outdated system software and started crashing violently. The solution is to either have your cdev refuse to open on pre-System 6 machines (beware though, some users will have old versions of the Control Panel installed in their current Systems), or you can... 1. Define the locations of your custom controls in the DITL with userItems instead of CNTL references. Make sure that these userItems have their enabled bits set. 2. When your cdev receives the initDev message, use GetNewControl() to create your CDEF-based controls. Then use GetDItem() to get the location of the userItems in the dialog box and use MoveControl() to move the controls to those locations. When you have to handle hitDev messages... 1. Check to see if the item hit is one of your userItems. 2. If a userItem was hit, call FindControl() to determine which of of your CDEF-based controls was hit. 3. If FindControl() returned a non-zero part code, call TrackControl() and take it from there. The key here is just that you'll have to do all the usual control-oriented work for yourself when you're dealing with these controls based on custom CDEFs - the Control Panel won't do it for you. :-( When it comes time to handle the closeDev message... 1. All you have to do is call DisposeControl() for each of the custom CDEF-based controls. This way, they're disposed of *before* the cdev's resource file is closed. I experimented with other approaches to this problem, but this was the only safe solution I found. It's annoying, but it always works. I hope this helps (and if you had problems with GateKeeper 1.0, now you know why!) ----Chris (Johnson)