[comp.sys.mac.programmer] Heirarchical Menus and Menu Definitions

jasmerb@coil.cs.orst.edu (Bryce Roger Jasmer) (07/05/88)

I am having serious trouble getting my own menu definition working in a 
submenu. The menu definition will work all by itself when it is regular
menu in the menubar, and the heirarchical menu works just fine with a
standard menu attached as a submenu, but when the two are combined they
won't work.

I am using LSP and here is some of the code to create the menu:

TopLevelMenu := GetMenu(TopLevelMenuID);  
tempString := ConCat(chr(hMenuCmd), chr(SubMenuID), 'SubMenu');
AppendMenu(TopLevelMenu, tempString);	
InsertMenu(TopLevelMenu, 0);

SubMenu := GetMenu(SubMenuID);
SubMenu^^.menuProc := NewHandle(0);	
SubMenu^^.menuProc^ := Ptr(@SubMenuProc);   {defined elsewhere}
InsertMenu(SubMenu, -1);
CalcMenuSize(SubMenu);

-------

I will click in the TopLevelMenu and drag down to the 'SubMenu' item,
the Mac then draws the empty box that the my submenu will draw in, and
then crashes at the "MenuSelect(theEvent.where)" function call.

I would compile the menu definition into a MDEF resource but the menu
definition needs to have access to some global data.

Please send e-mail, I am desperate! I will summarize if the solution
comes my way. Thank you VERY much.

Bryce Jasmer
jasmerb@coil.cs.orst.edu

singer@endor.harvard.edu (Rich Siegel) (07/05/88)

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

darin@Apple.COM (Darin Adler) (07/05/88)

In article <4884@husc6.harvard.edu> singer@endor.UUCP (Rich Siegel) writes:
> 	jH^^.jmpInstr := $EF9;

Watch out for typos! This should have been:

	jH^^.jmpInstr := $4EF9;
Darin Adler					       AppleLink: Adler4
UUCP: {sun,voder,nsc,mtxinu,dual}!apple!darin	  CSNET: darin@Apple.com