Debugging Code Res
Volume Number: 6
Issue Number: 3
Column Tag: Programmer's Forum
Debugging Code Resources 
By Bryan Waters, Casselberry, FL
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Developing and Debugging Control Definition Procedures
An application I was working on recently required a control that operated similar
to the way the date and time is set in the alarm clock desk accessory. So I set out to
write my own control definition procedure. Everything was going great, until I tried
to use it. It didn’t work. Now, I can use TMON with the best, but I don’t program in C
just so I can sit down and calculate offsets for all my structures, and track down
variables on the stack. In order to use THINK C’s source level debugger, I had to embed
my CDEF in my test application. This article describes exactly how I did this, and
provides a framework for which any type of definition procedure ( WDEFs, LDEFs,
MDEFs, and MBDFs ) can be tested and thoroughly debugged using a debugger like
THINK C’s.
Control Definition Procedures
A control definition procedure, for those of you who don’t already know, is a
resource of type ‘CDEF’, which contains the code to draw and manipulate a specific
style of control. The Macintosh comes with two default CDEFs. These are the button
CDEF, which has resource ID of 0, and the scroll bar CDEF, which is resource ID 1.
The procID argument to NewControl, is determined by a combination of the resource
ID, and the variation code. The algorithm for calculating the procID is as follows:
resourceID * 16 + variation code
This allows for up to 16 variations of a control. The button CDEF, has three
variations, the button, the check box, and the radio button. These have variation codes
of 0, 1, and 2. Using this information, the procID for the radio button would be
0*16+2 or 2. The scroll bar CDEF does not have any variations, so its procID would
be 1*16+0, or 16. In our example the CDEF has an ID of 2, so that its procID would
be 32. When NewControl is called, the resource ID and the variation code is backed out
of the procID, and then it loads the CDEF with that resource ID, and calls it with the
appropriate variation code. The interface to the CDEF is defined as follows:
/* 1 &/
pascal long mycdef(varCode,myControl,message,param)
int varCode ;
ControlHandle myControl ;
int message ;
long param ;
The varCode parameter is the variation code of the particular control. Since our
control won’t have any variations, we can ignore this parameter. The second
parameter is the control handle itself. The last parameter is used for passing extra
information associated with a specific message. The message parameter tells our CDEF
what the control manager wants us to do. The messages are defined as follows:
/* 2 */
enum{
drawCntl,
testCntl,
CalcCRgns,
initCntl,
dispCntl,
posCntl,
thumbCntl,
dragCntl,
autoTrack
} ;
Then initCntl, and the dispCntl messages, are for initialization, and cleanup
respectively. Our control uses these messages to allocate and initialize data storage,
and to dispose of it. The control manager uses the testCntl message to request a
partCode for a mouseDown in a control. The drawCntl message is used in conjunction
with a partCode to cause the part to be drawn. Initially a partCode of 0 is passed in
param, which tells our CDEF to draw the whole control. When a CDEF receives a
drawCntl message, it must do several checks first. First it must check the cntrlVisible
field of the control, to see if we need to draw the control at all. Then the cntrlHilite
field must be checked to see if part of the control must be hilited. The cntrlHilite field
specifies a partCode to hilite on the control, 0 for the whole control, or 255 to
inactivate the control. The autoTrack message is sent to track a mouseDown event in
the control. Upon initialization, the actionProc field of the control should be set to -1
to indicate that there is a default “Tracking” procedure. When a mouse down first
occurs in a control, the Control Manager first call the CDEF with testCntl, which
returns a partCode, and then calls the CDEF with autoTrack, passing the partCode in
param. The autoTrack procedure should handle whatever hiliting needs to be done, plus
whatever other tasks need to be specific to the control. The CalcCRgns message should
be handled by building the region of the control into the RgnHandle passed in param.
The top byte of param should be cleared first, to clear bit flags that the control
manager sets. The dragCntl, posCntl, and thumbCntl messages are not required to
implement our control. For more information on these see chapter 10, of Inside
Macintosh Vol. I.
Figure 1. Testing CDEFs
Debugging Code Resources
The following is a description of the method used for using THINK C’s source
debugger to debug code resources:
• first create a dummy code resource with the same interface as the code
resource to be debugged. This dummy code resource will do nothing but a GetResource
on an unused type. Then it will use the first long word of this resource to make a
pascal call to this address using the same parameters as it was called with.
• Include the code resource to be debugged in the test application’s project.
• In the beginning of the test application, first allocate a long word size handle.
Then get the address of the main routine of the code resource, and store it in the handle.
Now we do an add resource of the same unused type as our dummy code resource uses.
• The rest of the application proceed to use the code resource as it normally
would. At this point you will be able to compile and debug your code resource under the
debugger in THINK C.
One of the things to watch for while using this technique is that when a code
resource is being used under the debugger, if your code resource uses globals, you will
be referencing off of A5. Code resources reference globals off of A4 in THINK C. This
normally would cause no problem, except that THINK C does not set up A4 pointing to
your code resource globals. This must be done by the RememberA0(), SetupA4()
sequence done in the beginning of the listing of the example CDEF. At the end of the
CDEF, the RestoreA4( ) restores the old value of A4.
Date/Time Control
Our control was written in an attempt to provide a method for entering the date
and time conveniently, and having a control that was portable to other programs and
not embedded inside of the program. The CDEF for this control is provided on this
issues source code disk and can be ported into your own program, using Resedit. The
way it is used, is as follows:
Ex.3
install the control in you window or dialog
while( i don’t want to quit yet ) {
getnext event
if( mouseDown ) {
FindControl( )
partCode = TrackControl( )
HiliteControl( ourControl, partCode )
}
}