[comp.sys.mac.programmer] Gestalt - new and improved methods

potts@itl.itd.umich.edu (Paul Potts) (06/14/91)

I've been putting together some code to use Gestalt in its new and
improved form.  Since it has taken me a while to get it going, I thought
I would post it to save someone else time.

This uses the new method for checking trap availability described in IM-6,
chapter 3.  I've translated some of that code directly into THINK C.

If anyone finds an error, please post a correction. It seems to work fine.

----------- compatibility.h ------------
---- this is a header file that lists some useful function prototypes
and defines for the compatibility.c file ----------------------------

#define GESTALT_NOT_PRESENT -1
/* prototypes */
int NumToolboxTraps (void);
TrapType GetTrapType (int theTrap);
Boolean TrapAvailable (int theTrap);
Boolean WNEAvailable (void);
Boolean GestaltAvailable (void);
Boolean testAttribute (OSType selector, short attribute, short * error);
short GestaltFeature(OSType selector, long * feature);
Boolean GestaltPresent(void);

--------- compatibility.c --------------
---- here are some useful functions to work with Gestalt. ------

#include <GestaltEqu.h>
#include "Compatibility.h"	/* contains prototypes */

int NumToolboxTraps(void)
{ return ((NGetTrapAddress(_InitGraf, ToolTrap) == 
		NGetTrapAddress(0xAA6E, ToolTrap)) ? 0x200 : 0x400); }

TrapType GetTrapType (theTrap) int theTrap;
{ return ((theTrap & 0x0800) ? ToolTrap : OSTrap); }

Boolean TrapAvailable (theTrap) int theTrap;
{ TrapType tType;
	tType = GetTrapType (theTrap);
	if (tType == ToolTrap)
	{ theTrap = (theTrap & 0x07FF);
		if (theTrap >= NumToolboxTraps())
			theTrap = _Unimplemented;
	}
	return ((NGetTrapAddress(theTrap, tType) 
			!= NGetTrapAddress(_Unimplemented, ToolTrap)));
}

Boolean WNEAvailable(void)
{ return (TrapAvailable (0xA860)); }

Boolean GestaltAvailable (void)
{ return (TrapAvailable (0xA1Ad /*Gestalt*/ )); }

Boolean GestaltPresent()
{
	return GestaltAvailable();
}

short GestaltFeature(OSType selector, long * feature)
{
	return Gestalt(selector, feature);
}

Boolean testAttribute (OSType selector, short attribute, short * error)
{
	long feature;
	if (GestaltPresent())
	{	
		*error = GestaltFeature (gestaltHardwareAttr, &feature);
		return (BitTst((void*)&feature, 31 - attribute));
	}
		else
	{
		* error = -1;
	}	/* my code for Gestalt Not Present */
}

----------------------------------------------------------
------ Now here is some code that shows how you might ----
------ call these routines -------------------------------

void HandleGestaltError(short error)
{
	switch (error)
	{
		case GESTALT_NOT_PRESENT:
			error_message (NO_GESTALT);
                        /* do whatever error handling you do */
                        break;
						
		case gestaltUnknownErr:
		case gestaltUndefSelectorErr:
		/* could handle these cases separately,
                   but I just return a general message */
		default:
                        error_message (GESTALT_ERROR);
                        break;
                /* NOTE THE FALL-THROUGH which occurs when I
                   have a case without an explicit break */ 
       } /* end of switch */
} /* end of procedure */

----------- this example function tests for compatibility by
----------- looking to see if an apple sound chip is present,
----------- and returns false if it isn't.

Boolean compatible()
{
	Boolean result;
	short error;

	result = testAttribute (gestaltHardwareAttr, gestaltHasASC, &error);
	if (error !=0) /* if Gestalt returned an OS Error or -1 */
	{
		HandleGestaltError(error);
		return (FALSE);	
	}
		else /* assume result is correct */
	{
		if (!result) /* sound chip bit was zero */
		{
			error_message (NO_SOUND_CHIP); 
			return (FALSE);	
		}
			else /* sound chip bit was one */
		{
			return (result); /* return TRUE */
		}
	}	/* end of no OS Error returned case */
} /* end of procedure */

--------------- Have fun!  let me know if anyone finds errors. -------

Paul Potts
potts@itl.itd.umich.edu
Paul_Potts@um.cc.umich.edu
 

keith@Apple.COM (Keith Rollin) (06/17/91)

In article <1991Jun14.160733.14793@terminator.cc.umich.edu> potts@itl.itd.umich.edu (Paul Potts) writes:
>I've been putting together some code to use Gestalt in its new and
>improved form.  Since it has taken me a while to get it going, I thought
>I would post it to save someone else time.
>
>This uses the new method for checking trap availability described in IM-6,
>chapter 3.  I've translated some of that code directly into THINK C.
>
>If anyone finds an error, please post a correction. It seems to work fine.

In the code that you posted, you check for the existance of the
_Gestalt trap. I don't think this is a good idea. Gestalt is both glue
and a trap.  When you compile a program with a version of MPW or THINK
that supports Gestalt, you end up calling the glue. The glue checks to
see if the trap is implemented. If so, the trap is called. If not, the
rest of the glue provides some emulated behavior. If you check for the
trap yourself, you loose out on this emulated behavior.

Actually, the above is just a little shy of the truth. It is possible
for you to specify that you want your program to be built for 7.0 or
later, in which case you end up calling the trap directly. However, in
that case, you can safely assume the existance of _Gestalt and not
check for it.

By the way, in testAttribute(), why do you use:

	return (BitTst((void*)&feature, 31 - attribute));

instead of

	return (feature & (1 << attribute));

?

-- 
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc. 
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"But where the senses fail us, reason must step in."  - Galileo