Path: utzoo!utgpu!water!watmath!clyde!att!rutgers!ukma!husc6!endor!singer
From: singer@endor.harvard.edu (Rich Siegel)
Newsgroups: comp.sys.mac.programmer
Subject: Re: Heirarchical Menus and Menu Definitions
Message-ID: <4884@husc6.harvard.edu>
Date: 5 Jul 88 12:43:54 GMT
References: <5381@orstcs.CS.ORST.EDU>
Sender: news@husc6.harvard.edu
Reply-To: singer@endor.UUCP (Rich Siegel)
Organization: Symantec/THINK Technologies, Bedford, MA
Lines: 76

In article <5381@orstcs.CS.ORST.EDU> jasmerb@coil.cs.orst.edu (Bryce Roger Jasmer) writes:
>SubMenu := GetMenu(SubMenuID);
>SubMenu^^.menuProc := NewHandle(0);	
>SubMenu^^.menuProc^ := Ptr(@SubMenuProc);   {defined elsewhere}

	The above three lines of code are BAD! They are ILLEGAL, IMMORAL,
and are guaranteed to smash your heap.

	What you've done here is to define what's commonly known as a "fake"
handle; by saying

	SubMenu^^.menuProc^ := Ptr(@SubMenuProc)

you've thoroughly crushed the master pointer for that particular handle,
which will sooner or later crash the memory manager.

I have several instances in my code where I need custom definition functions.
Furthermore, it's easiest to have these in source form in my project, so
that I  can easily modify and debug them. But the above strategy is the wrong
way to do it. Instead, I declare a procedure as follows:

PROCEDURE InstallDefProc(dpType : ResType; dpID : Integer; dpAddr: : Ptr);
var
	jH : JumpHandle;

begin
	jH := JumpHandle(GetResource(dpType, dpID));
	if jH = NIL then begin
		jH := JumpHandle(NewHandle(SizeOf(JumpRec)));
		AddResource(Handle(jH), dpType, dpID, '');
	end;
	jH^^.jmpInstr := $EF9;
	jH^^.jmpAddr := Ord4(dpAddr);
	ChangedResource(Handle(jH));
	WriteResource(Handle(jH));
end;

InstallDefProc relies on the following type definition:

TYPE
	JumpRec = record
		jmpInstr : Integer;
		jmpAddr : LongInt;
	end;
	JumpPtr = ^JumpRec;
	JumpHandle = ^JumpPtr;

What InstallDefProc does is store a "dummy" definition code resource in
the application's resource file. This code resource consists of a JMP
to an absolute address. 

Now, for your menu:

menu := GetMenu(MenuID));
menu^^.menuProc := GetResource('MDEF', mdefID));

where "MenuID" and "mdefID" are constants that you supply.

Some caveats:

	1) You should call the "InstallDefProc" routine in your application's
initialization code.

	2) The pointer that you pass to InstallDefProc for the address of
your defproc should be a pointer to a routine that's in a segment that
is always loaded and locked; in other words, any defprocs you have should
be in the main code segment ("Segment 1" in a Lightspeed Pascal project)).

This whole business of bogus handles is unfortunate, ...

(Thanks to Jon Hueras for giving me tips on doing all this for myself.)

		--Rich

Rich Siegel
THINK Technologies