Gestalt with the first parameter being the magic
bytes " OMS" (0x204F3D53) and the
second parameter being a pointer to a 32-bit variable that
receives the magic pointer.
{% comment %}
is there was a way to do this with newlines? this is ugly
{% endcomment %}
UniversalProcPtr OMS_GetGestaltPtr(void)
{
OSErr err;
uint32_t x;
err = Gestalt(0x204F3D53 /* " OMS" */, &x);
if (err != noErr)
return NULL;
return (UniversalProcPtr)x;
}CallUniversalProc
function to safely call into 68k code.
UniversalProcPtr oms_table[0x5e];
#define OMS_GESTALT_PROC_TYPE \
(kThinkCStackBased \
| RESULT_SIZE(kFourByteCode) \
| STACK_ROUTINE_PARAMETER(1, kTwoByteCode) \
| STACK_ROUTINE_PARAMETER(2, kFourByteCode))
int32_t OMS_Init(void)
{
uint32_t functable;
UniversalProcPtr omsptr;
omsptr = OMS_GetGestaltPtr();
if (!omsptr)
return -1;
functable = CallUniversalProc(omsptr, OMS_GESTALT_PROC_TYPE, 4, 0);
if (functable != (uint32_t)-1) {
memcpy(oms_table, (const void *)functable, sizeof(oms_table));
} else {
/* very old OMS */
uint32_t i;
functable = CallUniversalProc(omsptr, OMS_GESTALT_PROC_TYPE, 1, 0);
if (!functable)
return -1;
for (i = 0; i < ARRAY_SIZE(oms_table); i++, functable += 4)
oms_table[i] = (UniversalProcPtr)functable;
}
return 0;
}oms_table, provided that you know what the parameters
are. The easiest way I've found to find the parameters is to open an
OMS-capable program in a reverse-engineering tool, search for uses of
CallUniversalProc that look roughly like the initialization
code above, and mark the offset they are copied to as the OMS table with
the correct size and type. You can then find other uses of
CallUniversalProc that use the pointers in the OMS table,
and mark down the procedure type (the second parameter to
CallUniversalProc). To decode the procedure type, I've
written a simple utility to do the heavy lifting
here.
Do take note that it does not support register-based calling yet.
Feel free to send me any patches if you add support for it ;)