home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / System / Control Panel Project 0.9.5 / MyExtension.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-06  |  14.2 KB  |  384 lines  |  [TEXT/KAHL]

  1. /*
  2.     MyExtension.c
  3.     
  4.     Written by Ken Worley, 10/04/94, using Symantec Think C 7.0.
  5.     Copyright 1994. All Rights Reserved.
  6.     AOL KNEworley
  7.     
  8.     Feel free to use this code in an extension of your own.  Please don't
  9.     publish or distribute this code without giving me proper credit.
  10.     
  11.     This code is set up to use Apple's "Universal Headers."  If you're not
  12.     using those, some slight modifications may be necessary (changing
  13.     pointer types).
  14.     
  15.     This extension is an example.  It shows how to use an extension to install
  16.     a trap patch and shows how to share data between an extension, a control
  17.     panel, and a trap patch.  You can use this as a basis for writing your own
  18.     extension/control panel combination (or just a plain extension).
  19.         
  20.     The method for sharing data between the extension and patch was adapted
  21.     from an extension called 'FlashInit.'  This was an example extension written
  22.     by Richard Harvey in April 1990.  Thanks Richard!!  The method involves
  23.     allocating a chunk of memory, then replacing a dummy reference in the patch
  24.     code with the actual address of the memory (our shared memory structure).
  25.     
  26.     We can't use that method with the control panel code because it gets written
  27.     back to disk, so we also store the address of the shared data in a resource
  28.     that the control panel can access when it is opened.
  29.     
  30.     This extension also incorporates 'ShowIconFamily' by Patrick C. Beard and
  31.     modified by James W. Walker.  This piece of code
  32.     is called to display the extension's icon at startup.  This
  33.     code was based on the original ShowInit by Paul Mercer, Darin Adler, Paul
  34.     Snively and Steve Capps.  These are the guys to blame for our startup icon
  35.     parades.  That piece of code (ShowIconFamily.c) is public domain.  I made
  36.     some modifications to it in order to use it without any global variables.
  37.     
  38.     This extension uses no global or static variables, so it's not necessary
  39.     to set up and restore A4.  All of our 'global' data is in the shared data
  40.     structure (in a locked block in the system heap).
  41.     
  42.     I've also included a 'sysz' resource in the resource file.  Pre-System 7
  43.     Macs will look at this resource when loading the extension and interpret the
  44.     number there as a request to expand the system heap by the specified number
  45.     of bytes.  The expanded space is not reserved for the extension, it is just
  46.     added to the system heap space.  System 7 expands and contracts the system
  47.     heap dynamically and so ignores the 'sysz' resource.  A template is also included
  48.     for easily modifying the sysz resource with ResEdit.
  49.     
  50.     We use what I call a 'preferences' resource to save some settings between
  51.     restarts.  For the most part, this same information is also held in memory
  52.     (in the shared data structure) while the computer is running so that the
  53.     patch code can access the settings.  The resource is normally accessed once
  54.     by the extension code, then accessed and possibly changed later by the control
  55.     panel code.
  56.     
  57.     This code sets a couple of the fields in the shared data structure which are
  58.     accessed and/or modified by other code later on.  The 'CPon' field is set to
  59.     true or false depending on whether or not the preferences resource indicates
  60.     the control panel was set to 'on' or 'off' when last closed.  The 'patched'
  61.     field is set to true if the trap patch was installed and false if it was not.
  62.     
  63.     About the only thing you'll ever need to modify in this file when writing
  64.     your own extension (unless you're making major changes) are some of the #defines.
  65.     
  66.         kTrapToPatch determines which trap the patch is installed for.
  67.         kParamBytes is the number of bytes passed on the stack as parameters for
  68.             the trap routine.  (This would be zero for a register based trap.)
  69.         kReturnBytes is the number of bytes reserved on the stack for the return
  70.             value.  (This would also be zero for a register based trap.)
  71.             
  72.         kTaskRsrcNo is the resource number of the patch code.
  73.         kTaskRsrcType is the resource type of the patch code ('task').
  74.         
  75.         kCDEVRsrcNo is the resource number of the control panel code.  You shouldn't
  76.             need to change this.
  77.             
  78.         kIconFamilyID is the resource number of the icon family our final file will
  79.             be using.  The number is used to send to ShowInit so our icon can be
  80.             shown in the startup icon parade.
  81.         
  82.         kXIconID is the resource number of the icon family to be used when there was
  83.             a problem when loading the extension.  This icon looks Xed out.
  84.         
  85.         kNoPatchIconID is the resource number of the icon family to be used when
  86.             the patch is not loaded (when the control panel is set to "off").
  87.         
  88.         kMemAddrType is the resource type of the resource used to hold the address of
  89.             the shared data structure.
  90.         kMemAddrID is the resource number of the above resource.
  91.     
  92.     BUILDING THE CODE RESOURCE
  93.     
  94.         This file should be included in a project of type 'code resource' along
  95.         with MacTraps. The type should be 'INIT' for the resource and it should
  96.         have the system heap attribute set. (It should NOT be locked).  The resulting
  97.         code resource should be included in the same file with the patch code
  98.         resource and the control panel resource with the overall file type being
  99.         'cdev'. The resource ID can be zero.
  100. */
  101.  
  102. /* trap patching defines */
  103.  
  104. #define        kTrapToPatch        _MenuSelect
  105. #define        kParamBytes            4        /* a Point-in global coordinates */
  106. #define        kReturnBytes        4        /* long int-hiword is menu id-loword is item# */
  107.  
  108. /* patch code defines */
  109.  
  110. #define        kTaskRsrcNo            128        /* the patch code's resource number */
  111. #define        kTaskRsrcType        'task'    /* the patch code's resource type */
  112.  
  113. /* other defines */
  114.  
  115. #define        kCDEVRsrcNo            -4064    /* rsrc no of cdev code (rsrc type 'cdev') */
  116.  
  117. /* The following three icons are the ones I defined for this example.  Modify them */
  118. /* for your purposes or come up with some on your own.  */
  119.  
  120. #define        kIconFamilyID        -4064    /* rsrc no of ICN# rsrc with our icons */
  121. #define        kXIconID            -4033    /* rsrc no of Xed out icon family */
  122. #define        kNoPatchIconID        -4034    /* rsrc no of icon family when patch not inst. */
  123.  
  124. /* control panel preferences resource defines */
  125.  
  126. #define kCPprefsRsrcType    'pref'
  127. #define    kCPprefsRsrcID        -4048    /* careful - this number is also used in the cdev */
  128.  
  129. /* shared memory address resource defines */
  130.  
  131. #define kMemAddrType        'memA'
  132. #define kMemAddrID            -4048    /* careful - this number is also used in the cdev */
  133.  
  134. typedef struct {
  135.     long    theAddr;
  136. } **memAddrHdl;
  137.  
  138. #include    <Traps.h>
  139.  
  140. #include "SharedData.h"            /* The definition of our shared data structure. */
  141.                                 /* Includes definitions of myDataStruct, myDataPtr, */
  142.                                 /* and myDataHandle to refer to this data */
  143.  
  144. /* Prototypes */
  145.  
  146. void    main( void );
  147. void    ShowIconFamily(short iconId);
  148.  
  149. /* Functions */
  150.  
  151. void    main( void )
  152. {
  153.     myDataPtr            myData;        /* pointer to shared data structure */
  154.     Handle                myTask;        /* handle to my trap patch code */
  155.     memAddrHdl            addrHandle;    /* handle to memory address resource */
  156.     UniversalProcPtr    myTaskAddr;    /* used to get addr of the task code */
  157.     THz                    saveZone;    /* used to save memory zone */
  158.     long                toReplace,    /* these two items are used to replace the bogus */
  159.                         replaceWith;    /* addr in the task code with the */
  160.                                         /* addr of the shared data structure */
  161.                                         
  162.     CPprefsHandle        prefsHandle;    /* Handle to the Control Panels prefs rsrc */
  163.     Boolean                showStartupIcon;    /* show icon at startup? */
  164.     Boolean                installPatch;        /* install trap patch? */
  165.     
  166.     Boolean                stillOK;        /* still OK to proceed? */
  167.     Boolean                sharedDataOK;    /* was shared data struct allocated OK? */
  168.     
  169.     stillOK = true;
  170.     showStartupIcon = true;
  171.     installPatch = true;
  172.     
  173.     myData = NULL;
  174.     myTask = NULL;
  175.     addrHandle = NULL;
  176.                                         
  177.     /*    First save the current memory zone, then switch to the System zone so
  178.      *    we're positive that all memory allocation occurs in the System Heap.
  179.      */
  180.     
  181.         saveZone = GetZone();
  182.         SetZone( SystemZone() );
  183.         
  184.     /*    Allocate memory (a pointer) for our data structure so that both this code
  185.      *    and the patch code will have access to the data.  (We'll see about
  186.      *    giving access to this data to the patch code later.)  We use a pointer
  187.      *    rather than a handle because the data has to be locked down anyway.
  188.      */
  189.         
  190.         myData = (myDataPtr)NewPtrSysClear(sizeof(myDataStruct));
  191.         
  192.         sharedDataOK = true;
  193.         
  194.         if ( !myData )
  195.         {
  196.             stillOK = false;
  197.             sharedDataOK = false;
  198.         }
  199.     
  200.     /*    Mark the data as in use until we're through with it.  Since we just
  201.      *    created it, we know no one is using it now.  Also initialize some
  202.      *    values in the shared data structure and set the check value so the
  203.      *    control panel can tell the extension actually ran.
  204.      */
  205.         if ( sharedDataOK )
  206.         {
  207.             myData->inUse = true;
  208.             myData->oldTrap = 0L;
  209.             myData->CPprefsRsrc = NULL;
  210.             myData->checkValue = kCheckValue;
  211.         }
  212.  
  213.     /*    Load the control panel's preferences resource to see if we should show
  214.      *    the icon at startup and if we should patch the trap.  After we've read it,
  215.      *    release it.  The control panel will reload it.  If we cannot read the
  216.      *    resource from the file (probably because it doesn't yet exist), just assume
  217.      *    true/yes for both questions.
  218.      */
  219.      
  220.          myData->CPon = true;        /* preset to 'on' unless we find otherwise */
  221.                                      /* installPatch was also preset to true above */
  222.          
  223.          prefsHandle = (CPprefsHandle)Get1Resource( kCPprefsRsrcType, kCPprefsRsrcID );
  224.          if ( prefsHandle )
  225.          {
  226.              if ( !(*prefsHandle)->On )
  227.              {
  228.                  installPatch = false;
  229.                  myData->CPon = false;
  230.              }
  231.              
  232.              if ( !(*prefsHandle)->ShowIcon )
  233.                  showStartupIcon = false;
  234.                  
  235.              ReleaseResource( (Handle)prefsHandle );
  236.          }
  237.     
  238.     /*    Get the address of the trap we're going to patch. */
  239.         if ( sharedDataOK )
  240.             myData->oldTrap = NGetTrapAddress( kTrapToPatch, ToolTrap );
  241.     
  242.     /*    Put the size of the trap's parameters and the size of the return value
  243.      *    (can be zero) in the shared data structure so that the patch code has
  244.      *    access to it.  This is used by the patch code to handle parameters that
  245.      *    are passed on the stack (same for the return value).  Note that with
  246.      *    register based routines (like a lot of the memory routines), the patch
  247.      *    has to know which registers are used and what their sizes are itself.
  248.      *    With stack based routines, the patch does not necessarily need to know
  249.      *    anything else about the parameters unless it wants to do something with
  250.      *    them.
  251.      */
  252.          if ( sharedDataOK )
  253.          {
  254.              myData->paramBytes = kParamBytes;
  255.              myData->returnBytes = kReturnBytes;
  256.          }
  257.         
  258.     /*    Now load the code resource that comprises the actual 'patch.'  This code
  259.      *    will execute (instead of the original code) when the trap is executed.
  260.      *    The patch itself determines whether or not to execute (jump to) the original
  261.      *    trap code once it's done its thing.  The actual patch code is in its own
  262.      *    resource of type 'task'.
  263.      */
  264.          if ( installPatch && stillOK )
  265.          {
  266.             myTask = Get1Resource( kTaskRsrcType, kTaskRsrcNo );
  267.         
  268.             if ( !myTask )
  269.                 stillOK = false;
  270.         }
  271.         
  272.     /*    Here's an example of a clever technique used in Harvey's code.  We use the
  273.      *    Munger routine to replace a predetermined pattern in the task code with
  274.      *    the handle of our data structure so that the patch code has access to
  275.      *    the data.  The patch code assigns its data structure handle to 0x12345678
  276.      *    (which is a bogus address).  We use Munger to find this pattern
  277.      *    and replace it with the real address of our data structure handle.
  278.      */
  279.  
  280.         replaceWith = (long)( myData );
  281.         toReplace = 0x12345678;
  282.         
  283.         if ( stillOK && installPatch )
  284.             Munger( myTask, 0L, &toReplace, 4, &replaceWith, 4 );
  285.  
  286.     /*    The original (Harvey) code also used Munger to force the patch to jump to
  287.      *    the original trap address after it executed.  I'm leaving that up to the
  288.      *    patch code to do by itself (if it wants to).  The original (old) trap
  289.      *    address is stored in the oldTrap field in the shared data structure.
  290.      *    
  291.      *    Now we actually patch the trap.  We've waited until now to detach and
  292.      *    lock the task (patch) code because Munger expects a movable/resizeable
  293.      *    Handle. (Actually, this is just for form. Since we replaced a pattern
  294.      *    with something the same size, there was no need to resize or move the
  295.      *    memory block, so the locked/unlocked status wasn't that important.)
  296.      */
  297.         if ( stillOK && installPatch )
  298.         {
  299.             DetachResource( myTask );
  300.             HLock( myTask );
  301.         
  302.             myTaskAddr = (UniversalProcPtr)(StripAddress( (Ptr)(*myTask) ) );
  303.             NSetTrapAddress( myTaskAddr, kTrapToPatch, ToolTrap );
  304.             
  305.             myData->patched = true;
  306.         }
  307.         else
  308.         {
  309.             myData->patched = false;
  310.         }
  311.     
  312.     /*    Store the address of our shared data structure in a resource that
  313.      *    can be accessed by our control panel.  That way, the control panel 
  314.      *    can use and change our shared data.
  315.      */
  316.         if ( stillOK )
  317.         {
  318.             addrHandle = (memAddrHdl)Get1Resource( kMemAddrType, kMemAddrID );
  319.             if ( addrHandle )    /* got the resource */
  320.             {
  321.                 (*addrHandle)->theAddr = replaceWith;    /* store value of myData */
  322.                 ChangedResource( (Handle)addrHandle );
  323.                 WriteResource( (Handle)addrHandle );    /* write rsrc back to file */
  324.             }
  325.             else    /* create a new resource */
  326.             {
  327.                 addrHandle = (memAddrHdl)NewHandleClear( sizeof( long ) );
  328.                 if ( addrHandle )
  329.                 {
  330.                     (*addrHandle)->theAddr = replaceWith;    /* store value of myData */
  331.                     AddResource( (Handle)addrHandle, kMemAddrType, kMemAddrID,
  332.                         "\pShared Memory Addr" );        /* add a rsrc to file */
  333.                     WriteResource( (Handle)addrHandle ); /* write it out to the file */
  334.                 }
  335.                 else
  336.                 {
  337.                     stillOK = false;    /* unable to allocate memory for new rsrc */
  338.                 }
  339.             }
  340.         }
  341.         
  342.     /*    If there was a problem and it looks like the trap was still patched,
  343.      *    go ahead and remove the patch (restoring the original trap address).
  344.      */
  345.      
  346.          if ( ( !stillOK ) && sharedDataOK )
  347.          {
  348.              if ( myTask )    /* if the task code was loaded, it was probably installed */
  349.              {
  350.                  NSetTrapAddress( myData->oldTrap, kTrapToPatch, ToolTrap );
  351.                  DisposeHandle( myTask );
  352.                  myTask = NULL;
  353.                  
  354.                  myData->patched = false;
  355.              }
  356.          }
  357.     
  358.     /*    Show our icon in the startup icon parade.  If there was a problem somewhere
  359.      *    along the way, we'll show the icon even if the control panel says not to.
  360.      */
  361.  
  362.         if ( showStartupIcon || ( !stillOK ) )
  363.         {
  364.             if ( stillOK )
  365.                 if ( installPatch )
  366.                     ShowIconFamily( kIconFamilyID );
  367.                 else
  368.                     ShowIconFamily( kNoPatchIconID );
  369.             else
  370.                 ShowIconFamily( kXIconID );
  371.         }
  372.  
  373.     /*    Restore the memory zone to what it was when we began. */
  374.     
  375.         SetZone( saveZone );
  376.     
  377.     /*    Mark the data structure as no longer in use - we're through with it. */
  378.     
  379.         if ( sharedDataOK )
  380.             myData->inUse = false;
  381. }
  382.  
  383. #include "ShowIconFamily.c"
  384.