[comp.sys.mac.programmer] patching globally after MF

gurgle@well.sf.ca.us (Pete Gontier) (09/22/90)

I need to monitor NewWindow.
 
MultiFinder seems to be patching NewWindow and *replacing* it. Thus, a patch I
install at INIT time never gets called.
 
A patch to NewWindow I install at the time of the first GetNextEvent affects
only the Finder (or the startup application) even if my patch code lives in
the System Heap.
 
I patched OpenResFile and waited for something other than MultiFinder to be
opened. But by that time, MF has monkeyed with SetTrapAddress enough that the
trap dispatcher gets confused and blows up.
 
Anybody got any secrets about patching after MultiFinder?
-- 
 Pete Gontier, gurgle@well.sf.ca.us
 Software Imagineer, Kiwi Software, Inc.

jwhitnell@cup.portal.com (Jerry D Whitnell) (09/24/90)

 Pete Gontier, gurgle@well.sf.ca.us writes...
|A patch to NewWindow I install at the time of the first GetNextEvent affects
|only the Finder (or the startup application) even if my patch code lives in
|the System Heap.
|Anybody got any secrets about patching after MultiFinder?

I havn't tried it, so I'd like to know what you find.  However I'd think
OpenResFile may be too early in the process that MultiFinder goes through
to launch tasks.  Try looking for one of the Init* that everyone has
to call at the beginning of their program (InitGraf, InitWindow, ad nasum)
for one that is not patched by MF, and patch it to patch NewWindow.  Since
everyone has to call them, your patch code will get control early on in the
application.  Let me know what you find.

Jerry Whitnell
SuperMac Technology
jwhitnell@cup.portal.com

ericsc@microsoft.UUCP (Eric SCHLEGEL) (09/24/90)

In article <20695@well.sf.ca.us> gurgle@well.sf.ca.us (Pete Gontier) writes:
>I need to monitor NewWindow.
> 
>MultiFinder seems to be patching NewWindow and *replacing* it. Thus, a patch I
>install at INIT time never gets called.
> 
>A patch to NewWindow I install at the time of the first GetNextEvent affects
>only the Finder (or the startup application) even if my patch code lives in
>the System Heap.
> 
>I patched OpenResFile and waited for something other than MultiFinder to be
>opened. But by that time, MF has monkeyed with SetTrapAddress enough that the
>trap dispatcher gets confused and blows up.
> 
>Anybody got any secrets about patching after MultiFinder?

I had the same problem, except I needed to patch _MoveWindow. My solution was
to patch _InitDialogs, which is not patched out by MF. My _InitDialogs patch
then installs the _MoveWindow patch.

I assume you know, also, that MultiFinder removes any traps that installed
while an application is running when that application quits or is switched out.
So you need to reinstall your _NewWindow patch whenever a new applicaton is
launched.

But wait, there's more! You'll need to keep around the original address of 
_NewWindow for each running application, so that your _NewWindow patch can
jump to the real _NewWindow. The method I originally used to do this was
to create a 0 height, 0 width invisible window in my _InitDialogs patch,
and store the original _MoveWindow address in the refCon of that window. Then
in my _MoveWindow patch I searched the windowList for a window with my
special name and grabbed the refCon. I also set the windowKind of the window
to 0, hoping that this would keep apps from getting confused. Finally, I named
the window "MyWindow :/\-[.". The reason I used all the strange characters is
because it's possible for the Finder to create a window named "MyWindow". When
this happened, my _MoveWindow patch got confused. But the Finder can never
create a window with the ":" character in its name because that character is
used to separate directory names. I threw in the other strange characters
because most of them are used by some operating system that the Macintosh
does or might work with to separate directory names.

Remember, though, that the user might not be running MultiFinder. In that
case creating a dummy window is a bad idea, because the window will be
destroyed after the first running application quits, but your patch will
remain. So if MultiFinder is not running, my _InitDialogs patch doesn't create
a dummy window. Instead it stuffs the address of _MoveWindow into a global
variable in the same heap block as the _MoveWindow patch, so that the patch
can access the address.

I check for the existence of _OSDispatch (the temporary memory trap) to see
if MultiFinder is running. I sent mail to DTS asking if they could recommend
a way to check for the "specific functionality" of the trap table being 
reinitialized when an application quits, but they said "We don't know, and
we're not going to spend lots of time trying to find out because you're not
a certified developer, so if it works for you, do what you want."

This scheme actually does work, too. Unfortunately, it breaks Disinfectant 2.1;
as near as I can tell from looking at Disinfectant's code in MacsBug, it's 
looping through the windowlist and assuming that any window with a non-negative
windowKind belongs to Disinfectant. My window's windowKind is 0, so 
Disinfectant breaks.

I now have a new idea which I haven't yet implemented. I'm going to patch
_ErrorSound, which is an obscure trap in the Dialog Manager used to set
a procedure that's called by the Dialog Manager to produce a sound when the
user clicks outside of a dialog. _ErrorSound takes a ProcPtr. My patch will
check if the ProcPtr points at a special string identifying my INIT. If it
does, my patch will stuff a handle to a block of globals into the memory
pointed at by the ProcPtr and return immediately, without calling the real
_ErrorSound. I think this will work and not break anyone.

Finally, my _InitDialogs patch has to be careful about who is calling it.
_InitDialogs can be called by INITs that need to put up a dialog. If that's
the case, I don't want my _InitDialogs patch to install the _MoveWindow patch.
So when my INIT runs, it clears the first word of the low-mem global CurApName.
CurApName isn't changed until the first application runs. My _InitDialogs patch
can therefore check to see if the first work of CurApName is still zero. If
it is, _InitDialogs is being called by an INIT, and my patch proceeds directly
to the real _InitDialogs.

So there's my story. It's a mess, but it works. Anyone got any better ideas?

-eric

mneerach@iiic.ethz.ch (Matthias Ulrich Neeracher) (09/27/90)

In article <34224@cup.portal.com> jwhitnell@cup.portal.com (Jerry D Whitnell) writes:
> Pete Gontier, gurgle@well.sf.ca.us writes...
>|A patch to NewWindow I install at the time of the first GetNextEvent affects
>|only the Finder (or the startup application) even if my patch code lives in
>|the System Heap.
>|Anybody got any secrets about patching after MultiFinder?
>
>  Try looking for one of the Init* that everyone has
>to call at the beginning of their program (InitGraf, InitWindow, ad nasum)
>for one that is not patched by MF, and patch it to patch NewWindow. 

In my experience, InitGraf works fine but you have to be *extremely* careful
not to install your patch twice. This can be quite tricky, especially under
Finder. You also have to think about removing your patch again.

Matthias

-----
Matthias Neeracher                                   mneerach@iiic.ethz.ch
   "These days, though, you have to be pretty technical before you can 
    even aspire to crudeness." -- William Gibson, _Johnny Mnemonic_

beard@ux5.lbl.gov (Patrick C Beard) (09/28/90)

In article <20695@well.sf.ca.us> gurgle@well.sf.ca.us (Pete Gontier) writes:
#I need to monitor NewWindow.
# 
#MultiFinder seems to be patching NewWindow and *replacing* it. Thus, a patch I
#install at INIT time never gets called.
# 
#A patch to NewWindow I install at the time of the first GetNextEvent affects
#only the Finder (or the startup application) even if my patch code lives in
#the System Heap.
# 
#I patched OpenResFile and waited for something other than MultiFinder to be
#opened. But by that time, MF has monkeyed with SetTrapAddress enough that the
#trap dispatcher gets confused and blows up.
# 
#Anybody got any secrets about patching after MultiFinder?

1.  In your INIT, get the address of SetTrapAddress.
2.  Patch InitGraf, or some other trap that all app's use.
3.  When MF runs Finder, apply your other patches with the REAL SetTrapAddress
that you've saved.  This will bypass the SetTrapAddress MF installs.

This works, I've tried it, although I can't guarantee that it is safe.  I just
know I've tried it.

Good luck!

--
-------------------------------------------------------------------------------
-  Patrick Beard, Macintosh Programmer                        (beard@lbl.gov) -
-  Berkeley Systems, Inc.  ".......<dead air>.......Good day!" - Paul Harvey  -
-------------------------------------------------------------------------------