|
Technote 1127
In Search of... |
CONTENTSThe Problem: Missing routines |
They're everywhere: Missing Links! If you are writing a CFM
application and want to call This Technote is of interest to developers attempting
to use the classic 68K API's currently missing from
WARNING: This is an advanced topic for use by developers
who can't continue development because of these missing
API's. Even as this Technote is being published, efforts are being made
to identify the missing links and get them added to |
This Technote provides a temporary solution by showing
how to create glue code which you can include with your
program. You need to write one glue routine for each missing API.
Each of these routines determines the address of the 68K
A-Trap and then calls it via |
Note: The following four API's are not missing from
Here is |
extern pascal void InitWindows(void) ONEWORDINLINE(0xA912); extern pascal void SelectWindow(WindowPtr's theWindow) ONEWORDINLINE(0xA91F); extern pascal WindowPtr FrontWindow(void) ONEWORDINLINE(0xA924); extern pascal Boolean CheckUpdate(EventRecord *theEvent) ONEWORDINLINE(0xA911); |
For |
pascal void InitWindows(void) // ONEWORDINLINE(0xA912); { CallUniversalProc(GetToolboxTrapAddress(0xA912), kPascalStackBased); } |
That was not too hard. Just in case you don't know
where the value |
extern pascal void SelectWindow(WindowPtr theWindow) // ONEWORDINLINE(0xA91F); { CallUniversalProc(GetToolboxTrapAddress(0xA91F), kPascalStackBased | STACK_ROUTINE_PARAMETER(1,SIZE_CODE(sizeof(WindowPtr))), theWindow // the parameter ); } |
Nothing complicated here--we added the
|
extern pascal WindowPtr FrontWindow(void) // ONEWORDINLINE(0xA924); { return (WindowPtr) CallUniversalProc( GetToolboxTrapAddress(0xA924), kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(WindowPtr))) ); } |
This one uses the |
extern pascal Boolean CheckUpdate(EventRecord *theEvent) // ONEWORDINLINE(0xA911); { return (Boolean) CallUniversalProc( GetToolboxTrapAddress(0xA911), kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))) | STACK_ROUTINE_PARAMETER(1,SIZE_CODE(sizeof(EventRecord*))) ); } |
Operating system A-Traps pass their parameters in
registers. Apple recently introduced the |
// WARNING: Don't use this code - read rest of section! //#pragma parameter __D0 PBXGetVolInfoSync(__A0) pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock) // TWOWORDINLINE(0x7012, 0xA060); { return (OSErr) CallOSTrapUniversalProc( (UniversalProcPtr) GetOSTrapAddress(0xA060), kRegisterBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | REGISTER_RESULT_LOCATION(kRegisterD0) | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, kTwoByteCode) | // selector REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr*))), 0x0012, // selector paramBlock); // parameter(s) } // WARNING: Don't use this code - read rest of section! |
The first thing to notice is that we're using
How did we determine the selector ( |
MacsBug> dh 7012 A060 MOVEQ #$12,D0 _FSDispatch |
Just in case you're confused, we are copying the
API and the Notice that I'm using |
_NewPtr = 0xA11E _NewPtrSys = 0xA51E _NewPtrClear= 0xA31E _NewPtrSysClear = 0xA71E |
You can tell that bit 9 is the 'Sys' bit and bit 10 is
the 'Clear' bit. These four A-Traps are dispatched through a
single dispatcher that uses these flag bits to determine
which routine to call. Guess what? The A-Trap for
|
_FSDispatch = 0xA060 _HFSDispatch = 0xA260 _FSDispatchAsync = 0xA460 _HFSDispatchAsync = 0xA660 |
See Inside Macintosh: Operating Systems Utilities for more information on the Trap Manager. So how does the A-Trap dispatcher know what A-Trap
invoked it? It's passed to the dispatcher in register D1. So to fix out
Note: The order here is
critical! If CFM glue is calling a trap that has
been patched with CFM code and the |
pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock) // TWOWORDINLINE(0x7012, 0xA060); { return (OSErr) CallOSTrapUniversalProc ( (UniversalProcPtr) GetOSTrapAddress(0xA060), kRegisterBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | REGISTER_RESULT_LOCATION(kRegisterD0) | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, kTwoByteCode) | // selector REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, kTwoByteCode) | // A-Trap REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr*))), 0x0012, // selector 0xA060, // A-Trap paramBlock); // parameter(s) } |
Register-dispatched A-Traps require a selector passed
ether register D0 or D1. Here's an AppleGuide API that until
recently was missing from the CFM-68K |
pascal AGErr AGGeneral(AGRefNum refNum, AGEvent theEvent) // TWOWORDINLINE(0x700D, 0xAA6E); { return (AGErr) CallUniversalProc(GetToolboxTrapAddress(0xAA6E), kD0DispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(AGErr))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(refNum))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(theEvent))), 0x000D, // selector -> D0 refNum,theEvent // the parameters ); } |
The first thing to notice about this code is the selector
( |
MacsBug> dh 700D AA6E MOVEQ #$0D,D0 _AGGeneral |
This gives us a clue to determine that this API is D0-dispatched. Now,
how do we determine the correct value to
use for the |
MacsBug> api AA6E ° AA6E _AppleGuideDispatch DO.W=0001 AGOpen DO.W=0002 AGOpenWithSearch DO.W=0003 AGOpenWithSequence <...> |
From this we can determine that the selector is in fact
word-based; therefore, we know to use the |
Stack-dispatched A-Traps require a selector passed in on
the stack. While |
// WARNING: Don't use this code - read paragraph below static Point TEGetPoint(short offset,TEHandle hTE) { // THREEWORDINLINE(0x3F3C, 0x0008, 0xA83D); // MOVE.W #$0008,-(A7) // _TEDispatch // _TEGetPoint is A83D (_TEDispatch) when A7^.W=0008 return (Point) CallUniversalProc( GetToolboxTrapAddress(_TEDispatch), // address of dispatcher kStackDispatchedPascalStackBased | // proc info RESULT_SIZE(SIZE_CODE(sizeof(Point))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(TEHandle))), 0x0008, // selector -> stack offset, hTE // parameter(s) ); } // WARNING: Don't use this code - read paragraph below |
This time the selector was passed in as a word on the
stack. Does everything make sense? Almost. This was a trick
question to catch anyone thinking they just could skip ahead
to the tough ones. In this case, the |
static Point TEGetPoint(short offset,TEHandle hTE) { // THREEWORDINLINE(0x3F3C, 0x0008, 0xA83D); // MOVE.W #$0008,-(A7) // _TEDispatch // _TEGetPoint is A83D (_TEDispatch) when A7^.W=0008 long private_results = CallUniversalProc( GetToolboxTrapAddress(_TEDispatch), // address of dispatcher kStackDispatchedPascalStackBased | // proc info RESULT_SIZE(SIZE_CODE(sizeof(Point))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(TEHandle))), 0x0008, // selector offset, hTE // parameter(s) ); return *(Point*) &private_results; } |
This is all well and good if the structure is four bytes in size. What would happen if it were smaller? Try this example: |
typedef struct CryptoCharsRecord { char findChar; char replaceChar; } CryptoCharsRec, *CryptoCharsPtr, **CryptoCharsHdl; |
If this structure was to be returned from |
+---------------------------+ Low Mem | 0 | <-- Address of private_result +---------------------------+ | 1 | +---------------------------+ | 2 | findChar +---------------------------+ High Mem| 3 | replaceChar +---------------------------+ |
In this case, neither the simple typecast nor the dereferenced-pointer typecast will work. What we have to do is dereference the address of our result, plus an offset to the high word. |
pascal CryptoCharsRec GetEncodeKey(char* pThePassword) { long private_results = CallUniversalProc( GetToolboxTrapAddress(0xAxxx), kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))) | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(EventRecord*))) theEvent // the parameter ); return *(((CryptoCharsRec*)&private_result) + 1); } |
At first glance, you might think that the offset should be two, but remember that in this case it's not a byte offset, it is an offset for a two-byte structure. C knows this and internally adds two instead of one. It's really easy to miscompute this offset, so here's a macro that will compute it for you given a variable or variable type: |
#define RESULT_OFFSET(type) \ ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0)) |
There's nothing complicated here. If the size of the structure is one then the offset to the high byte is three (bytes). If the size of the structure is two, then the offset to the high word is one (word); otherwise, the offset is zero. It's used like this: |
pascal CryptoCharsRec Get_Encode_Key(char* pThePassword) { long private_results = CallUniversalProc( GetToolboxTrapAddress(0xA911), kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))) | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(EventRecord*))) theEvent // the parameter ); return *(((CryptoCharsRec*)&private_result) + RESULT_OFFSET(CryptoCharsRec)); } |
Is this clear? So what happens if our result is larger than four
bytes? If this is the case then |
#ifdef applec #if sizeof(OSErr) > 4 #error "Result types larger than 4 bytes are not supported." #endif #endif |
Let's take a look at some API's actually missing from
|
pascal OSErr CursorDeviceMoveTo(CursorDevicePtr ourDevice, long absX, long absY) { // TWOWORDINLINE(0x7001, 0xAADB); // MOVEQ #$01,D0 | 7001 // _CursorDeviceDispatch | AADB return (OSErr) CallUniversalProc( (UniversalProcPtr)GetToolboxTrapAddress(0xAADB), kD0DispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kFourByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ourDevice))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(absX))) | DISPATCHED_STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(absY))), 0x00000001, // selector ourDevice, absX, absY); // parameter(s) } |
Now one missing from the |
static pascal OSErr FlushCodeCacheRange(void *address, unsigned long count) { // TWOWORDINLINE(0x7009, 0xA098); // MOVEQ #$09,D0| 7009 // _HWPriv | A098 return (OSErr) CallOSTrapUniversalProc( GetOSTrapAddress(_HWPriv), kRegisterBased | RESULT_SIZE (SIZE_CODE (sizeof (OSErr))) | REGISTER_RESULT_LOCATION (kRegisterD0) | REGISTER_ROUTINE_PARAMETER(1,kRegisterA0, SIZE_CODE(sizeof(address))) | REGISTER_ROUTINE_PARAMETER(2,kRegisterA1, SIZE_CODE(sizeof(count))) address,count); // parameter(s) } |
The following API is missing from both |
pascal ComponentResult TVSetFrequency(TVTunerComponent ci, long frequency) //FIVEWORDINLINE(0x2F3C, 0x04, kSelectTVSetFrequency, 0x7000, 0xA82A); // MOVE.L #$00040001,-(A7) // MOVEQ #$00,D0 // _ComponentDispatch { return (ComponentResult) CallUniversalProc( (UniversalProcPtr) GetToolboxTrapAddress(0xA82A), kD0DispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof(TVTunerComponent))) | DISPATCHED_STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(sizeof(long))) | DISPATCHED_STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(sizeof(long))), 0x0000, // D0 selector ci, frequency, // parameter(s) 0x00040001); // Stack dispatched selector } |
Full Example: HFS+ |
/* File: DiskInit.Glue.c Copyright: © 1984-1997 by Apple Computer, Inc. All rights reserved. */ #include <DiskInit.h>#include <MixedMode.h> static UniversalProcPtr gPack2TrapUPP = kUnresolvedCFragSymbolAddress; static UniversalProcPtr gUnimplementedUPP = kUnresolvedCFragSymbolAddress; pascal OSErr DIXFormat(short drvNum, Boolean fmtFlag, unsigned long fmtArg, unsigned long *actSize) // THREEWORDINLINE(0x700C, 0x3F00, 0xA9E9); // MOVEQ #$0C,D0 | 700C // MOVE.W D0,-(A7) | 3F00 // _Pack2 | A9E9 { long private_result = unimpErr; // assume unimplemented A-Trap if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPack2TrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPack2TrapUPP = GetToolboxTrapAddress(0xA9E9); if ((Ptr) gPack2TrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gPack2TrapUPP, kStackDispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(Boolean))) | DISPATCHED_STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(unsigned long))) | DISPATCHED_STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(unsigned long))), 0x000C, // selector drvNum, fmtFlag, fmtArg, actSize); // parameter(s) } return (OSErr) private_result; } pascal OSErr DIXZero(short drvNum, ConstStr255Param volName, short fsid, short mediaStatus, short volTypeSelector, unsigned long volSize, void *extendedInfoPtr) // THREEWORDINLINE(0x700E, 0x3F00, 0xA9E9); // MOVEQ #$0E,D0 | 700E // MOVE.W D0,-(A7) | 3F00 // _Pack2 | A9E9 { long private_result = unimpErr; // assume unimplemented A-Trap if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPack2TrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPack2TrapUPP = GetToolboxTrapAddress(0xA9E9); if ((Ptr) gPack2TrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gPack2TrapUPP, kStackDispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(ConstStr255Param))) | DISPATCHED_STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(unsigned long))) | DISPATCHED_STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(void *))), 0x000E, // selector drvNum, volName, fsid, mediaStatus, // parameter(s) volTypeSelector, volSize, extendedInfoPtr); } return (OSErr) private_result; } pascal OSErr DIReformat(short drvNum, short fsid, ConstStr255Param volName, ConstStr255Param msgText) // THREEWORDINLINE(0x7010, 0x3F00, 0xA9E9); // MOVEQ #$10,D0 | 7010 // MOVE.W D0,-(A7) | 3F00 // _Pack2 | A9E9 { long private_result = unimpErr; // assume unimplemented A-Trap if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPack2TrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPack2TrapUPP = GetToolboxTrapAddress(0xA9E9); if ((Ptr) gPack2TrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gPack2TrapUPP, kStackDispatchedPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(short))) | DISPATCHED_STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(ConstStr255Param))) | DISPATCHED_STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(ConstStr255Param))), 0x0010, // selector drvNum, fsid, volName, msgText); // parameter(s) } return (OSErr) private_result; } |
/* File: ControlStrip.Glue.c Copyright: © 1984-1997 by Apple Computer, Inc. All rights reserved. */ #include <MixedMode.h>#include <ControlStrip.h> static UniversalProcPtr gControlStripTrapUPP = kUnresolvedCFragSymbolAddress; static UniversalProcPtr gUnimplementedUPP = kUnresolvedCFragSymbolAddress; #define _ControlStripDispatch 0xAAF2 pascal Boolean SBIsControlStripVisible(void) // TWOWORDINLINE(0x7000, 0xAAF2); // MOVEQ #$00,D0 // _ControlStripDispatch { long private_result = 0L; if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gControlStripTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gControlStripTrapUPP = GetToolboxTrapAddress(_ControlStripDispatch); if ((Ptr) gControlStripTrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gControlStripTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))), 0x0000); // selector } return (Boolean) private_result; } pascal void SBShowHideControlStrip(Boolean showIt) // THREEWORDINLINE(0x303C, 0x0101, 0xAAF2); // MOVE.W #$0101,D0 // _ControlStripDispatch { if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gControlStripTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gControlStripTrapUPP = GetToolboxTrapAddress(_ControlStripDispatch); if ((Ptr) gControlStripTrapUPP != (Ptr) gUnimplementedUPP) { CallUniversalProc(gControlStripTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(Boolean))), 0x0101, // selector showIt); // parameter(s) } } |
/* File: Power.Glue.c Copyright: © 1984-1997 by Apple Computer, Inc. All rights reserved. */ #include <MixedMode.h>#include <Power.h> static UniversalProcPtr gPowerTrapUPP = kUnresolvedCFragSymbolAddress; static UniversalProcPtr gUnimplementedUPP = kUnresolvedCFragSymbolAddress; pascal Boolean HardDiskPowered(void) // TWOWORDINLINE(0x7006, 0xA09E); // MOVEQ #$06,D0 | 7006 ; Move selector // _PowerMgr | A09E ; for _HardDiskPowered { long private_result = 0L; if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPowerTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPowerTrapUPP = GetToolboxTrapAddress(0xA09E); if ((Ptr) gPowerTrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gPowerTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))), 0x0006); // selector } return (OSErr) private_result; } pascal void SpinDownHardDisk(void) // TWOWORDINLINE(0x7007, 0xA09E); // MOVEQ #$07,D0 | 7006 ; Move selector // _PowerMgr | A09E ; for _SpinDownHardDisk { if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPowerTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPowerTrapUPP = GetToolboxTrapAddress(0xA09E); if ((Ptr) gPowerTrapUPP != (Ptr) gUnimplementedUPP) { CallUniversalProc(gPowerTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode), 0x0007); // selector } } pascal Boolean IsSpindownDisabled(void) // TWOWORDINLINE(0x7008, 0xA09E); // MOVEQ #$08,D0 ; Move selector // _PowerMgr ; for _IsSpindownDisabled { long private_result = 0L; if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPowerTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPowerTrapUPP = GetToolboxTrapAddress(0xA09E); if ((Ptr) gPowerTrapUPP != (Ptr) gUnimplementedUPP) { private_result = CallUniversalProc(gPowerTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))), 0x0008); // selector } return (OSErr) private_result; } // These two API's are strange in that they pass the boolean to the //A-Trap via the high-word of D0. The low-word holds the selector. //(Is this weird or what?) pascal void SetSpindownDisable(Boolean setDisable) // FOURWORDINLINE(0x4840, 0x303C, 0x0009, 0xA09E); // SWAP D0 ; Move setDisable to high-Word of D0 // MOVE.W #$0009,D0 ; Move selector to low-Word of D0 // _PowerMgr ; for _SetSpindownDisable { if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPowerTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPowerTrapUPP = GetToolboxTrapAddress(0xA09E); if ((Ptr) gPowerTrapUPP != (Ptr) gUnimplementedUPP) CallUniversalProc(gPowerTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode), (setDisable << 16) | 0x0009); // selector } pascal void AutoSleepControl(Boolean enableSleep) // FOURWORDINLINE(0x4840, 0x303C, 0x000D, 0xA09E); // SWAP D0 ; Move setDisable to high-Word of D0 // MOVE.W #$000D,D0 ; Move selector to low-Word of D0 // _PowerMgr ; for _AutoSleepControl { if ((Ptr) gUnimplementedUPP == (Ptr) kUnresolvedCFragSymbolAddress) gUnimplementedUPP = GetToolboxTrapAddress(_Unimplemented); if ((Ptr) gPowerTrapUPP == (Ptr) kUnresolvedCFragSymbolAddress) gPowerTrapUPP = GetToolboxTrapAddress(0xA09E); if ((Ptr) gPowerTrapUPP != (Ptr) gUnimplementedUPP) CallUniversalProc(gPowerTrapUPP, kD0DispatchedPascalStackBased | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode), (enableSleep << 16) | 0x000D); // selector } |
SummaryNow that you know how to glue in all those routines missing fromInterfaceLib , you are now officially out of
excuses. Time to write the next killer CFM application!
|
Further References
|
Downloadables |
AcknowledgmentsThanks to: Alan Lillich, Pete Gontier, Matt Mora, Quinn & Joe Zobkiw. |