jason@ux1.cso.uiuc.edu (Jason Watts) (09/30/90)
I have written an XFCN using Think C 4.0. The routine utilizes an
object (in the oop sense) to bind the data being manipulated to its graphic
representation (a dialog box). The main() function creates an instance of my
object, calls its initialization routine, calls its "go" routine (which handles
the dialog actions), then disposes of the object before exitting. The object's
initialization routine creates a dialog by calling GetNewDialog and passing it
a pointer to the dialog record that is itself an instance variable of the
object. A reference to the object (i.e., this) is saved in the dialog's window
refCon. The initialization routine proceeds with other initializations,
including installing userItem procedures to be called by ModalDialog and
storing, in the object's filterProc instance variable, a pointer to the filter
function to be used by ModalDialog. The three dialog userItem procs and the
ModalDialog filter proc all call certain methods of the object; these routines
access the object by retrieving the object reference that has been stored in
the window refCon of the dialog.
When the XFCN is executed, the object is successfully created and
initialized. The MyObject->Go() routine is then called. It succeeds in
showing the dialog window. ModalDialog is called next, which in turn calls the
first userItem proc. The userItem proc executes smoothly until it attempts to
call my object with something like theObject->AnyMethod(). The routine bombs
with either a bus error or an illegal instruction, indicating that the object
reference is bad (execution never branches to AnyMethod(), so the problem isn't
in the method being called). What baffles me is that when I bypass the
userItem procs (by either having them return immediately or by never installing
them), ModalDialog() calls only the filter proc I gave it. The filter proc
runs beautifully, even when it calls my object, which it accesses in exactly
the same way as the userItem procs! This proves that "this" (the object
reference) *is* being stored correctly in the dialog window refCon, and that it
is valid when my ModalDialog filter gets it.
My userItem procs all look something like:
pascal void UserItemProc( DialogPeek theDialog, int itemNumber )
{
CMyClass *theObjectRef;
/* get the object reference--it's in theDialog's window refCon */
theObjectRef = ( CMyClass * ) GetWRefCon( theDialog );
/* The following instruction dies with system error ID=1 or 3 */
theObjectRef->DoSomeDrawing();
}
and the ModalDialog filter:
pascal Boolean DialogFilter( DialogPeek theDialog, EventRecord *theEvent,
int *itemHit )
{
CMyClass *theObjectRef;
.
.
.
theObjectRef = ( CMyClass * ) GetWRefCon( theDialog );
/* the follow call works fine */
theObjectRef->WhateverMethod();
.
.
.
/* In fact, all such calls from this filter proc work as expected */
theObjectRef->AnotherMethod();
.
.
.
}
I have checked that the functions are all declared correctly. I have tried to
verify that everything that shouldn't matter doesn't matter. I have tested both
direct and indirect versions of my object (using new() and delete() for the
indirect, and NewPtr(), blessD(), and DisposPtr() for the direct). I *am* using
the oopsA4 library. Can anyone figure out what might be going wrong?
--
| | |====================|
| | | Jason Watts |
\ |\ |\ \ | (jazzin@uiuc.edu) |
\| \| \|\|====================|phils@chaos.cs.brandeis.edu (Phil Shapiro) (10/02/90)
If you have a callback (in a code resource or application) that uses
objects, you must make sure that your jump table pointer is correct,
since object use the jump table to dispatch their methods. In code
resources, A4 points to the jump table. What you should do is
something like:
void LineBox::DoAbout(DialogPtr aboutBox)
{
int itemHit;
RememberA4();
ShowWindow((WindowPtr) aboutBox);
SetWRefCon((WindowPtr) aboutBox, (long) this);
do {
ModalDialog(filter, &itemHit);
} while (itemHit != OKItem);
}
static pascal
Boolean filter(DialogPtr theDialog, EventRecord *theEvent, short
*itemHit)
{
Boolean result = FALSE;
switch(theEvent->what) {
/* ... other cases ... */
case nullEvent:
SetUpA4();
((LineBox *)GetWRefCon((WindowPtr) theDialog))->Idle();
RestoreA4();
break;
default:
break;
}
return result;
}
This method works the same for user item draw procedures, as well.
-phil shapiro, symantec tech support
--
Phil Shapiro
phils@chaos.cs.brandeis.edu