home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Frameworks / Extension Shell 1.3 / Extension Shell 1.3 (Source) / ExtensionShell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-06  |  16.7 KB  |  604 lines  |  [TEXT/R*ch]

  1. /*    NAME:
  2.         ExtensionShell.c
  3.  
  4.     WRITTEN BY:
  5.         Dair Grant
  6.                 
  7.     DESCRIPTION:
  8.         This file contains the main entry point of Extension Shell. It 
  9.         calls everything else to do the actual work.        
  10.  
  11.     NOTES:
  12.         •    Compiled with THINK C 6.0.
  13.         
  14.         •    Extension Shell must be compiled with System Heap and Locked attributes.
  15.             We don't lock ourselves down manually, so we implicitly depend on this.
  16.  
  17.         •    At startup, A0 contains the address of our CODE resource. THINK C CODE
  18.             resources reach their globals from A4, so we save the value of A4
  19.             when we enter and restore it when done. This is THINK C specific.
  20.         
  21.         •    We must also initialise the Toolbox. The only tricky one is QuickDraw,
  22.             since we can't reach a valid thePort. Instead we allocate a record of
  23.             size GrafSize and pass the address of the thePort field to InitGraf.
  24.         
  25.         •    Initialising the Window Manager would erase the screen. This
  26.             means we that we would zap all the previous icons, and feel an
  27.             irresistable urge to throw horrible windows and dialogs up on
  28.             screen at starutp. Don't initialise the Window Manager - see the
  29.             ‘DeskHook and INIT Evils’ Tech Note if you think you're special.
  30.  
  31.     ___________________________________________________________________________
  32.  
  33.  
  34.     RELEASE INFORMATION:
  35.         Extension Shell is freeware. Basically, it tries to tie together all the
  36.         code/ideas related to INIT writing that have been floating around for
  37.         years, and combine them in an Extension-independant way. All of the
  38.         techniques it makes use of are, to the best of my knowledge, public
  39.         domain/freeware themselves. However, Extension Shell is still
  40.         Copyrighted © 1993-1994, Dair Grant. You may not redistribute it in any
  41.         modified form.
  42.  
  43.         You may not charge for Extension Shell itself, or redistribute it as part
  44.         of a commercial package without my prior permission. Shareware houses, BBS
  45.         Sysops, or CD-ROM Distributors may include Extension Shell in their
  46.         collections, on the understanding that they do not charge for access to
  47.         Extension Shell specifically.
  48.  
  49.         If you use Extension Shell in a commercial Extension, you are obliged to
  50.         display some form of indication that your product uses Extension Shell code.
  51.         This notice must be plainly visible to users (either in the 'vers' resource,
  52.         or in some other form of documentation), and not just those curious enough to
  53.         use ResEdit. Shareware and Freeware authors can use the code without notice.
  54.  
  55.         End of <legalstuff.h>. I do plan to support this code. If you have any
  56.         problems, or see any errors in the code, let me know, and the source will
  57.         be updated. If you don't like how something is implemented, and can think
  58.         of a better way - again, let me know.
  59.  
  60.     ___________________________________________________________________________
  61. */
  62. //=============================================================================
  63. //        Include files                                                                     
  64. //-----------------------------------------------------------------------------
  65. #include <GestaltEqu.h>
  66. #include "ESConstants.h"
  67. #include "ExtensionShell.h"
  68. #include "StandaloneCode.h"
  69. #include "NotifyMsg.h"
  70. #include "ShowIcon.h"
  71. #include "ParamBlock.h"
  72. #include "InstallCode.h"
  73. #include "UninstallCode.h"
  74. #include "AddrsTable.h"
  75.  
  76.  
  77.  
  78.  
  79.  
  80. //=============================================================================
  81. //        Private function prototypes                                                                     
  82. //-----------------------------------------------------------------------------
  83. void        main(void);
  84. void        InitToolbox(void);
  85. void        InitParamBlock(void);
  86. void        CallESHandler(short theMsg);
  87. OSErr        InstallForESHandler(void);
  88. void        TryAndUninstallESHandlerResources(void);
  89. void        IndicateError(void);
  90. void        ShowTheIcon(void);
  91. pascal Boolean UserForcedDisable(short keyCode, Boolean checkMouse);
  92. pascal Boolean IsTrapAvailable(int trapNum);
  93.  
  94.  
  95.  
  96.  
  97.  
  98. //=============================================================================
  99. //        Global variables                                                                 
  100. //-----------------------------------------------------------------------------
  101. FakeQD            gTheQDGlobals;
  102. ESParamBlock    gTheParamBlock;
  103. AddressTable    *gTheAddressTable;
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114. //=============================================================================
  115. //        main : Entry point to our 'INIT' code resource.                                                                 
  116. //-----------------------------------------------------------------------------
  117. //        Note :    The only thing we have to watch out for is that we have to get
  118. //                access to our globals. We do this in the way mentioned above.
  119. //
  120. //                Unlike most 'INIT' entry routines, we don't call RecoverHandle,
  121. //                HLock, and DetachResource on ourselves. We don't leave *anything*
  122. //                behind apart from the trap-patches. We don't lock ourselves down
  123. //                as the 'INIT' resource was compiled with System Heap & Locked
  124. //                attributes.
  125. //-----------------------------------------------------------------------------
  126. void main(void)
  127. {    THz                oldZone;
  128.  
  129.  
  130.  
  131.  
  132.     // Set up A4, switch to the System Zone so that any memory we allocate
  133.     // hangs out there, and initialise everything
  134.     GetGlobals();
  135.     oldZone = GetZone();
  136.     SetZone(SystemZone());
  137.     InitToolbox();
  138.     InitParamBlock();
  139.     
  140.     
  141.  
  142.     // Execute the ES Handler CODE resource
  143.     CallESHandler(kInitialiseParamBlock);
  144.  
  145.  
  146.  
  147.     // Try and install the whatever we have to. If we don't have
  148.     // anything to install, InstallUsersResources() returns noErr.
  149.     if (InstallForESHandler() != noErr)
  150.         {
  151.         // If there's a problem, we have to call the handler again
  152.         CallESHandler(kHandleError);
  153.         
  154.     
  155.     
  156.         // If we're allowed to, try and remove any code that was installed
  157.         if (gTheParamBlock.removeInstalledCode)
  158.             TryAndUninstallESHandlerResources();
  159.         }
  160.  
  161.  
  162.  
  163.     // Handle any errors - this could arise from a failure to install
  164.     // a code resource, or the Extension might have decided it
  165.     // just isn't able to run (e.g., we're under System 6.x.x).
  166.     if (gTheParamBlock.beepNow || gTheParamBlock.postError)
  167.         IndicateError();
  168.     
  169.     
  170.         
  171.     // Show any icons that we're to show
  172.     ShowTheIcon();
  173.  
  174.  
  175.  
  176.     // Return to the previous zone, and restore A4
  177.     SetZone(oldZone);
  178.     UngetGlobals();
  179. }
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190. //=============================================================================
  191. //        InitToolbox : Initialises the Toolbox.                                                                 
  192. //-----------------------------------------------------------------------------
  193. //        Note :    If we initialise all the Toolbox Managers, we will erase the
  194. //                screen. This looks ugly - so all but the minimum is moved inside
  195. //                the __InitAllToolbox__ #define.
  196. //-----------------------------------------------------------------------------
  197. void InitToolbox(void)
  198. {
  199.  
  200.  
  201.  
  202.  
  203.     // Initialise the bits of the Toolbox that we need
  204.     InitGraf(&gTheQDGlobals.thePort);
  205.  
  206.  
  207.  
  208. #ifdef __InitAllToolbox__
  209.     // This fixes the pre-Mac II bug that can happen if we try and create a window
  210.      // from within an INIT. See the ‘DeskHook and INIT Evils’ Tech Note.
  211.     *((void**)DragHook) = NULL;
  212.     *((void**)DeskHook) = NULL;
  213.  
  214.  
  215.  
  216.     // Initialise the rest of the Toolbox
  217.     InitFonts();
  218.     InitWindows();
  219.     InitCursor();
  220.     InitMenus();
  221.     InitDialogs(NULL);
  222.     TEInit();
  223. #endif
  224.     
  225.     
  226.     
  227.     // Flush out any events that may be lurking
  228.     FlushEvents(everyEvent, 0);
  229.     FlushEvents(everyEvent, 0);
  230.     FlushEvents(everyEvent, 0);
  231. }
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242. //=============================================================================
  243. //        InitParamBlock : Initialise gTheParamBlock.                                                             
  244. //-----------------------------------------------------------------------------
  245. //        Note :    We want to minimise the work the user's CODE resource has to
  246. //                do. As such we minimise everything to the 'least harmful'
  247. //                value.
  248. //-----------------------------------------------------------------------------
  249. void InitParamBlock(void)
  250. {    OSErr        myErr;
  251.  
  252.     
  253.  
  254.     
  255.     // Initialise the general values
  256.     myErr = Gestalt(gestaltSystemVersion, &gTheParamBlock.systemVersion);
  257.     gTheParamBlock.IsTrapAvailable        = IsTrapAvailable;
  258.     gTheParamBlock.UserForcedDisable    = UserForcedDisable;
  259.  
  260.  
  261.  
  262.     // Initialise the Icon related values
  263.     gTheParamBlock.numIcons                = 0;
  264.     gTheParamBlock.animationDelay        = 3;
  265.     
  266.     
  267.     
  268.     // Initialise the installable code related values
  269.     gTheParamBlock.installAddressTable    = false;
  270.     gTheParamBlock.numCodeResources        = 0;
  271.     gTheParamBlock.errorIndex            = 0;
  272.     gTheParamBlock.theErr                = noErr;
  273.  
  274.     
  275.         
  276.     // Initialise the error handling related values
  277.     gTheParamBlock.removeInstalledCode    = false;
  278.     gTheParamBlock.beepNow                = false;
  279.     gTheParamBlock.postError            = false;
  280.     gTheParamBlock.errorStringsID        = 0;
  281.     gTheParamBlock.errorStringIndex        = 0;
  282. }
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293. //=============================================================================
  294. //        CallESHandler : Execute this Extension's ES Handler CODE resource.                                                             
  295. //-----------------------------------------------------------------------------
  296. //        Note :    This routine can be called several times. We load the CODE
  297. //                resource in once, and save it in a static variable. When
  298. //                the System closes our resource fork, the code will get
  299. //                flushed out (we're not calling DetachResource).
  300. //
  301. //                If we can't find the ES Handler, we die - nothing else for it.
  302. //-----------------------------------------------------------------------------
  303. void CallESHandler(short theMsg)
  304. {    static void        (*theHandler)(short theMsg, ESParamBlock *gTheParamBlock)=nil;
  305.     Handle            theHnd;
  306.  
  307.  
  308.  
  309.  
  310.     // If we've not already loaded the code, do so, and lock it down
  311.     if (theHandler == nil)
  312.         {
  313.         theHnd = Get1Resource(kESHandlerCodeType, kESHandlerCodeID);
  314.         if (theHnd == nil)
  315.             DebugStr("\pExtension Shell - couldn't find ES Handler");
  316.         else
  317.             HLock(theHnd);
  318.             
  319.         theHandler = (ProcPtr) StripAddress(*theHnd);
  320.         }
  321.     
  322.  
  323.     
  324.     // Call the code with the message and gTheParamBlock
  325.     (*theHandler)(theMsg, &gTheParamBlock);
  326. }
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337. //=============================================================================
  338. //        InstallForESHandler : Install what the ES Handler wants installed.                                                             
  339. //-----------------------------------------------------------------------------
  340. //        Note :    This routine attempts to install the routines the ES Handler
  341. //                CODE resource wants installed. If there is a problem, the
  342. //                appropriate fields in gTheParamBlock will be filled in, and
  343. //                an error code returned. If everything installs without a
  344. //                problem, noErr is returned.
  345. //-----------------------------------------------------------------------------
  346. OSErr InstallForESHandler(void)
  347. {    int        i;
  348.     OSErr    theErr=noErr;
  349.  
  350.  
  351.  
  352.  
  353.     // If we're to install an address table, install it. If there's a problem,
  354.     // it will have to stay locked in the System heap. But we can't set it up
  355.     // after we install everything, because some of the things we install might
  356.     // depend on earlier things being installed correctly. After we've installed
  357.     // it we call the ES Handler again just in case there's something special
  358.     // it wants to do to the address table. There may well be some Extension
  359.     // specific fields tagged onto the end of the address table and the ES
  360.     // Handler will have to initialise them to some values. If there's a problem,
  361.     // the ES Handler can set gTheParamBlock.theErr to some error value (any
  362.     // error value) and we won't install any code. The Handler will then be
  363.     // called later on to handle the error as normal.
  364.     if (gTheParamBlock.installAddressTable)
  365.         {
  366.         InstallAddressTable();
  367.         
  368.         CallESHandler(kInitialiseAddrsTable);
  369.         if (gTheParamBlock.theErr != noErr)
  370.             return(gTheParamBlock.theErr);
  371.         }
  372.  
  373.  
  374.  
  375.     // Install each resource in turn. If there's a problem, we save the
  376.     // error details and break out of the loop.
  377.     for (i = 1; i <= gTheParamBlock.numCodeResources && theErr == noErr; i++)
  378.         {
  379.         theErr = InstallCode(i);
  380.         if (theErr != noErr)
  381.             {
  382.             gTheParamBlock.errorIndex = i;
  383.             gTheParamBlock.theErr     = theErr;
  384.             }
  385.         }
  386.         
  387.         
  388.     
  389.     // Return any error code - gTheParamBlock.TheErr is initialised to
  390.     // noErr, so it always holds the correct value.
  391.     return(gTheParamBlock.theErr);
  392. }
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403. //=============================================================================
  404. //        TryAndUninstallESHandlerResources : Try and uninstall what was
  405. //                                            previously installed.
  406. //-----------------------------------------------------------------------------
  407. //        Note :    This routine attempts to remove the routines the ES Handler
  408. //                resource tried to install. The error index is assumed to be at
  409. //                the resource that could not be installed, and so only entries
  410. //                before ErrorIndex are removed.
  411. //
  412. //                We make *no* guarantees as to what can be removed. Hopefully,
  413. //                most things can, but you never know.
  414. //-----------------------------------------------------------------------------
  415. void TryAndUninstallESHandlerResources(void)
  416. {    int        i;
  417.  
  418.  
  419.  
  420.  
  421.     // gTheParamBlock.ErrorIndex contains the index of the item that
  422.     // couldn't be installed. We try and uninstall everything before this.
  423.     // If we bombed on the first item, there's nothing to uninstall.
  424.     if (gTheParamBlock.errorIndex > 1)
  425.         {
  426.         for (i = 1; i < gTheParamBlock.errorIndex; i++)
  427.             UninstallCode(i);
  428.         }
  429. }
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440. //=============================================================================
  441. //        IndicateError : Provide some error handling capabilities.                                                                 
  442. //-----------------------------------------------------------------------------
  443. //        Note :    This routine is how Extension Shell communicates errors to the
  444. //                user. The two functions it offers are to beep, and to post a 
  445. //                Notification Manager dialog to the user.
  446. //-----------------------------------------------------------------------------
  447. void IndicateError(void)
  448. {
  449.  
  450.  
  451.  
  452.  
  453.     // If we're to beep, do so now
  454.     if (gTheParamBlock.beepNow)
  455.         SysBeep(30);
  456.     
  457.     
  458.     
  459.     // If we're to post a NM message, do so
  460.     if (gTheParamBlock.postError)
  461.         NotificationMessage(gTheParamBlock.errorStringsID, gTheParamBlock.errorStringIndex);
  462. }
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473. //=============================================================================
  474. //        ShowTheIcon : Call PlotINITIcon to display the icons.                                                             
  475. //-----------------------------------------------------------------------------
  476. //        Note :    We pull the values out of gTheParamBlock, and let PlotINITIcon
  477. //                do all the work.
  478. //-----------------------------------------------------------------------------
  479. void ShowTheIcon(void)
  480. {
  481.  
  482.  
  483.  
  484.     // Call PlotINITIcon to do the work
  485.     PlotINITIcon(gTheParamBlock.systemVersion >= 0x0700,
  486.                  gTheParamBlock.animationDelay,
  487.                  gTheParamBlock.numIcons,
  488.                  &gTheParamBlock.theIcons);
  489. }
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500. //=============================================================================
  501. //        UserForcedDisable : Called by the user's CODE to scan for disables.                                                             
  502. //-----------------------------------------------------------------------------
  503. //        Note :    We return true if the key corresponding to KeyCode is pressed,
  504. //                and false otherwise.
  505. //                If CheckMouse is true, we also return false if the mouse is not
  506. //                pressed, and true if it is.
  507. //-----------------------------------------------------------------------------
  508. pascal Boolean UserForcedDisable(short keyCode, Boolean checkMouse)
  509. {    unsigned char    theKeys[16];
  510.  
  511.  
  512.  
  513.  
  514.     // First check the keyboard
  515.     GetKeys((void *) theKeys);
  516.     if ((theKeys[keyCode >> 3] >> (keyCode & 7)) & 1)
  517.         return(true);
  518.     
  519.     
  520.     
  521.     // No? OK, check if the mouse button is down
  522.     if (checkMouse)
  523.         return(Button());
  524.     
  525.     
  526.     
  527.     // If we've got this far, nothing is being pressed
  528.     return(false);
  529. }
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540. //=============================================================================
  541. //        GetTrapType : Is a given trap an OS trap or a Toolbox trap?                                                             
  542. //-----------------------------------------------------------------------------
  543. TrapType GetTrapType(int trapNum)
  544. {    TrapType tType;
  545.  
  546.  
  547.  
  548.     tType = (trapNum & 0x0800) ? ToolTrap : OSTrap;
  549.     return(tType);
  550. }  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561. //=============================================================================
  562. //        IsTrapAvailable : Determines if a given trap number is implemented.                                                             
  563. //-----------------------------------------------------------------------------
  564. //        Note :    This function is based on Inside Mac VI, 3-8. It comes from
  565. //                Eric Shapiro's July BYTE '93 article, and the sample INITs
  566. //                he provides - on ftp.uu.net in /published/byte.
  567. //-----------------------------------------------------------------------------
  568. pascal Boolean IsTrapAvailable(int trapNum)
  569. {    TrapType    tType;
  570.     short        numToolboxTraps;
  571.  
  572.  
  573.  
  574.  
  575.     // Check trap word for Toolbox bit
  576.     tType = (trapNum & 0x0800) ? ToolTrap : OSTrap;
  577.     
  578.     
  579.     
  580.     // If it's a Toolbox trap...
  581.     if (tType == ToolTrap)
  582.         {
  583.         // Mask through largest # of traps available
  584.         trapNum &= 0x07FF;
  585.         
  586.         
  587.         // Is _InitGraf at address of 0xAA6E?
  588.         if (NGetTrapAddress(kInitGrafTrap,ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  589.             numToolboxTraps = 0x0200;                // Yes, only this many entries in dispatch table
  590.         else
  591.             numToolboxTraps = 0x0400;                // No, dispatch table is larger
  592.         
  593.         
  594.         // Trap # bigger than dispatch table? If so it's a bogus trap, so abort
  595.         if (trapNum > numToolboxTraps)
  596.             return(FALSE);
  597.         } 
  598.  
  599.  
  600.  
  601.     // Return trap address if it's not an unimplemented trap
  602.     return(NGetTrapAddress(trapNum, tType) != NGetTrapAddress(kUnimplementedTrap, ToolTrap));
  603. }
  604.