user.exe16: Support Windows 1.x and 2.x Menus

Martin Payne development at martinpayne.me.uk
Sun Sep 24 03:04:51 CDT 2017


Added support for Windows 1.x / 2.x menu resources to
LoadMenuIndirect16. The format of these are slightly different from
Windows 3.x menus which causes them to fail to load.

Tested on Fedora 26 x86.

Signed-off-by: Martin Payne <development at martinpayne.me.uk>
---
 dlls/krnl386.exe16/krnl386.exe16.spec |  1 +
 dlls/user.exe16/user.c                | 44 +++++++++++++++++++++++++----------
 dlls/user.exe16/user_private.h        |  1 +
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/dlls/krnl386.exe16/krnl386.exe16.spec b/dlls/krnl386.exe16/krnl386.exe16.spec
index 62d37e5e4f..0fd7e7a164 100644
--- a/dlls/krnl386.exe16/krnl386.exe16.spec
+++ b/dlls/krnl386.exe16/krnl386.exe16.spec
@@ -706,6 +706,7 @@
 @ stdcall -arch=win32 GetCurrentTask()
 @ stdcall -arch=win32 GetDOSEnvironment16()
 @ stdcall -arch=win32 GetExePtr(long)
+@ stdcall -arch=win32 GetExeVersion16()
 @ stdcall -arch=win32 GetExpWinVer16(long)
 @ stdcall -arch=win32 GetModuleHandle16(str)
 @ stdcall -arch=win32 GlobalReAlloc16(long long long)
diff --git a/dlls/user.exe16/user.c b/dlls/user.exe16/user.c
index 35f2585959..eac4a19d39 100644
--- a/dlls/user.exe16/user.c
+++ b/dlls/user.exe16/user.c
@@ -1428,7 +1428,7 @@ HMENU16 WINAPI LookupMenuHandle16( HMENU16 hmenu, INT16 id )
 }
 
 
-static LPCSTR parse_menu_resource( LPCSTR res, HMENU hMenu )
+static LPCSTR parse_menu_resource( LPCSTR res, HMENU hMenu, BOOL oldFormat )
 {
     WORD flags, id = 0;
     LPCSTR str;
@@ -1436,11 +1436,21 @@ static LPCSTR parse_menu_resource( LPCSTR res, HMENU hMenu )
 
     do
     {
-        flags = GET_WORD(res);
+        /* Windows 3.00 and later use a WORD for the flags, whereas 1.x and 2.x use a BYTE. */
+        if (oldFormat)
+        {
+            flags = GET_BYTE(res);
+            res += sizeof(BYTE);
+        }
+        else
+        {
+            flags = GET_WORD(res);
+            res += sizeof(WORD);
+        }
+
         end_flag = flags & MF_END;
         /* Remove MF_END because it has the same value as MF_HILITE */
         flags &= ~MF_END;
-        res += sizeof(WORD);
         if (!(flags & MF_POPUP))
         {
             id = GET_WORD(res);
@@ -1452,7 +1462,7 @@ static LPCSTR parse_menu_resource( LPCSTR res, HMENU hMenu )
         {
             HMENU hSubMenu = CreatePopupMenu();
             if (!hSubMenu) return NULL;
-            if (!(res = parse_menu_resource( res, hSubMenu ))) return NULL;
+            if (!(res = parse_menu_resource( res, hSubMenu, oldFormat ))) return NULL;
             AppendMenuA( hMenu, flags, (UINT_PTR)hSubMenu, str );
         }
         else  /* Not a popup */
@@ -1468,22 +1478,32 @@ static LPCSTR parse_menu_resource( LPCSTR res, HMENU hMenu )
  */
 HMENU16 WINAPI LoadMenuIndirect16( LPCVOID template )
 {
+    BOOL oldFormat;
     HMENU hMenu;
     WORD version, offset;
     LPCSTR p = template;
 
     TRACE("(%p)\n", template );
-    version = GET_WORD(p);
-    p += sizeof(WORD);
-    if (version)
+
+    /* Windows 1.x and 2.x menus have a slightly different menu format from 3.x menus */
+    oldFormat = (GetExeVersion16() < 0x0300);
+
+    /* Windows 3.00 and later menu items are preceded by a MENUITEMTEMPLATEHEADER structure */
+    if (!oldFormat)
     {
-        WARN("version must be 0 for Win16\n" );
-        return 0;
+        version = GET_WORD(p);
+        p += sizeof(WORD);
+        if (version)
+        {
+            WARN("version must be 0 for Win16 >= 3.00 applications\n" );
+            return 0;
+        }
+        offset = GET_WORD(p);
+        p += sizeof(WORD) + offset;
     }
-    offset = GET_WORD(p);
-    p += sizeof(WORD) + offset;
+
     if (!(hMenu = CreateMenu())) return 0;
-    if (!parse_menu_resource( p, hMenu ))
+    if (!parse_menu_resource( p, hMenu, oldFormat ))
     {
         DestroyMenu( hMenu );
         return 0;
diff --git a/dlls/user.exe16/user_private.h b/dlls/user.exe16/user_private.h
index 7c91afb2ce..336b89102d 100644
--- a/dlls/user.exe16/user_private.h
+++ b/dlls/user.exe16/user_private.h
@@ -95,6 +95,7 @@ extern LRESULT WINPROC_CallProc32ATo16( winproc_callback16_t callback, HWND hwnd
 
 extern void call_WH_CALLWNDPROC_hook( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp ) DECLSPEC_HIDDEN;
 
+#define GET_BYTE(ptr)  (*(const BYTE *)(ptr))
 #define GET_WORD(ptr)  (*(const WORD *)(ptr))
 #define GET_DWORD(ptr) (*(const DWORD *)(ptr))
 
-- 
2.14.1.windows.1




More information about the wine-patches mailing list