On Tuesday, March 9, 2004, at 03:23 PM, Robert Purves wrote: > > H. Gluender wrote: > >> please tell us something about the "toc"-functionality and the >> assembler code line? >> (I know it's defined in Rntm Appearanc.Incl and it's not an Apple >> struct. Your code somehow manages to mimic the FB PROC"label" >> function for labeled FNs and perhaps the FB PROC"label" function also >> uses a global. Can we mortals know how the FB PROC"label" function is >> implemented?) > > EnterProc/ExitProc causes the compiler to preface the contained FB > code with a "routine descriptor". A RoutineDescriptor has both > executable assembler code and data; it is an obsolete mechanism for > allowing automatic switching between 68K and PPC code, and we don't > need to study any of its content except for one part. Buried inside > the RoutineDescriptor is an 8-byte structure, which is accessed by > this strange code: > > [proc "WindowBoundsChangingHandler" + _FBprocToProcPtrOffset] What kind of of strange, sick and twisted mind even knows about this stuff Pete... (the other one) :-) > > The 8-byte structure is a transition vector (also known as a PowerPC > ProcPtr). It specifies the address (4 bytes) of a function, along with > an environment variable "Table of Contents", or toc (4 bytes). The > called function uses the value of toc to access its global variables. > This value gets stored in the processor's register R2, also known as > RTOC. Different modules (such as your app, CarbonLib, QuickTime..) > use different values of toc. A call from one module to another -- such > as a callback from the system into your app -- must ensure that RTOC > is set appropriately. > > In a callback, the system calls the address sBoundsChangingUPP, where > there is some glue code previously set up by NewEventHandlerUPP. > The glue code extracts toc from the transition vector, sets RTOC to > that value, and calls the address specified in the transition vector, > i.e. your FB function code. > > >> the great advantage of making FNs "Local Mode" isn't possible for >> most handlers because they need to access globals. > > You can of course remove Local Mode if you want to contaminate your > handler routine with global variables. Most handlers can be written > without globals. I write Local Mode as an advertisement of purity in > heart; such routines can be simply copied in one step from a demo into > a project under development, where they will "just work" or maybe > "just compile" :-) > > >> Finally, we obviously need to accept another GLOBAL (actually a >> pseudo static var), namely sBoundsChangingHandler. >> BTW, why must it be a GLOBAL? > > Both sBoundsChangingUPP and sBoundsChangingHandler must be persistent, > so that their contents remain as set by the install routine. They > cannot be stack-based local variables, because those are liable to be > overwritten by other local fns. Neither needs to be disposed, as they > are initialised on the first call only. These requirements are met in > FB by making them globals. > > begin globals > dim as TransitionVector sBoundsChangingHandler // 'static' var > dim as proc sBoundsChangingUPP // 'static' var > end globals > > I like to embed the globals declaration inside the installer routine, > so that the installer can be copied from a demo and pasted into a new > project, in one step. This also corresponds well with the static > variable in C, which is the recommended way for storing an XxxxxUPP: > > // initialize once; never dispose > static EventHandlerUPP handlerUPP = NewEventHandlerUPP( MyHandler ); > > In C, the internal details of the transition vector/ProcPtr are done > by the compiler and not exposed to the application programmer: > typedef CALLBACK_API( OSStatus, EventHandlerProcPtr > )(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void > *inUserData); > > In FB, we have to put up with a little more ugliness when we install a > callback routine. > > Robert P. > > -- >