menu fix

Andreas Mohr andi at rhlx01.fht-esslingen.de
Fri Sep 6 16:16:26 CDT 2002


Hi all,

my previous menu patch ("Make sure we clear the owning window's hMenu
in DestroyMenu().") caused problems with certain apps.
That's because DestroyMenu set the hMenu member of the hWnd that the
hMenu had been assigned to to 0.
Since a SetMenu changed the hMenu of a hWnd to a new hMenu
without removing the link from the old hMenu to its thus old hWnd,
the *new* hMenu handle registered in the hWnd got erased as soon as
we did a DestroyMenu on the *old* hMenu not affiliated with the hWnd any
more.

- make sure we set old hMenu's hWnd pointer to 0 when doing a SetMenu
- added a small menu conformance test

(dlls/user/tests/menu.c)

Note that this is only a workaround for the bigger issue:
a pending rewrite of the menu handling to really cope with the changes
from Win 3.x to Win9x (which affect DestroyMenu, SetMenu etc.).

-- 
Andreas Mohr                        Stauferstr. 6, D-71272 Renningen, Germany
-------------- next part --------------
Determining best CVS host...
Using CVSROOT :pserver:cvs at rhlx01.fht-esslingen.de:/home/wine
Index: controls/menu.c
===================================================================
RCS file: /home/wine/wine/controls/menu.c,v
retrieving revision 1.146
diff -u -r1.146 menu.c
--- controls/menu.c	28 Aug 2002 23:31:56 -0000	1.146
+++ controls/menu.c	6 Sep 2002 21:04:27 -0000
@@ -24,6 +24,14 @@
  * Note: the style MF_MOUSESELECT is used to mark popup items that
  * have been selected, i.e. their popup menu is currently displayed.
  * This is probably not the meaning this style has in MS-Windows.
+ *
+ * TODO
+ * - Win9x has menu changes compared to Win 3.x:
+ *   DestroyMenu() doesn't unregister hMenu in owning hWnd in Win3.x,
+ *   whereas Win9x does it (and many other menu handling changes
+ *   in this respect). Roughly spoken, the current DestroyMenu, GetMenu
+ *   code is nothing more than a bad hack designed to make as many
+ *   programs work with the current code as possible.
  */
 
 #include "config.h"
@@ -3844,8 +3852,13 @@
 
         if (!lppop) return FALSE;
 
-	/* unregister menu in owning window */
-	SetWindowLongA( lppop->hWnd, GWL_ID, 0 );
+	/* unregister menu in owning window.
+	 * Note that this is problematic, since a hMenu can be assigned
+	 * to several hWnd. Thus you can't keep track of all hWnd a menu
+	 * is assigned to. FIXME: Win9x menu handling rewrite. */
+	if (lppop->hWnd)
+	    SetWindowLongA( lppop->hWnd, GWL_ID, 0 );
+
 
         lppop->wMagic = 0;  /* Mark it as destroyed */
 
@@ -3950,6 +3963,15 @@
 HMENU WINAPI GetMenu( HWND hWnd )
 {
     HMENU retvalue = (HMENU)GetWindowLongA( hWnd, GWL_ID );
+    /* need to check whether HMENU is still valid,
+     * since DestroyMenu doesn't zero hMenu of a HWND's struct
+     * (as a HMENU can be assigned to *several* HWNDs,
+     * there's no way of finding all HWNDs to zero out their hMenu !)
+     * FIXME: Win9x menu handling rewrite.
+     */
+    if (!MENU_GetMenu(retvalue))
+        retvalue = 0;
+
     TRACE("for %04x returning %04x\n", hWnd, retvalue);
     return retvalue;
 }
@@ -3960,6 +3982,7 @@
  */
 BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu )
 {
+    HMENU hMenuOld;
     TRACE("(%04x, %04x);\n", hWnd, hMenu);
 
     if (hMenu && !IsMenu(hMenu))
@@ -3970,8 +3993,25 @@
     if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
 
     hWnd = WIN_GetFullHandle( hWnd );
+
+    hMenuOld = (HMENU)GetWindowLongA( hWnd, GWL_ID);
+
+    /* bail out if no change */
+    if (hMenuOld == hMenu)
+        return TRUE;
+
     if (GetCapture() == hWnd) ReleaseCapture();
 
+    if (hMenuOld)
+    {
+        LPPOPUPMENU lpmenu;
+
+        if (!(lpmenu = MENU_GetMenu(hMenuOld))) return FALSE;
+
+        /* set hWnd of old hMenu to 0, since we're unregistering it */
+        lpmenu->hWnd = 0;
+    }
+
     if (hMenu != 0)
     {
         LPPOPUPMENU lpmenu;
@@ -3981,6 +4021,8 @@
         lpmenu->hWnd = hWnd;
         lpmenu->Height = 0;  /* Make sure we recalculate the size */
     }
+
+    /* register new hMenu in the window */
     SetWindowLongA( hWnd, GWL_ID, hMenu );
 
     if (IsWindowVisible(hWnd))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: menu.c
Type: text/x-csrc
Size: 3649 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-patches/attachments/20020906/fee08c97/menu.c


More information about the wine-patches mailing list