Getting the File List's ListHandle from within CustomGetFile

If I'm in my Dialog hook function, called by CustomGetFile, how can I get the ListHandle for the File list that the Toolbox makes?  I need to be able to see & change which items are selected.
dhirschAsked:
Who is Participating?
 
Paul BConnect With a Mentor Commented:
Hi,
  Getting this to work is extreamly complicated. But it can be done :)
First the bad news:
The patch itself MUST be in 68K code. The reason for this is that the List Manager uses a pascal dispatched routine selector with a different number of params for each selector.
This makes creating a Universal Proc Pointer to the patch nearly impossible.

If you need this to work for PPC there are work arounds such as having your App in PPC and have the code that patches in a seperate resource compiled for 68K and installing a gestalt or something.
For the sake of time I'll only do that if you need it.
If you do neesd PPC email me and I will send you code for PPC. This will require a little more time.
My email adrress is pbaxter@assistivetech.com

The code is in three functions
PatchLNew    -- installs the patch. Call this right before your call to CustomGetFile
UnPatchLNew  -- removes the patch. Call this right after your call to CustomGetFile
LNewPatch    -- the patch itself --- very scary code

The code needs two global variables
gOldLNew     -- original trap address
gMyListhande -- The list handle that you want;

Here now the patch from hell:

#include <Traps.h>

void PatchLNew(void);
void UnPatchLNew(void);
asm void LNewPatch(void);

#if !GENERATINGPOWERPC
typedef pascal ListRef (*LNewProcPtr) (
      const Rect *rView,
      const ListBounds *dataBounds,
      Point cSize,
      short theProc,
      WindowRef theWindow,
      Boolean drawIt,
      Boolean hasGrow,
      Boolean scrollHoriz,
      Boolean scrollVert);

typedef  LNewProcPtr LNewUPP;

enum {
      uppLNewProcInfo = 0
};

#define NewLNewProc(proc) (LNewUPP)(proc)
#define CallLNewProc(proc, p1, p2, p3, p4, p5, p6, p7, p8, p9)      \
            (* (LNewProcPtr) (proc))(p1, p2, p3, p4, p5, p6, p7, p8, p9)

#else
      #error      only for 68K
#endif

LNewUPP gOldLNew=0;
ListHandle gMyListhande = nil;

void PatchLNew(void)
{
      short trap = _Pack0;
      
      gOldLNew = (LNewUPP)
                  NGetTrapAddress(trap, (trap & 0x0800) ? ToolTrap : OSTrap);

      NSetTrapAddress((UniversalProcPtr) LNewPatch,
                  trap, (trap & 0x0800) ? ToolTrap : OSTrap);

}

void UnPatchLNew(void)
{
      short trap = _Pack0;

      NSetTrapAddress((UniversalProcPtr) gOldLNew,
                  trap, (trap & 0x0800) ? ToolTrap : OSTrap);
      
}

asm void LNewPatch(void)
{
                  bra.s      start

saveA5:            dc.l      0
oldreturn:      dc.l      0
dispatch:      dc.w      0
start:

                  lea            saveA5, a0            // access to globals
                  move.l      a5,(a0)

                  lea            dispatch, a0      // routine selector
                  move.w      4(sp),(a0)
                  move.l      0x0904, a5            // SetCurentA5

                  move.l      gOldLNew, a0      // old trap address
                  lea            dispatch, a1      // get routine selector
                  cmpi.w      #68, (a1)            // LNew selector

                  beq.s      lnewdispatch      // see if we need to steal the result
                  move.l      saveA5,a5            // restore A5
                  jmp            (a0)                  // jump to old address

lnewdispatch:
                  lea            oldreturn,a1      // save return address
                  move.l      (sp),(a1)            

                  lea       restoreA5, a1      // where we want to return to
                  move.l      a1, (sp)            // put6 on stack
                  jmp            (a0)                  // jump to old code
restoreA5:
                  move.l      (sp), gMyListhande      // SAVE THE LIST HANDLE!!!!
                  move.l      saveA5,a5            // restore A5
                  move.l      oldreturn,a1      // get the old return address
                  jmp            (a1)                  // jump!!!
}                  

Paul B
pbaxter@assistivetech.com


0
 
Paul BCommented:
Hi,
  Are you apposed to using a patch :/
If you are not I can give you an answer and code example.

Paul B
0
 
dhirschAuthor Commented:
Paul-
  A patch is fine.  I know there's no easy way to get at it, because I've tried all the easy ways.
-Dave
0
 
dhirschAuthor Commented:
This looks like what I needed.  I'll email you to discuss PPC implementation, which, sadly, I do need.
0
 
Paul BCommented:
Hi,
Here is how it is done for PPC with Sample Code.

First the patch should be compiled with 68K and to generate a code resource of type 'patc' with id 0.
Add this resource to your PPC target.

Then main code then calls the patc resource using the Mixed Mode Mgr.

Here is the patch code:
/* File patch.c */
#include <Traps.h>
#include <Gestalt.h>
#include <A4Stuff.h>

#include "patch.h"

asm void LNewPatch(void);
static void PatchLNew(void);
static void UnPatchLNew(void);

static void InstallGlobals(void);
pascal void main(short remove, ListHandle* listaddres);

#if !GENERATINGPOWERPC
typedef pascal ListRef (*LNewProcPtr) (
      const Rect *rView,
      const ListBounds *dataBounds,
      Point cSize,
      short theProc,
      WindowRef theWindow,
      Boolean drawIt,
      Boolean hasGrow,
      Boolean scrollHoriz,
      Boolean scrollVert);

typedef  LNewProcPtr LNewUPP;

enum {
      uppLNewProcInfo = 0
};

#define NewLNewProc(proc) (LNewUPP)(proc)
#define CallLNewProc(proc, p1, p2, p3, p4, p5, p6, p7, p8, p9)      \
            (* (LNewProcPtr) (proc))(p1, p2, p3, p4, p5, p6, p7, p8, p9)

#else
      #error      only for 68K
#endif

LNewUPP gOldLNew=0;
ListHandle *gMyListHandlePtr = nil;


pascal void main(short remove, ListHandle* listaddres)
{
      long oldA4;
      Boolean installfailed;

      oldA4 = SetCurrentA4();

      if (remove) {
            UnPatchLNew();
      }
      else {
            gMyListHandlePtr = listaddres;
            PatchLNew();
            InstallGlobals();      // must be after patch installed!
      }
      SetA4(oldA4);
}

static void PatchLNew(void)
{
      short trap = _Pack0;
      
      gOldLNew = (LNewUPP)
                  NGetTrapAddress(trap, (trap & 0x0800) ? ToolTrap : OSTrap);

      NSetTrapAddress((UniversalProcPtr) LNewPatch,
                  trap, (trap & 0x0800) ? ToolTrap : OSTrap);

}

static void UnPatchLNew(void)
{
      short trap = _Pack0;

      NSetTrapAddress((UniversalProcPtr) gOldLNew,
                  trap, (trap & 0x0800) ? ToolTrap : OSTrap);
      
}



asm void LNewPatch(void)
{
                        bra.s      start

                        entry      static InstallGlobals
InstallGlobals:
                        lea            lstHandAddr, a0
                        move.l      gMyListHandlePtr, (a0)
                        lea            oldAddress, a0
                        move.l      gOldLNew, (a0)
                        rts

lstHandAddr:      dc.l      0
oldAddress:            dc.l      0
oldreturn:            dc.l      0

start:
                        cmpi.w      #68, 4(sp)            // LNew selector
                        beq            DoLNew

                        move.l      oldAddress,a0
                        jmp            (a0)                  // jump to old code

DoLNew:
                        lea            oldreturn,a0      // save return address
                        move.l      (sp),(a0)            

                        lea       Continue, a0      // where we want to return to
                        move.l      a0, (sp)            // put on stack

                        move.l      oldAddress,a0
                        jmp            (a0)                  // jump to old code

Continue:
                        move.l      lstHandAddr,a0
                        move.l      (sp),(a0)

                        move.l      oldreturn,a0      // get the old return address
                        jmp            (a0)                  // jump!!!
}

/* File patch.h */
enum {
      kInstall = 0,
      kRemove = 1
};

Here is the main for PPC
/* File main.c */

#include <StandardFile.h>
#include "patch.h"

void main(void);
void inittoolbox(void);

ListHandle gMyListHandle = nil;
long lasttime = 0;

pascal Boolean HookProc(short itemHit, DialogPtr theDialog, void* data);

enum {
      uppPatchProcInfo = kPascalStackBased
             | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short)))
             | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(ListHandle*)))
};
      
void main(void)
{
      UniversalProcPtr patchCode;
      DlgHookYDUPP dlgHook;
      Handle patchResource;
      StandardFileReply reply;
      long responce;
      OSErr err = noErr;
      Point where;

      inittoolbox();

      patchResource = GetResource('patc', 0);
      if (patchResource) {
            HLock(patchResource);
            HNoPurge(patchResource);
            patchCode = NewRoutineDescriptor((ProcPtr)*patchResource, uppPatchProcInfo,  kM68kISA);
            CallUniversalProc(patchCode, uppPatchProcInfo, kInstall, &gMyListHandle);

            where.h = where.v = -1;

            dlgHook =  NewDlgHookYDProc(HookProc);

            gMyListHandle = nil;
            CustomGetFile(nil, -1, nil, &reply, 0, where, dlgHook, nil, nil, nil, nil);
            gMyListHandle = nil;

            CallUniversalProc(patchCode, uppPatchProcInfo, kRemove, &gMyListHandle);
            DisposeRoutineDescriptor(patchCode);
            
      }
      else {
            SysBeep(1);
      }
}

pascal Boolean HookProc(short itemHit, DialogPtr theDialog, void* data)
{
      Cell thecell, nextcell;
      Boolean result;

      if (gMyListHandle) {
            if (TickCount() - lasttime > 30) {
                  if ((itemHit == 100)) {
                        thecell.h = thecell.v = 0;
                        result = LGetSelect(true, &thecell, gMyListHandle);
                        if (result) {
                              nextcell = thecell;
                              result = LNextCell(false, true, &nextcell, gMyListHandle);
                              LSetSelect(false, thecell, gMyListHandle);
                              LSetSelect(true, nextcell, gMyListHandle);
                        }
                        else {
                              LSetSelect(false, thecell, gMyListHandle);
                              thecell.h = thecell.v = 0;
                              LSetSelect(true, thecell, gMyListHandle);
                        }
                        LAutoScroll(gMyListHandle);
                  }
                  lasttime = TickCount();
            }
      }
      if ((itemHit == ok) || (itemHit == cancel))
            return true;
      return false;
}

void inittoolbox(void)
{
      InitGraf(&qd.thePort);
      FlushEvents ( everyEvent, 0);
      InitFonts();
      InitWindows();
      InitMenus();
      TEInit();
      InitDialogs(nil);
      InitCursor();
}



0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.