Solved

Getting the File List's ListHandle from within CustomGetFile

Posted on 1997-07-08
5
235 Views
Last Modified: 2013-12-26
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.
0
Comment
Question by:dhirsch
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 
LVL 1

Expert Comment

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

Paul B
0
 

Author Comment

by:dhirsch
ID: 1291536
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
 
LVL 1

Accepted Solution

by:
Paul B earned 150 total points
ID: 1291537
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
 

Author Comment

by:dhirsch
ID: 1291538
This looks like what I needed.  I'll email you to discuss PPC implementation, which, sadly, I do need.
0
 
LVL 1

Expert Comment

by:Paul B
ID: 1291539
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

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Is it possible to combine several text files into one big one? (redhat v5 enterprise) 4 110
viewing source code from eclipse 13 110
Fibonacci challenge 11 138
mapAB Challlenge 35 174
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question