home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat España 21
/
macformat_21.iso
/
Shareware
/
Programación
/
VideoToolbox
/
VideoToolboxSources
/
SetGestaltValue1.c
< prev
next >
Wrap
Text File
|
1996-05-09
|
8KB
|
210 lines
/*
SetGestaltValue1.c
enum{gestaltPsychTable='Psyc'} // this can be whatever you want
error=SetGestaltValue1(gestaltPsychTable,table); // install a table address
error=SetGestaltValue1(gestaltPsychTable,NULL); // replace the table address with NULL
error=Gestalt(gestaltPsychTable,&tablePtr); // retrieve the table address
SetGestaltValue1.c provides an approximate equivalent for the
SetGestaltValue() function provided in System 7.5 (see Apple's
Gestalt.h), but only requires System 7 or better. SetGestaltValue1()
allows you to install a new Gestalt selector or replace an existing selector
installed by SetGestalt1. DON'T use SetGestaltValue1() to replace a
pre-existing selector NOT installed by SetGestalt1 because its attempt
to free the storage (upp and code) may fail.
The Macintosh Gestalt() function provides a way for many autonomous
programs to share a global table. All the programs simply call Gestalt()
with the same selector and Gestalt returns the table address. Any
program calling Gestalt() to get the table address should check that
error==0 and that table!=NULL before using the table. To set the
selector and table address in Gestalt you can either use
SetGestaltValue1 (this file), which works on all Mac Systems and
architectures, or you can use Apple's routines.
Instead of using SetGestaltValue1 (this file), you could use Apple's
routines. System 7.5 provides NewGestaltValue() and SetGestaltValue()
(see Apple's Gestalt.h). PowerPC computers require System 7.5 or better,
so your ppc code can safely assume the presence of those routines. If
your program may be run on 68k computers running an earlier System, then
your 68k code should link in Apple's GestaltValue.o library, which Apple
supplies on their developer disks.
Invent your own selector name, e.g. gestaltPsychTable. By convention,
the selector name should begin with "gestalt" and end with "Table". Its
value is a four-character code, like 'Psyc'. Apple reserves all the
lowercase-only codes for itself.
In order for the Gestalt selector routine to stick around, and not cause
grief to Gestalt by disappearing when the application quits, we follow
Apple's guidelines and install it in the System heap. Once installed
it'll stay there until the machine is rebooted. You can't get rid of a
selector once you've installed it, but you can call SetGestaltValue1()
again, and assign the response NULL.
The selector function that we install into the System Heap is 68k code,
because I know how to copy such routines, and have had no success doing
so with ppc code. To have the 68k code available even when this file is
compiled for ppc, without resorting to using resources, i.e. multiple files,
i saved the machine code from a disassembly in a C array.
QUESTION:
In thinking about the uses of this routine, it occurred to me that if an
application creates a table in its own heap space and publishes the table's
address via Gestalt, then it might happen that the application is
abnormally terminated before it has a chance to NULL the table address
published by Gestalt. The System would recover the application's memory,
including the table, but the Gestalt value would persist, dangerously
providing a pointer to memory that the System considers unassigned. So,
how can we tell if a table pointer is valid?
ANSWER:
Every running application has a unique process serial number (psn). An
application that creates a table in its own heap space and publishes the
table's address via Gestalt should store its psn in the table. Whenever
we retrieve a table address via Gestalt we should check the psn field.
If the table's psn field is not NULL, then we should make sure that that
process is still running. At the moment, David Brainard and I are only
worried about MEX files that all run as part of the MATLAB
application, so it is enough for us to simply make sure that the stored
psn matches our current psn.
#include <Processes.h>
ProcessSerialNumber psn;
Boolean ours;
// when we make the table, mark it as our own
error=GetCurrentProcess(&table->psn);
// when we access the table, make sure that it's ours
error=GetCurrentProcess(&psn);
error=SameProcess(&table->psn,&psn,&ours); // Apple says this is the way to compare psns.
if(!ours) table is invalid,
HISTORY:
5/7/96 dgp wrote it.
5/9/96 dgp got it to work on ppc.
*/
#include "VideoToolbox.h"
//#include <Gestalt.h>
// modified from Gestalt.h because our routine is ALWAYS 68k code.
#if GENERATINGCFM
#define New68kSelectorFunctionProc(userRoutine) \
(SelectorFunctionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppSelectorFunctionProcInfo, kM68kISA)
#else
#define New68kSelectorFunctionProc(userRoutine) \
((SelectorFunctionUPP) (userRoutine))
#endif
#if (THINK_C || THINK_CPLUS || SYMANTEC_C)
#pragma options(!profile)
#endif
#if __MWERKS__ && __profile__
#pragma profile off
#endif
// There's nothing special about these numbers. We hope that they won't coincide with
// machine instructions used in the tiny MyGestaltValue program, immediately following.
#define SELECTOR 0x12345678
#define RESPONSE 0x87654321
// SetGestaltValue1 copies the compiled version (below) of this code to the
// System heap and sets the copy's selector and response.
pascal OSErr MyGestaltValue(OSType selector,long *response); // private
pascal OSErr MyGestaltValue(OSType selector,long *response)
{
if(selector==SELECTOR){
*response=RESPONSE;
return 0;
}else return gestaltUnknownErr;
}
/*
MyGestaltValueCode is the 68k compiled code produced by Metrowerks C 8
for the MyGestaltValue routine above. This allows me to install a 68k
code version even when this file is compiled for ppc. I've found it easy
to copy, modify, and install a 68k routine, but haven't succeeded when I
tried to do the same with a ppc routine, because I'm not quite sure what
to do about the indirection through the TVector (nor have I found any
documentation on it.) Apple Developer Tech Support told me that all ppc
routines are called indirectly via a TVector.
*/
short myGestaltValueCode[]={
0x4E56,0x0000 // LINK A6,#$0000
,0x0CAE,0x1234,0x5678 // CMPI.L #$12345678,$000C(A6)
,0x000C
,0x6610 // BNE.S *+$0012
,0x206E,0x0008 // MOVEA.L $0008(A6),A0
,0x20BC,0x8765,0x4321 // MOVE.L #$87654321,(A0)
,0x426F,0x0010 // CLR.W $0010(A7)
,0x6006 // BRA.S *+$0008
,0x3F7C,0xEA52,0x0010 // MOVE.W #$EA52,$0010(A7)
,0x4E5E // UNLK A6
,0x205F // MOVEA.L (A7)+,A0
,0x504F // ADDQ.W #$8,A7
,0x4ED0 // JMP (A0)
,0x8E4D,0x5947,0x4553 // DC.B $80+$0E, 'MYGESTALTVALUE', $00
,0x5441,0x4C54,0x5641
,0x4C55,0x4500,0x0000
};
OSErr SetGestaltValue1(OSType selector,long response)
{
Ptr ptr;
OSErr error;
long value,version;
SelectorFunctionUPP upp,oldUpp;
THz heapZone;
long size;
unsigned short *wordPtr;
SelectorFunctionProcPtr functionPtr;
Gestalt(gestaltSystemVersion,&version);
if(version<0x700)PrintfExit("%s %ld. Sorry. I need System 7 or better.\n",__FILE__,(long)__LINE__);
functionPtr=(void *)myGestaltValueCode;
size=sizeof(myGestaltValueCode);
// copy our function to System Heap
ptr=NewPtrSys(size);
if(ptr==NULL)PrintfExit("%s %ld. No space in System Heap.\n",__FILE__,(long)__LINE__);
BlockMove(functionPtr,ptr,size);
// Set the copy's selector and response.
wordPtr=(unsigned short *)ptr;
wordPtr[3]=selector>>16;
wordPtr[4]=selector&0xffff;
wordPtr[10]=response>>16;
wordPtr[11]=response&0xffff;
#if GENERATINGPOWERPC
MakeDataExecutable(ptr,size);
#else
FlushCodeCacheRange(ptr,size);
#endif
heapZone=GetZone();
SetZone(SystemZone());
upp=New68kSelectorFunctionProc(ptr); // allocate UUP in System Heap
SetZone(heapZone);
// does our Gestalt selector already exist?
error=Gestalt(selector,&value);
if(!error){
// yes, replace it. (It may persist from an earlier run of MATLAB.)
error=ReplaceGestalt(selector,upp,&oldUpp);
if(error)PrintfExit("%s %ld. ReplaceGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
// free the old function's space in the System Heap
if(oldUpp!=NULL){
#if GENERATINGCFM
DisposePtr((Ptr)oldUpp->routineRecords[0].procDescriptor);
#endif
DisposePtr((Ptr)oldUpp);
}
}else{
// no, install it.
error=NewGestalt(selector,upp);
if(error)PrintfExit("%s %ld. NewGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
}
return error;
}