[futurebasic] Re: Two questions for MacOS gurus.

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : February 1998 : Group Archive : Group : All Groups

From: Mars Saxman <marssaxman@...>
Date: Sun, 1 Feb 98 15:08:37 -0800
Mark Goodes said:
>1.  I'd like to be able to get the window list for the current frontmost
>application from a code resource, and even better, for any application that
>is running (I think the Toolbox keeps a separate window list for each
>application).

This is a very hard problem. The window list is a linked list of window 
records. The address of the first record (the head of the list) is stored 
in the low memory global WindowList which lives at &09D6. This is the 
value FrontWindow returns (unless FrontWindow has been patched).

The problem exists because the Process Manager does an excellent job at 
switching between applications. It maintains a list of low-memory-global 
blocks, one for each application. Whenever you switch between 
applications, it copies the low memory globals in for that application.

So the only way to directly track down another application's globals is 
to disassemble the process manager and figure out how to look through its 
table of blocks - not something I would suggest attempting!

However, you can also find the value you want indirectly, by waiting for 
it with a jGNEFilter.

The jGNEFilter is one of the low memory globals that does *not* get 
swapped out between applications. Although it is commonly used to install 
event filters from extensions, there's no reason you can't patch it from 
an application.

The scheme runs like this: each trip through the event loop, your 
function calls GetCurrentProcess and GetFrontProcess, then compares them 
with SameProcess. If the values match, the function can grab the 
WindowList global. Since the front process is current, its window list 
will be active.

I did something much like this for an application several years ago, but 
it was the menu bar I was concerned with rather than the window list. The 
principle will still work, but there are some things to watch out for.

1) If your app crashes, it will take the whole system down with it, since 
you will have no time to unload the jGNEFilter.

2) If you install a jGNEFilter, then someone else installs one after you, 
uninstalling your filter will effectively cut off the rest.

The solution? Don't actually install your routine as the jGNEFilter. 
Instead, write a short machine languge function that does this:

push savedAppProcessNumber
_GetNextProcess
test result
if no error
  load savedFunctionAddress
  jsr(a0)
end if
load savedNextJNEAddress
jmp(A0)

To install this, create a new block in the system heap with NewSysPtr. 
Blockmove this function into that block. Poke in the values for the 
process serial number, the function address, and the old jGNEFilter value 
at the appropriate points in the code. Install the block as the 
jGNEFilter. Forget about it.

Every time it's called, this function will check to see if your 
application is still alive. If so, it will call the function address 
given. If not, it won't call. So if your app crashes, it doesn't bring 
down the system, and it never has to unload the stub function so the jGNE 
chain is not damaged.

Conclusion: It's possible, but not easy. You'll have to be fairly 
familiar with assembly language and willing to do a lot of MacsBug 
stepping.

>2.  I'd like to be able to register with the Gestalt function as described
>in "Ultimate Mac Programming", p. 266, by Dave Mark.
[snip]
>As far as I can tell, one would do this:
>      ENTERPROC%(selector%,result&)
>          do stuff
>      EXITPROC%=result&
>Trouble is, I don't know what to do with the OsErr% value.  Even worse,
>this wil take place in an INIT, so I'd like to cloak this in a local
>function to prevent it from being automatically executed.  Is this
>possible?  Feel free to respond with inline assembler.

The osErr% value is what you return as the ExitProc% value. It is the 
function's return value.

The result& is what is called a "reference parameter". The system doesn't 
give you the value - it gives you the _location_ of the value. So your 
result& variable in the example will contain the address of the actual 
result& variable.

To return a value, poke a long into the variable pointed at by result&. 
To return an error, pass it to EXITPROC%.

To keep an enterproc from being automatically executed, skip around it 
with GOTO:

GOTO "endofenterproc"
ENTERPROC%(selector, resultPtr&)
  ...
  & resultPtr&, result&
EXITPROC%=error%
"endofenterproc"

This is basically all FB does to keep a local function from executing, 
anyway.

-Mars

mars@... * www.redplanetsw.com