[net.micro.mac] DA/Finder Menu Bug

sakw@cvaxa.UUCP (06/13/86)

> to: PAUL RUSSELL
> What's the workaround for the DA/Finder menu bug? .....

Paul replies:
------------
Problem with DA's, GetMenu and Finder 5.x
-----------------------------------------
 
While working on a DA some time ago I found that it kept crashing
when running under Finder 5.1. After some detective work with TMON
I discovered that the crash occurred when a call was made to GetMenu
(_GetRMenu in assembly language) when the menu was already in memory.
This happens when you deactivate and then activate an open DA - it has
to remove its menu from the menu bar when it is deactivated and then
replace it when it is activated again. My suspicions were confirmed
in the April 1986 MacTutor ('Finder 5.0 and up bug', p68).
 
The desk accessory example supplied with TML Pascal is a good example.
It will work OK under just about any application but crashes under
Finder 5.0/5.1/5.2. Here is how to get round the problem in general:
 
 
*               Call GetMenu only once when your DA is opened
 
 
*       either: Save the handle to the menu in your DA globals
                for later use
 
        or:     Use LoadResource to get a handle to the menu whenever
                you need it
 
 
*               Use ReleaseResource to dispose of the menu when the DA
                is closed
 
 
Here is one way in which the TML Pascal example DA can be modified to
work properly under Finder 5.x, it is not necessarily the 'best' way
and has not been rigorously tested:
 
First of all the Open routine - this has a new variable:
 
        menuH:MenuHandle;
 
the resourceID of the DA's menu (and other possible resources) is
calculated when the DA is first opened as usual:
 
        ResourceID := $BFE0 + 32 * (-Device.DCtlRefNum);
 
and then the DCtlMenu field of the DCE is set equal to this ID:
 
        Device.DCtlMenu := ResourceID;
 
this is followed by our one and only call to GetMenu to read the
menu resource into memory (note: this does not draw the menu, it only
reads it into memory, drawing is handled automatically by ActivateDA):
 
        menuH:=GetMenu(Device.DCtlMenu);
 
That is all we need to do in the Open routine, the local variable menuH
is not used again.
 
Instead of GetMenu we define a new function GetMenuH for use by parts of
the program other than Open which require a handle to our menu:
 
        FUNCTION GetMenuH(resourceID:INTEGER):MenuHandle;
 
        begin
        GetMenuH:=MenuHandle(GetResource('MENU',resourceID))
        end; { GetMenuH }
 
Hence ActivateDA becomes:
 
        PROCEDURE ActivateDA(VAR Device: DCtlEntry);
 
        var   menuH:menuHandle;
 
        begin
        menuH := GetMenuH(Device.DCtlMenu);
        menuH^^.menuID := Device.DCtlMenu; { patch menu resource ID }
        InsertMenu(menuH,0);
        DrawMenuBar
        end; { of ActivateDA }
 
DeactivateDA is unchanged.
 
When the DA is closed we use the following code to get rid of our MENU
resource:
 
        DeactivateDA(Device); { remove menu from menu bar }
        ReleaseResource(Handle(GetMenuH(Device.DCtlMenu))); { dispose of menu re
source
}
 
That is all - the DA's code will be about 50 bytes bigger but it shouldn't
crash under Finder 5.x any more.
 
Incidentally it is worth noting that the resource file provided with the
TML Pascal DA example has all its resources un-purgeable. While the
MENU resource MUST be un-purgeable (don't ask me why - see Inside Mac)
the DRVR, DLOG and DITL resources really ought to be purgeable so that
the application can reclaim all the memory used by the DA.
 
Paul Russell
12th June 1986
-- 
Sak Wathanasin, U of Sussex, Cognitive Studies, Falmer, Sussex BN1 9QN, UK
uucp:  ...mcvax!ukc!cvaxa!sakw
arpa:  sakw%cvaxa.sussex.ac.uk@ucl.cs.ac.uk
janet: sakw@uk.ac.sussex.cvaxa