Solved

Getting the File List's ListHandle from within CustomGetFile

Posted on 1997-07-08
5
195 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
  • 3
  • 2
5 Comments
 
LVL 1

Expert Comment

by:Paul B
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Perl Awk Need Help 3 94
has22 challenge 11 70
zeroFront challenge 7 70
Updating statistics with error notification email in SQL server 4 44
Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
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.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

763 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now