[comp.sys.mac.programmer] cdev resources

charles@tasis.utas.oz (Charles Lakos) (06/19/89)

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.  Does anyone have more information on that?
Below are some more specific questions.

1. Firstly, if I click on the close box of the Control Panel, the cdev 
   receives a close request before the CDEF, whereas if I click on another
   cdev in the list, the CDEF receives a close request before the cdev.
   Why the difference?
   
2. What happens if you cannot allocate resource numbers for the cdev
   code resources in the recommended range (-4048..-4033?)?  The CDEF
   does not have a number in that range because I couldn't work out how
   to reference the CDEF in the CNTL's procID (which should be the resource
   id of the CDEF * 16 + variation - all in 16 bits!).

3. Why is it that the system does not seem to use custom scroll bars in its
   cdevs??  Instead those cdevs (e.g. Sound) specify a UserItem where the
   scroll bar will be drawn.  Makes one suspicious!

Any suggestions welcome.

Charles Lakos.

ACSnet: charles@tasis.utas.oz
ARPA:   charles%tasis.utas.oz@uunet.uu.net
UUCP:   {enea,hplabs,mcvax,uunet,ukc}!munnari!tasis.utas.oz!charles
Snail:  Computer Science Dept., University of Tasmania,
	GPO Box 252C, Hobart, TAS, 7001, Australia.

mnkonar@manyjars.SRC.Honeywell.COM (Murat N. Konar) (06/28/89)

In article <1103@tasis.utas.oz> charles@tasis.utas.oz (Charles Lakos) writes:
>2. What happens if you cannot allocate resource numbers for the cdev
>   code resources in the recommended range (-4048..-4033?)?  The CDEF
>   does not have a number in that range because I couldn't work out how
>   to reference the CDEF in the CNTL's procID (which should be the resource
>   id of the CDEF * 16 + variation - all in 16 bits!).
>
>3. Why is it that the system does not seem to use custom scroll bars in its
>   cdevs??  Instead those cdevs (e.g. Sound) specify a UserItem where the
>   scroll bar will be drawn.  Makes one suspicious!


I suspect that the answer to questions 2 and 3 are related.

The cdevs that use custom CDEFs are probably:
1) using NewControl to create a control (invisible at first)
2) setting the controls rectangle to the user item rect
3) getting a handle to the custom CDEF (numbered in the 
   recommended range) by using GetResource
4) storing the handle to the custom CDEF into the proc field
   of the control record
5) replacing the user item with the control using SetDItem
6) showing the control by using ShowControl.

Disclaimer: I'm writing all this off the top of my head so
if it doesn't work, oops.  But I think there is enoughg in 
here to get you on your way to solving your problem.

____________________________________________________________________
Have a day. :^|
Murat N. Konar        Honeywell Systems & Research Center, Camden, MN
mnkonar@SRC.honeywell.com (internet) {umn-cs,ems,bthpyd}!srcsip!mnkonar(UUCP)

chrisj@ut-emx.UUCP (Chris Johnson) (07/01/89)

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)