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