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