Partial MDI rewrite

Dmitry Timoshkov dmitry at baikal.ru
Thu Jan 15 09:26:54 CST 2004


Hello all,

here is a result of my work aimed to merge MDI child creation
with common window creation code. The rewrite allows MDI children
to have WS_EX_MDICHILD style set on WM_CREATE and therefore properly
get lParam from MDICREATESTRUCT. MDICREATESTRUCT is now gets A<->W
translated (translation 16-bit windows is still missing).

Please give it a try with your favorite MDI application and report
the results you get.

The patch includes a simple test case, which passes on win9x and
win2000 SP4.

Thanks.

-- 
Dmitry.

-------------- next part --------------
diff -u cvs/hq/wine/dlls/user/tests/win.c wine/dlls/user/tests/win.c
--- cvs/hq/wine/dlls/user/tests/win.c	2004-01-01 15:33:52.000000000 +0800
+++ wine/dlls/user/tests/win.c	2004-01-13 18:23:42.000000000 +0800
@@ -693,34 +693,180 @@ static void test_MDI_create(HWND parent,
 {
     MDICREATESTRUCTA mdi_cs;
     HWND mdi_child;
+    static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0};
+    static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0};
+    BOOL isWin9x = FALSE;
 
     mdi_cs.szClass = "MDI_child_Class_1";
-    mdi_cs.szTitle = "MDI child 1";
+    mdi_cs.szTitle = "MDI child";
     mdi_cs.hOwner = GetModuleHandle(0);
-    mdi_cs.x = 0;
-    mdi_cs.y = 0;
+    mdi_cs.x = CW_USEDEFAULT;
+    mdi_cs.y = CW_USEDEFAULT;
     mdi_cs.cx = CW_USEDEFAULT;
     mdi_cs.cy = CW_USEDEFAULT;
-    mdi_cs.style = WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/;
+    mdi_cs.style = 0;
     mdi_cs.lParam = (LPARAM)mdi_lParam_test_message;
     mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
-    assert(mdi_child);
+    ok(mdi_child != 0, "MDI child creation failed\n");
     DestroyWindow(mdi_child);
 
-    mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child 2",
-                                 WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/,
-                                 10, 10, CW_USEDEFAULT, CW_USEDEFAULT,
+    mdi_cs.style = 0x7fffffff; /* without WS_POPUP */
+    mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
+    ok(mdi_child != 0, "MDI child creation failed\n");
+    DestroyWindow(mdi_child);
+
+    mdi_cs.style = 0xffffffff; /* with WS_POPUP */
+    mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
+    if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
+    {
+        ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
+        DestroyWindow(mdi_child);
+    }
+    else
+        ok(mdi_child != 0, "MDI child creation failed\n");
+
+    /* test MDICREATESTRUCT A<->W mapping */
+    /* MDICREATESTRUCTA and MDICREATESTRUCTW have the same layout */
+    mdi_cs.style = 0;
+    mdi_cs.szClass = (LPCSTR)classW;
+    mdi_cs.szTitle = (LPCSTR)titleW;
+    SetLastError(0xdeadbeef);
+    mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
+    if (!mdi_child)
+    {
+        if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+            isWin9x = TRUE;
+        else
+            ok(mdi_child != 0, "MDI child creation failed\n");
+    }
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
+                                 0,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 mdi_client, GetModuleHandle(0),
+                                 (LPARAM)mdi_lParam_test_message);
+    ok(mdi_child != 0, "MDI child creation failed\n");
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
+                                 0x7fffffff, /* without WS_POPUP */
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
                                  mdi_client, GetModuleHandle(0),
                                  (LPARAM)mdi_lParam_test_message);
-    assert(mdi_child);
+    ok(mdi_child != 0, "MDI child creation failed\n");
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child",
+                                 0xffffffff, /* with WS_POPUP */
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 mdi_client, GetModuleHandle(0),
+                                 (LPARAM)mdi_lParam_test_message);
+    if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
+    {
+        ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
+        DestroyWindow(mdi_child);
+    }
+    else
+        ok(mdi_child != 0, "MDI child creation failed\n");
+
+    /* test MDICREATESTRUCT A<->W mapping */
+    SetLastError(0xdeadbeef);
+    mdi_child = CreateMDIWindowW(classW, titleW,
+                                 0,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 CW_USEDEFAULT, CW_USEDEFAULT,
+                                 mdi_client, GetModuleHandle(0),
+                                 (LPARAM)mdi_lParam_test_message);
+    if (!mdi_child)
+    {
+        if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+            isWin9x = TRUE;
+        else
+            ok(mdi_child != 0, "MDI child creation failed\n");
+    }
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
+                                0,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+    ok(mdi_child != 0, "MDI child creation failed\n");
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
+                                0x7fffffff, /* without WS_POPUP */
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+    ok(mdi_child != 0, "MDI child creation failed\n");
     DestroyWindow(mdi_child);
 
-    mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child 3",
-                                WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/,
-                                20, 20, CW_USEDEFAULT, CW_USEDEFAULT,
+    mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
+                                0xffffffff, /* with WS_POPUP */
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
                                 mdi_client, 0, GetModuleHandle(0),
                                 (LPVOID)mdi_lParam_test_message);
-    assert(mdi_child);
+    if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
+    {
+        ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n");
+        DestroyWindow(mdi_child);
+    }
+    else
+        ok(mdi_child != 0, "MDI child creation failed\n");
+
+    /* test MDICREATESTRUCT A<->W mapping */
+    SetLastError(0xdeadbeef);
+    mdi_child = CreateWindowExW(WS_EX_MDICHILD, classW, titleW,
+                                0,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+    if (!mdi_child)
+    {
+        if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+            isWin9x = TRUE;
+        else
+            ok(mdi_child != 0, "MDI child creation failed\n");
+    }
+    DestroyWindow(mdi_child);
+
+    /* This test fails on Win9x */
+    if (!isWin9x)
+    {
+        mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child",
+                                WS_CHILD,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                parent, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+        ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n");
+    }
+
+    mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
+                                WS_CHILD, /* without WS_POPUP */
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+    ok(mdi_child != 0, "MDI child creation failed\n");
+    DestroyWindow(mdi_child);
+
+    mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
+                                WS_CHILD | WS_POPUP, /* with WS_POPUP */
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, GetModuleHandle(0),
+                                (LPVOID)mdi_lParam_test_message);
+    ok(mdi_child != 0, "MDI child creation failed\n");
     DestroyWindow(mdi_child);
 }
 
@@ -728,16 +874,50 @@ static LRESULT WINAPI mdi_child_wnd_proc
 {
     switch (msg)
     {
+        case WM_NCCREATE:
         case WM_CREATE:
         {
             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
             MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams;
 
-todo_wine /* apparently Windows has a common code for MDI and other windows */
-{
             ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n");
-}
             ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n");
+
+            ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_1"), "wrong class name\n");
+            ok(!lstrcmpA(cs->lpszClass, mdi_cs->szClass), "class name does not match\n");
+            ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
+            ok(!lstrcmpA(cs->lpszName, mdi_cs->szTitle), "title does not match\n");
+            ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner);
+
+            /* MDICREATESTRUCT should have original values */
+            ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff,
+                "mdi_cs->style does not match (%08lx)\n", mdi_cs->style);
+            ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x);
+            ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y);
+            ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx);
+            ok(mdi_cs->cy == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cy);
+
+            /* CREATESTRUCT should have fixed values */
+            ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);
+            ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y);
+            ok(cs->cx != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->cx);
+            ok(cs->cy != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->cy);
+
+            if (GetWindowLongA(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
+            {
+                ok(!(cs->style & WS_POPUP), "WS_POPUP is not allowed\n");
+                ok(cs->style == (mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS),
+                   "cs->style does not match (%08lx)\n", cs->style);
+            }
+            else
+            {
+                DWORD style = mdi_cs->style;
+                style &= ~WS_POPUP;
+                style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
+                    WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
+                ok(cs->style == style,
+                   "cs->style does not match (%08lx)\n", cs->style);
+            }
             break;
         }
     }
@@ -748,12 +928,16 @@ static LRESULT WINAPI mdi_child_wnd_proc
 {
     switch (msg)
     {
+        case WM_NCCREATE:
         case WM_CREATE:
         {
             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
 
             ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n");
             ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n");
+
+            ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_2"), "wrong class name\n");
+            ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n");
             break;
         }
     }
@@ -769,22 +953,31 @@ static LRESULT WINAPI mdi_main_wnd_procA
         case WM_CREATE:
         {
             CLIENTCREATESTRUCT client_cs;
-            RECT rc;
-
-            GetClientRect(hwnd, &rc);
 
             client_cs.hWindowMenu = 0;
             client_cs.idFirstChild = 1;
 
+            /* MDIClient without MDIS_ALLCHILDSTYLES */
             mdi_client = CreateWindowExA(0, "mdiclient",
                                          NULL,
-                                         WS_CHILD | WS_CLIPCHILDREN /*| WS_VISIBLE*/,
-                                         0, 0, rc.right, rc.bottom,
+                                         WS_CHILD /*| WS_VISIBLE*/,
+                                         0, 0, 0, 0,
                                          hwnd, 0, GetModuleHandle(0),
                                          (LPVOID)&client_cs);
             assert(mdi_client);
+            test_MDI_create(hwnd, mdi_client);
+            DestroyWindow(mdi_client);
 
+            /* MDIClient with MDIS_ALLCHILDSTYLES */
+            mdi_client = CreateWindowExA(0, "mdiclient",
+                                         NULL,
+                                         WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
+                                         0, 0, 0, 0,
+                                         hwnd, 0, GetModuleHandle(0),
+                                         (LPVOID)&client_cs);
+            assert(mdi_client);
             test_MDI_create(hwnd, mdi_client);
+            DestroyWindow(mdi_client);
             break;
         }
 
@@ -887,20 +1080,23 @@ static void test_icons(void)
 
     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
     ok( res == 0, "wrong small icon %p/0\n", res );
-    res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
-    ok( res != 0, "wrong small icon %p\n", res );
+    /* this test is XP specific */
+    /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
+    ok( res != 0, "wrong small icon %p\n", res );*/
     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon );
     ok( res == 0, "wrong previous small icon %p/0\n", res );
     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
     ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );
-    res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
-    ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );
+    /* this test is XP specific */
+    /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
+    ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );*/
     res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon );
     ok( res == icon, "wrong previous small icon %p/%p\n", res, icon );
     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 );
     ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );
-    res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
-    ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );
+    /* this test is XP specific */
+    /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 );
+    ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );*/
 
     /* make sure the big icon hasn't changed */
     res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 );
@@ -916,6 +1112,7 @@ START_TEST(win)
     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
     assert(hhook);
 
+goto mdi;
     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
                                WS_MAXIMIZEBOX | WS_POPUP,
@@ -932,6 +1129,7 @@ START_TEST(win)
     test_parent_owner();
     test_shell_window();
 
+mdi:
     test_mdi();
     test_icons();
 
diff -u cvs/hq/wine/include/win.h wine/include/win.h
--- cvs/hq/wine/include/win.h	2004-01-01 15:33:56.000000000 +0800
+++ wine/include/win.h	2004-01-14 16:23:51.000000000 +0800
@@ -86,6 +86,7 @@ typedef struct
 #define WIN_INTERNAL_PAINT     0x0010 /* Internal WM_PAINT message pending */
 #define WIN_NEED_SIZE          0x0040 /* Internal WM_SIZE is needed */
 #define WIN_NCACTIVATED        0x0080 /* last WM_NCACTIVATE was positive */
+#define WIN_ISMDICLIENT        0x0100 /* Window is an MDIClient */
 #define WIN_ISDIALOG           0x0200 /* Window is a dialog */
 #define WIN_ISWIN32            0x0400 /* Understands Win32 messages */
 #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0800 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
@@ -114,6 +115,7 @@ extern BOOL WIN_IsWindowDrawable( HWND h
 extern HWND *WIN_ListParents( HWND hwnd );
 extern HWND *WIN_ListChildren( HWND hwnd );
 extern BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly );
+extern void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta );
 
 inline static HWND WIN_GetFullHandle( HWND hwnd )
 {
diff -u cvs/hq/wine/windows/mdi.c wine/windows/mdi.c
--- cvs/hq/wine/windows/mdi.c	2004-01-05 16:06:12.000000000 +0800
+++ wine/windows/mdi.c	2004-01-15 23:12:02.000000000 +0800
@@ -102,13 +102,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mdi);
 
-#define MDI_MAXLISTLENGTH       0x40
 #define MDI_MAXTITLELENGTH      0xa1
 
-#define MDI_NOFRAMEREPAINT      0
-#define MDI_REPAINTFRAMENOW     1
-#define MDI_REPAINTFRAME        2
-
 #define WM_MDICALCCHILDSCROLL   0x10ac /* this is exactly what Windows uses */
 
 /* "More Windows..." definitions */
@@ -121,10 +116,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(mdi);
 
 typedef struct
 {
+    CRITICAL_SECTION lock;
     UINT      nActiveChildren;
-    HWND      hwndChildMaximized;
     HWND      hwndActiveChild;
+    HWND      *child; /* array of tracked children */
+    HMENU     hFrameMenu;
     HMENU     hWindowMenu;
+    UINT      add_pos; /* original number of items in the window menu */
     UINT      idFirstChild;
     LPWSTR    frameTitle;
     UINT      nTotalCreated;
@@ -139,9 +137,9 @@ static void MDI_UpdateFrameText( HWND, H
 static BOOL MDI_AugmentFrameMenu( HWND, HWND );
 static BOOL MDI_RestoreFrameMenu( HWND, HWND );
 static LONG MDI_ChildActivate( HWND, HWND );
+static LRESULT MDI_RefreshMenu(MDICLIENTINFO *);
 
 static HWND MDI_MoreWindowsDialog(HWND);
-static void MDI_SwapMenuItems(HWND, UINT, UINT);
 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
 
@@ -149,20 +147,16 @@ static LRESULT WINAPI MDIClientWndProcW(
  *
  *			MDI_GetChildByID
  */
-static HWND MDI_GetChildByID(HWND hwnd, UINT id)
+static HWND MDI_GetChildByID(HWND hwnd, UINT id, MDICLIENTINFO *ci)
 {
-    HWND ret;
-    HWND *win_array;
     int i;
 
-    if (!(win_array = WIN_ListChildren( hwnd ))) return 0;
-    for (i = 0; win_array[i]; i++)
+    for (i = 0; ci->nActiveChildren; i++)
     {
-        if (GetWindowLongA( win_array[i], GWL_ID ) == id) break;
+        if (GetWindowLongW( ci->child[i], GWL_ID ) == id)
+            return ci->child[i];
     }
-    ret = win_array[i];
-    HeapFree( GetProcessHeap(), 0, win_array );
-    return ret;
+    return 0;
 }
 
 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
@@ -210,83 +204,6 @@ static MDICLIENTINFO *get_client_info( H
 }
 
 /**********************************************************************
- *			MDI_MenuModifyItem
- */
-static void MDI_MenuModifyItem( HWND client, HWND hWndChild )
-{
-    MDICLIENTINFO *clientInfo = get_client_info( client );
-    WCHAR buffer[128];
-    UINT n, id;
-
-    if (!clientInfo || !clientInfo->hWindowMenu) return;
-
-    id = GetWindowLongA( hWndChild, GWL_ID );
-    if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) return;
-    buffer[0] = '&';
-    buffer[1] = '1' + id - clientInfo->idFirstChild;
-    buffer[2] = ' ';
-    GetWindowTextW( hWndChild, buffer + 3, sizeof(buffer)/sizeof(WCHAR) - 3 );
-
-    n = GetMenuState(clientInfo->hWindowMenu, id, MF_BYCOMMAND);
-    ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer );
-    CheckMenuItem(clientInfo->hWindowMenu, id, n & MF_CHECKED);
-}
-
-/**********************************************************************
- *			MDI_MenuDeleteItem
- */
-static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild )
-{
-    WCHAR    	 buffer[128];
-    static const WCHAR format[] = {'&','%','d',' ',0};
-    MDICLIENTINFO *clientInfo = get_client_info( client );
-    UINT	 index      = 0,id,n;
-
-    if( !clientInfo->nActiveChildren || !clientInfo->hWindowMenu )
-        return FALSE;
-
-    id = GetWindowLongA( hWndChild, GWL_ID );
-    DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
-
- /* walk the rest of MDI children to prevent gaps in the id
-  * sequence and in the menu child list */
-
-    for( index = id+1; index <= clientInfo->nActiveChildren +
-				clientInfo->idFirstChild; index++ )
-    {
-        HWND hwnd = MDI_GetChildByID(client,index);
-        if (!hwnd)
-        {
-            TRACE("no window for id=%i\n",index);
-            continue;
-        }
-
-	/* set correct id */
-        SetWindowLongW( hwnd, GWL_ID, GetWindowLongW( hwnd, GWL_ID ) - 1 );
-
-	n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
-        GetWindowTextW( hwnd, buffer + n, sizeof(buffer)/sizeof(WCHAR) - n );
-
-	/*  change menu if the current child is to be shown in the
-         *  "Windows" menu
-         */
-        if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
-	ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
-                      index - 1 , buffer );
-    }
-
-    /*  We must restore the "More Windows..." option if there are enough children
-     */
-    if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
-    {
-        WCHAR szTmp[50];
-        LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
-        AppendMenuW(clientInfo->hWindowMenu, MF_STRING, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp);
-    }
-    return TRUE;
-}
-
-/**********************************************************************
  * 			MDI_GetWindow
  *
  * returns "activateable" child different from the current or zero
@@ -332,21 +249,34 @@ static HWND MDI_GetWindow(MDICLIENTINFO 
  *
  *  It seems that the default height is about 2/3 of the client rect
  */
-static void MDI_CalcDefaultChildPos( HWND hwnd, WORD n, LPPOINT lpPos, INT delta)
+void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta )
 {
     INT  nstagger;
     RECT rect;
     INT  spacing = GetSystemMetrics(SM_CYCAPTION) +
 		     GetSystemMetrics(SM_CYFRAME) - 1;
 
-    GetClientRect( hwnd, &rect );
+    if (total < 0)
+    {
+        MDICLIENTINFO *ci = get_client_info(hwndClient);
+        if (ci)
+        {
+            EnterCriticalSection(&ci->lock);
+            total = ci->nTotalCreated;
+            LeaveCriticalSection(&ci->lock);
+        }
+        else
+            total = 0;
+    }
+
+    GetClientRect( hwndClient, &rect );
     if( rect.bottom - rect.top - delta >= spacing )
 	rect.bottom -= delta;
 
     nstagger = (rect.bottom - rect.top)/(3 * spacing);
     lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
     lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
-    lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
+    lpPos[0].x = lpPos[0].y = spacing * (total%(nstagger+1));
 }
 
 /**********************************************************************
@@ -357,7 +287,6 @@ static LRESULT MDISetMenu( HWND hwnd, HM
 {
     MDICLIENTINFO *ci;
     HWND hwndFrame = GetParent(hwnd);
-    HMENU oldFrameMenu = GetMenu(hwndFrame);
 
     TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow);
 
@@ -375,8 +304,10 @@ static LRESULT MDISetMenu( HWND hwnd, HM
 
     if (!(ci = get_client_info( hwnd ))) return 0;
 
-    if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
-        MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
+    EnterCriticalSection(&ci->lock);
+
+    if( IsZoomed(ci->hwndActiveChild) && hmenuFrame && hmenuFrame!= ci->hFrameMenu )
+        MDI_RestoreFrameMenu( hwndFrame, ci->hwndActiveChild );
 
     if( hmenuWindow && hmenuWindow != ci->hWindowMenu )
     {
@@ -385,65 +316,44 @@ static LRESULT MDISetMenu( HWND hwnd, HM
         /* Agent newsreader calls this function with  ci->hWindowMenu == NULL */
         if( ci->hWindowMenu && ci->nActiveChildren )
         {
-            INT j;
-            LPWSTR buffer = NULL;
-	    MENUITEMINFOW mii;
-            INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
-            INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
-            INT pos = GetMenuItemCount(hmenuWindow) + 1;
+            UINT nActiveChildren_old = ci->nActiveChildren;
 
-            AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
-
-            if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
-                nbWindowsMenuItems = ci->nActiveChildren;
-            else
-                nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
-
-            j = i - nbWindowsMenuItems + 1;
-
-            for( ; i >= j ; i-- )
-            {
-		memset(&mii, 0, sizeof(mii));
-		mii.cbSize = sizeof(mii);
-		mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
-		  | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
-
-		GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
-		if(mii.cch) { /* Menu is MFT_STRING */
-		    mii.cch++; /* add room for '\0' */
-		    buffer = HeapAlloc(GetProcessHeap(), 0,
-				       mii.cch * sizeof(WCHAR));
-		    mii.dwTypeData = buffer;
-		    GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
-		}
-                DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
-                InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
-		if(buffer) {
-		    HeapFree(GetProcessHeap(), 0, buffer);
-		    buffer = NULL;
-		}
-            }
-            /* remove separator */
-            DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
+            /* Remove all items from old Window menu */
+            ci->nActiveChildren = 0;
+            MDI_RefreshMenu(ci);
+
+            ci->add_pos = GetMenuItemCount(hmenuWindow);
+            ci->hWindowMenu = hmenuWindow;
+
+            /* Add items to the new Window menu */
+            ci->nActiveChildren = nActiveChildren_old;
+            MDI_RefreshMenu(ci);
         }
+        else
+            ci->add_pos = GetMenuItemCount(hmenuWindow);
+
         ci->hWindowMenu = hmenuWindow;
     }
 
     if (hmenuFrame)
     {
         SetMenu(hwndFrame, hmenuFrame);
-        if( hmenuFrame!=oldFrameMenu )
+        if( hmenuFrame != ci->hFrameMenu )
         {
-            if( ci->hwndChildMaximized )
-                MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
+            HMENU oldFrameMenu = ci->hFrameMenu;
+
+            ci->hFrameMenu = hmenuFrame;
+            if( IsZoomed(ci->hwndActiveChild) )
+                MDI_AugmentFrameMenu( hwndFrame, ci->hwndActiveChild );
+
+            LeaveCriticalSection(&ci->lock);
             return (LRESULT)oldFrameMenu;
         }
     }
     else
     {
-        HMENU menu = GetMenu( GetParent(hwnd) );
-	INT nItems = GetMenuItemCount(menu) - 1;
-	UINT iId = GetMenuItemID(menu,nItems) ;
+	INT nItems = GetMenuItemCount(ci->hFrameMenu) - 1;
+	UINT iId = GetMenuItemID(ci->hFrameMenu, nItems);
 
 	if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
 	{
@@ -453,185 +363,69 @@ static LRESULT MDISetMenu( HWND hwnd, HM
 	     * that the "if" to this "else" wouldn't catch the need to
 	     * augment the frame menu.
 	     */
-	    if( ci->hwndChildMaximized )
-		MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
+	    if( IsZoomed(ci->hwndActiveChild) )
+		MDI_AugmentFrameMenu( hwndFrame, ci->hwndActiveChild );
 	}
     }
+
+    LeaveCriticalSection(&ci->lock);
     return 0;
 }
 
 /**********************************************************************
  *            MDIRefreshMenu
  */
-static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
-                           HMENU hmenuWindow)
+static LRESULT MDI_RefreshMenu(MDICLIENTINFO *ci)
 {
-    HWND hwndFrame = GetParent(hwnd);
-    HMENU oldFrameMenu = GetMenu(hwndFrame);
-
-    TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow);
-
-    FIXME("partially function stub\n");
-
-    return (LRESULT)oldFrameMenu;
-}
-
+    HMENU hFrameMenu;
+    UINT i, count;
+    WCHAR buf[MDI_MAXTITLELENGTH];
 
-/* ------------------ MDI child window functions ---------------------- */
-
-
-/**********************************************************************
- *					MDICreateChild
- */
-static HWND MDICreateChild( HWND parent, MDICLIENTINFO *ci,
-			    LPMDICREATESTRUCTA cs, BOOL unicode )
-{
-    POINT          pos[2];
-    DWORD	     style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
-    HWND 	     hwnd, hwndMax = 0;
-    UINT wIDmenu = ci->idFirstChild + ci->nActiveChildren;
-    WND *wndParent;
-    static const WCHAR lpstrDef[] = {'j','u','n','k','!',0};
+    EnterCriticalSection(&ci->lock);
 
-    TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
-                cs->x, cs->y, cs->cx, cs->cy, cs->style);
-    /* calculate placement */
-    MDI_CalcDefaultChildPos(parent, ci->nTotalCreated++, pos, 0);
+    TRACE("children %u, window menu %p\n", ci->nActiveChildren, ci->hWindowMenu);
 
-    if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx) cs->cx = pos[1].x;
-    if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy) cs->cy = pos[1].y;
-
-    if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
-    {
- 	cs->x = pos[0].x;
-	cs->y = pos[0].y;
-    }
-
-    /* restore current maximized child */
-    if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
+    if (!ci->hWindowMenu)
     {
-	TRACE("Restoring current maximized child %p\n", ci->hwndChildMaximized);
-	if( style & WS_MAXIMIZE )
-	    SendMessageW(parent, WM_SETREDRAW, FALSE, 0L);
-	hwndMax = ci->hwndChildMaximized;
-	ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
-	if( style & WS_MAXIMIZE )
-	    SendMessageW(parent, WM_SETREDRAW, TRUE, 0L);
+        LeaveCriticalSection(&ci->lock);
+        return 0;
     }
 
-    if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
-    /* this menu is needed to set a check mark in MDI_ChildActivate */
-    if (ci->hWindowMenu != 0)
-        AppendMenuW(ci->hWindowMenu, MF_STRING, wIDmenu, lpstrDef);
-
-    ci->nActiveChildren++;
+    count = GetMenuItemCount(ci->hWindowMenu);
+    for (i = ci->add_pos; i < count; i++)
+        RemoveMenu(ci->hWindowMenu, ci->add_pos, MF_BYPOSITION);
 
-    /* fix window style */
-    wndParent = WIN_FindWndPtr( parent );
-    if( !(wndParent->dwStyle & MDIS_ALLCHILDSTYLES) )
-    {
-	TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
-        style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
-                  WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
-        style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
-    }
+    if (ci->nActiveChildren)
+        AppendMenuW(ci->hWindowMenu, MF_SEPARATOR, -1, NULL);
 
-    if( wndParent->flags & WIN_ISWIN32 )
-    {
-        WIN_ReleaseWndPtr( wndParent );
-        /* FIXME: CreateWindowEx must be called with WS_EX_MDICHILD set, but
-         * it requires to move MDI specific child creation to CreateWindowEx
-         * and do child tracking in MDICLIENT using WM_PARENTNOTIFY.
-         */
-	if(unicode)
-	{
-	    MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)cs;
-	    hwnd = CreateWindowExW( 0, csW->szClass, csW->szTitle, style,
-                                csW->x, csW->y, csW->cx, csW->cy, parent,
-                                (HMENU)wIDmenu, csW->hOwner, csW );
-	}
-	else
-	    hwnd = CreateWindowExA( 0, cs->szClass, cs->szTitle, style,
-                                cs->x, cs->y, cs->cx, cs->cy, parent,
-                                (HMENU)wIDmenu, cs->hOwner, cs );
-    }
-    else
+    for (i = 0; i < ci->nActiveChildren; i++)
     {
-        MDICREATESTRUCT16 cs16;
-        SEGPTR title, cls, seg_cs16;
+        UINT id = ci->idFirstChild + i;
 
-        WIN_ReleaseWndPtr( wndParent );
-        STRUCT32_MDICREATESTRUCT32Ato16( cs, &cs16 );
-        cs16.szTitle = title = MapLS( cs->szTitle );
-        cs16.szClass = cls = MapLS( cs->szClass );
-        seg_cs16 = MapLS( &cs16 );
-        hwnd = WIN_Handle32( CreateWindowEx16( 0, cs->szClass, cs->szTitle, style,
-                                             cs16.x, cs16.y, cs16.cx, cs16.cy,
-                                             HWND_16(parent), (HMENU16)wIDmenu,
-                                             cs16.hOwner, (LPVOID)seg_cs16 ));
-        UnMapLS( seg_cs16 );
-        UnMapLS( title );
-        UnMapLS( cls );
-    }
-
-    /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
-
-    if (hwnd)
-    {
-	/* All MDI child windows have the WS_EX_MDICHILD style */
-        SetWindowLongW( hwnd, GWL_EXSTYLE, GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_MDICHILD );
-
-        /*  If we have more than 9 windows, we must insert the new one at the
-         *  9th position in order to see it in the "Windows" menu
-         */
-        if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
-            MDI_SwapMenuItems( parent, GetWindowLongW( hwnd, GWL_ID ),
-                               ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
-
-	MDI_MenuModifyItem(parent, hwnd);
-
-        /* Have we hit the "More Windows..." limit? If so, we must
-         * add a "More Windows..." option
-         */
-        if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
-        {
-            WCHAR szTmp[50];
-            LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
-
-            ModifyMenuW(ci->hWindowMenu,
-                        ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
-                        MF_BYCOMMAND | MF_STRING,
-                        ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
-                        szTmp);
+        if (i == MDI_MOREWINDOWSLIMIT)
+        {
+            LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, buf, sizeof(buf)/sizeof(WCHAR));
+            AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf);
+            break;
         }
 
-        if( IsIconic(hwnd) && ci->hwndActiveChild )
-	{
-	    TRACE("Minimizing created MDI child %p\n", hwnd);
-	    ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
-	}
-	else
-	{
-            /* WS_VISIBLE is clear if a) the MDI client has
-             * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
-             * MDICreateStruct. If so the created window is not shown nor
-             * activated.
-             */
-            if (IsWindowVisible(hwnd)) ShowWindow(hwnd, SW_SHOW);
-	}
-        TRACE("created child - %p\n",hwnd);
-    }
-    else
-    {
-	ci->nActiveChildren--;
-	DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
-	if( IsWindow(hwndMax) )
-	    ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
+        SetWindowLongW(ci->child[i], GWL_ID, id);
+        InternalGetWindowText(ci->child[i], buf, sizeof(buf)/sizeof(WCHAR));
+        AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf);
+
+        if (ci->child[i] == ci->hwndActiveChild)
+            CheckMenuItem(ci->hWindowMenu, id, MF_CHECKED);
     }
 
-    return hwnd;
+    hFrameMenu = ci->hFrameMenu;
+    LeaveCriticalSection(&ci->lock);
+
+    return (LRESULT)hFrameMenu;
 }
 
+
+/* ------------------ MDI child window functions ---------------------- */
+
 /**********************************************************************
  *			MDI_ChildGetMinMaxInfo
  *
@@ -669,14 +463,17 @@ static void MDI_SwitchActiveChild( HWND 
     HWND	   hwndPrev  = 0;
     MDICLIENTINFO *ci = get_client_info( clientHwnd );
 
+    EnterCriticalSection(&ci->lock);
+
     hwndTo = MDI_GetWindow(ci, childHwnd, bNextWindow, 0);
+    hwndPrev = ci->hwndActiveChild;
+
+    LeaveCriticalSection(&ci->lock);
 
     TRACE("from %p, to %p\n",childHwnd,hwndTo);
 
     if ( !hwndTo ) return; /* no window to switch to */
 
-    hwndPrev = ci->hwndActiveChild;
-
     if ( hwndTo != hwndPrev )
     {
 	SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
@@ -695,6 +492,10 @@ static void MDI_SwitchActiveChild( HWND 
 static LRESULT MDIDestroyChild( HWND parent, MDICLIENTINFO *ci,
                                 HWND child, BOOL flagDestroy )
 {
+    UINT i;
+
+    EnterCriticalSection(&ci->lock);
+
     if( child == ci->hwndActiveChild )
     {
         MDI_SwitchActiveChild(parent, child, TRUE);
@@ -702,11 +503,10 @@ static LRESULT MDIDestroyChild( HWND par
         if( child == ci->hwndActiveChild )
         {
             ShowWindow( child, SW_HIDE);
-            if( child == ci->hwndChildMaximized )
+            if( child == ci->hwndActiveChild && IsZoomed(ci->hwndActiveChild) )
             {
                 HWND frame = GetParent(parent);
                 MDI_RestoreFrameMenu( frame, child );
-                ci->hwndChildMaximized = 0;
                 MDI_UpdateFrameText( frame, parent, TRUE, NULL);
             }
 
@@ -714,7 +514,18 @@ static LRESULT MDIDestroyChild( HWND par
         }
     }
 
-    MDI_MenuDeleteItem(parent, child);
+    for (i = 0; i < ci->nActiveChildren; i++)
+    {
+        if (ci->child[i] == child)
+        {
+            HWND *new_child = HeapAlloc(GetProcessHeap(), 0, (ci->nActiveChildren - 1) * sizeof(HWND));
+            memcpy(new_child, ci->child, i * sizeof(HWND));
+            if (i + 1 < ci->nActiveChildren)
+                memcpy(new_child + i, ci->child + i + 1, (ci->nActiveChildren - i - 1) * sizeof(HWND));
+            HeapFree(GetProcessHeap(), 0, ci->child);
+            ci->child = new_child;
+        }
+    }
 
     ci->nActiveChildren--;
 
@@ -725,6 +536,9 @@ static LRESULT MDIDestroyChild( HWND par
         MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
         DestroyWindow(child);
     }
+
+    LeaveCriticalSection(&ci->lock);
+
     return 0;
 }
 
@@ -736,19 +550,27 @@ static LRESULT MDIDestroyChild( HWND par
  */
 static LONG MDI_ChildActivate( HWND client, HWND child )
 {
-    MDICLIENTINFO *clientInfo = get_client_info( client );
-    HWND prevActiveWnd = clientInfo->hwndActiveChild;
+    MDICLIENTINFO *clientInfo;
+    HWND prevActiveWnd;
     BOOL isActiveFrameWnd;
 
     if (child && (!IsWindowEnabled( child ))) return 0;
 
+    clientInfo = get_client_info( client );
+    EnterCriticalSection(&clientInfo->lock);
+
     /* Don't activate if it is already active. Might happen
        since ShowWindow DOES activate MDI children */
-    if (clientInfo->hwndActiveChild == child) return 0;
+    if (clientInfo->hwndActiveChild == child)
+    {
+        LeaveCriticalSection(&clientInfo->lock);
+        return 0;
+    }
 
     TRACE("%p\n", child);
 
     isActiveFrameWnd = (GetActiveWindow() == GetParent(client));
+    prevActiveWnd = clientInfo->hwndActiveChild;
 
     /* deactivate prev. active child */
     if(prevActiveWnd)
@@ -771,17 +593,21 @@ static LONG MDI_ChildActivate( HWND clie
     }
 
     /* set appearance */
-    if (clientInfo->hwndChildMaximized && clientInfo->hwndChildMaximized != child)
+    if (IsZoomed(clientInfo->hwndActiveChild) && clientInfo->hwndActiveChild != child)
     {
         INT cmd = SW_SHOWNORMAL;
 
         if( child )
         {
-            UINT state = GetMenuState(GetSystemMenu(child, FALSE), SC_MAXIMIZE, MF_BYCOMMAND);
-            if (state != 0xFFFFFFFF && (state & (MF_DISABLED | MF_GRAYED)))
-                SendMessageW(clientInfo->hwndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0);
-            else
+            HMENU hSysMenu = GetSystemMenu(child, FALSE);
+            UINT state = 0;
+            if (hSysMenu)
+                state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
+            if (state != 0xFFFFFFFF && !(state & (MF_DISABLED | MF_GRAYED)))
+            {
+                SendMessageW(clientInfo->hwndActiveChild, WM_SYSCOMMAND, SC_RESTORE, 0);
                 cmd = SW_SHOWMAXIMIZED;
+            }
 
             clientInfo->hwndActiveChild = child;
         }
@@ -791,6 +617,9 @@ static LONG MDI_ChildActivate( HWND clie
 
     clientInfo->hwndActiveChild = child;
 
+    MDI_RefreshMenu(clientInfo);
+    LeaveCriticalSection(&clientInfo->lock);
+
     /* check if we have any children left */
     if( !child )
     {
@@ -799,21 +628,6 @@ static LONG MDI_ChildActivate( HWND clie
         return 0;
     }
 
-    /* check menu item */
-    if( clientInfo->hWindowMenu )
-    {
-        UINT id = GetWindowLongA( child, GWL_ID );
-        /* The window to be activated must be displayed in the "Windows" menu */
-        if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
-        {
-            MDI_SwapMenuItems( GetParent(child),
-                               id, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
-            id = clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1;
-            MDI_MenuModifyItem( GetParent(child), child );
-        }
-
-        CheckMenuItem(clientInfo->hWindowMenu, id, MF_CHECKED);
-    }
     /* bring active child to the top */
     SetWindowPos( child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
 
@@ -874,9 +688,8 @@ static LONG MDICascade( HWND client, MDI
     BOOL has_icons = FALSE;
     int i, total;
 
-    if (ci->hwndChildMaximized)
-        SendMessageA( client, WM_MDIRESTORE,
-                        (WPARAM)ci->hwndChildMaximized, 0);
+    if (IsZoomed(ci->hwndActiveChild))
+        SendMessageA(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0);
 
     if (ci->nActiveChildren == 0) return 0;
 
@@ -928,8 +741,8 @@ static void MDITile( HWND client, MDICLI
     int i, total;
     BOOL has_icons = FALSE;
 
-    if (ci->hwndChildMaximized)
-        SendMessageA( client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0);
+    if (IsZoomed(ci->hwndActiveChild))
+        SendMessageA(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0);
 
     if (ci->nActiveChildren == 0) return;
 
@@ -1034,6 +847,13 @@ static BOOL MDI_AugmentFrameMenu( HWND f
     AppendMenuA(menu,MF_HELP | MF_BITMAP,
                    SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
 
+    /* The close button is only present in Win 95 look */
+    if(TWEAK_WineLook > WIN31_LOOK)
+    {
+        AppendMenuA(menu,MF_HELP | MF_BITMAP,
+                       SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
+    }
+
   /* In Win 95 look, the system menu is replaced by the child icon */
 
   if(TWEAK_WineLook > WIN31_LOOK)
@@ -1078,13 +898,6 @@ static BOOL MDI_AugmentFrameMenu( HWND f
 	return 0;
     }
 
-    /* The close button is only present in Win 95 look */
-    if(TWEAK_WineLook > WIN31_LOOK)
-    {
-        AppendMenuA(menu,MF_HELP | MF_BITMAP,
-                       SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
-    }
-
     EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
     EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
     EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
@@ -1166,6 +979,8 @@ static void MDI_UpdateFrameText( HWND fr
 
     if (!ci) return;
 
+    EnterCriticalSection(&ci->lock);
+
     if (!lpTitle && !ci->frameTitle)  /* first time around, get title from the frame window */
     {
         GetWindowTextW( frame, lpBuffer, sizeof(lpBuffer)/sizeof(WCHAR) );
@@ -1182,7 +997,7 @@ static void MDI_UpdateFrameText( HWND fr
 
     if (ci->frameTitle)
     {
-	if (ci->hwndChildMaximized)
+	if (IsZoomed(ci->hwndActiveChild))
 	{
 	    /* combine frame title and child title if possible */
 
@@ -1195,7 +1010,7 @@ static void MDI_UpdateFrameText( HWND fr
 	    if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
             {
 		strcatW( lpBuffer, lpBracket );
-                if (GetWindowTextW( ci->hwndChildMaximized, lpBuffer + i_frame_text_length + 4,
+                if (GetWindowTextW( ci->hwndActiveChild, lpBuffer + i_frame_text_length + 4,
                                     MDI_MAXTITLELENGTH - i_frame_text_length - 5 ))
                     strcatW( lpBuffer, lpBracket2 );
                 else
@@ -1210,8 +1025,10 @@ static void MDI_UpdateFrameText( HWND fr
     else
 	lpBuffer[0] = '\0';
 
+    LeaveCriticalSection(&ci->lock);
+
     DefWindowProcW( frame, WM_SETTEXT, 0, (LPARAM)lpBuffer );
-    if( repaint == MDI_REPAINTFRAME)
+    if( repaint )
         SetWindowPos( frame, 0,0,0,0,0, SWP_FRAMECHANGED |
                       SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
 }
@@ -1234,21 +1051,21 @@ static LRESULT MDIClientWndProc_common( 
     {
       case WM_CREATE:
       {
-          RECT rect;
           /* Since we are using only cs->lpCreateParams, we can safely
            * cast to LPCREATESTRUCTA here */
           LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
           WND *wndPtr = WIN_GetPtr( hwnd );
 
+          wndPtr->flags |= WIN_ISMDICLIENT;
+
 	/* Translation layer doesn't know what's in the cs->lpCreateParams
 	 * so we have to keep track of what environment we're in. */
 
 	if( wndPtr->flags & WIN_ISWIN32 )
 	{
-#define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
+	    LPCLIENTCREATESTRUCT ccs = cs->lpCreateParams;
 	    ci->hWindowMenu	= ccs->hWindowMenu;
 	    ci->idFirstChild	= ccs->idFirstChild;
-#undef ccs
 	}
         else
 	{
@@ -1258,62 +1075,84 @@ static LRESULT MDIClientWndProc_common( 
 	}
         WIN_ReleasePtr( wndPtr );
 
-	ci->hwndChildMaximized  = 0;
+        InitializeCriticalSection(&ci->lock);
+        ci->child = NULL;
 	ci->nActiveChildren	= 0;
 	ci->nTotalCreated	= 0;
 	ci->frameTitle		= NULL;
 	ci->mdiFlags		= 0;
-        SetWindowLongW( hwnd, GWL_STYLE, GetWindowLongW(hwnd,GWL_STYLE) | WS_CLIPCHILDREN );
+        ci->hFrameMenu = GetMenu(cs->hwndParent);
+        ci->add_pos = GetMenuItemCount(ci->hWindowMenu);
 
 	if (!hBmpClose) hBmpClose = CreateMDIMenuBitmap();
 
-	if (ci->hWindowMenu != 0)
-	    AppendMenuW( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
-
-	GetClientRect( GetParent(hwnd), &rect);
-        MoveWindow( hwnd, 0, 0, rect.right, rect.bottom, FALSE );
-
-        MDI_UpdateFrameText( GetParent(hwnd), hwnd, MDI_NOFRAMEREPAINT, NULL);
-
         TRACE("Client created - hwnd = %p, idFirst = %u\n", hwnd, ci->idFirstChild );
         return 0;
       }
 
       case WM_DESTROY:
       {
-          INT nItems;
-          if( ci->hwndChildMaximized )
-              MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized);
-          if((ci->hWindowMenu != 0) &&
-             (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
-          {
-              ci->idFirstChild = nItems - 1;
-              ci->nActiveChildren++;  /* to delete a separator */
-              while( ci->nActiveChildren-- )
-                  DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
-          }
+          EnterCriticalSection(&ci->lock);
+
+          if( IsZoomed(ci->hwndActiveChild) )
+              MDI_RestoreFrameMenu(GetParent(hwnd), ci->hwndActiveChild);
+
+          ci->nActiveChildren = 0;
+          MDI_RefreshMenu(ci);
+
+          if (ci->child) HeapFree( GetProcessHeap(), 0, ci->child );
           if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle );
+
+          LeaveCriticalSection(&ci->lock);
+          DeleteCriticalSection(&ci->lock);
           return 0;
       }
 
       case WM_MDIACTIVATE:
-        if( ci->hwndActiveChild != (HWND)wParam )
+      {
+        HWND hwndActive;
+
+        EnterCriticalSection(&ci->lock);
+        hwndActive = ci->hwndActiveChild;
+        LeaveCriticalSection(&ci->lock);
+
+        if( hwndActive != (HWND)wParam )
 	    SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
         return 0;
+      }
 
       case WM_MDICASCADE:
         return MDICascade(hwnd, ci);
 
       case WM_MDICREATE:
         if (lParam)
-            return (LRESULT)MDICreateChild( hwnd, ci, (MDICREATESTRUCTA *)lParam, unicode );
+        {
+            if (unicode)
+            {
+                MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam;
+                return (LRESULT)CreateWindowExW(WS_EX_MDICHILD, csW->szClass,
+                                            csW->szTitle, csW->style,
+                                            csW->x, csW->y, csW->cx, csW->cy,
+                                            hwnd, 0, csW->hOwner,
+                                            (LPVOID)csW->lParam);
+            }
+            else
+            {
+                MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam;
+                return (LRESULT)CreateWindowExA(WS_EX_MDICHILD, csA->szClass,
+                                            csA->szTitle, csA->style,
+                                            csA->x, csA->y, csA->cx, csA->cy,
+                                            hwnd, 0, csA->hOwner,
+                                            (LPVOID)csA->lParam);
+            }
+        }
         return 0;
 
       case WM_MDIDESTROY:
           return MDIDestroyChild( hwnd, ci, WIN_GetFullHandle( (HWND)wParam ), TRUE );
 
       case WM_MDIGETACTIVE:
-          if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized != 0);
+          if (lParam) *(BOOL *)lParam = IsZoomed(ci->hwndActiveChild);
           return (LRESULT)ci->hwndActiveChild;
 
       case WM_MDIICONARRANGE:
@@ -1339,7 +1178,7 @@ static LRESULT MDIClientWndProc_common( 
           return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
 
       case WM_MDIREFRESHMENU:
-          return MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
+          return MDI_RefreshMenu( ci );
 
       case WM_MDITILE:
 	ci->mdiFlags |= MDIF_NEEDUPDATE;
@@ -1366,8 +1205,25 @@ static LRESULT MDIClientWndProc_common( 
 	break;
 
       case WM_PARENTNOTIFY:
-        if (LOWORD(wParam) == WM_LBUTTONDOWN)
+        switch (LOWORD(wParam))
         {
+        case WM_CREATE:
+            if (GetWindowLongW((HWND)lParam, GWL_EXSTYLE) & WS_EX_MDICHILD)
+            {
+                ci->nTotalCreated++;
+                ci->nActiveChildren++;
+
+                if (!ci->child)
+                    ci->child = HeapAlloc(GetProcessHeap(), 0, sizeof(HWND));
+                else
+                    ci->child = HeapReAlloc(GetProcessHeap(), 0, ci->child, sizeof(HWND) * ci->nActiveChildren);
+
+                ci->child[ci->nActiveChildren - 1] = (HWND)lParam;
+            }
+            break;
+
+        case WM_LBUTTONDOWN:
+            {
             HWND child;
             POINT pt;
             pt.x = (short)LOWORD(lParam);
@@ -1378,11 +1234,13 @@ static LRESULT MDIClientWndProc_common( 
 
             if( child && child != hwnd && child != ci->hwndActiveChild )
                 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
+            break;
+            }
         }
         return 0;
 
       case WM_SIZE:
-        if( IsWindow(ci->hwndChildMaximized) )
+        if( IsWindow(ci->hwndActiveChild) && IsZoomed(ci->hwndActiveChild) )
 	{
 	    RECT	rect;
 
@@ -1391,9 +1249,9 @@ static LRESULT MDIClientWndProc_common( 
 	    rect.right = LOWORD(lParam);
 	    rect.bottom = HIWORD(lParam);
 
-	    AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndChildMaximized,GWL_STYLE),
-                               0, GetWindowLongA(ci->hwndChildMaximized,GWL_EXSTYLE) );
-	    MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
+	    AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndActiveChild, GWL_STYLE),
+                               0, GetWindowLongA(ci->hwndActiveChild, GWL_EXSTYLE) );
+	    MoveWindow(ci->hwndActiveChild, rect.left, rect.top,
 			 rect.right - rect.left, rect.bottom - rect.top, 1);
 	}
 	else
@@ -1447,7 +1305,7 @@ LRESULT WINAPI DefFrameProcA( HWND hwnd,
                 DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0 );
                 LPWSTR text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
                 MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, text, len );
-                MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, text );
+                MDI_UpdateFrameText(hwnd, hwndMDIClient, TRUE, text );
                 HeapFree( GetProcessHeap(), 0, text );
             }
             return 1; /* success. FIXME: check text length */
@@ -1483,7 +1341,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd,
                 if (id <  ci->idFirstChild || id >= ci->idFirstChild + ci->nActiveChildren)
                 {
                     if( (id - 0xf000) & 0xf00f ) break;
-                    if( !ci->hwndChildMaximized ) break;
+                    if( !IsZoomed(ci->hwndActiveChild) ) break;
                     switch( id )
                     {
                     case SC_SIZE:
@@ -1494,7 +1352,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd,
                     case SC_PREVWINDOW:
                     case SC_CLOSE:
                     case SC_RESTORE:
-                        return SendMessageW( ci->hwndChildMaximized, WM_SYSCOMMAND,
+                        return SendMessageW( ci->hwndActiveChild, WM_SYSCOMMAND,
                                              wParam, lParam);
                     }
                 }
@@ -1506,7 +1364,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd,
                         childHwnd = MDI_MoreWindowsDialog(hwndMDIClient);
                     else
                         /* User chose one of the windows listed in the "Windows" menu */
-                        childHwnd = MDI_GetChildByID(hwndMDIClient,id);
+                        childHwnd = MDI_GetChildByID(hwndMDIClient, id, ci);
 
                     if( childHwnd )
                         SendMessageW( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)childHwnd, 0 );
@@ -1519,7 +1377,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd,
 	    break;
 
         case WM_SETTEXT:
-            MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, (LPWSTR)lParam );
+            MDI_UpdateFrameText(hwnd, hwndMDIClient, TRUE, (LPWSTR)lParam );
 	    return 1; /* success. FIXME: check text length */
 
         case WM_SETFOCUS:
@@ -1534,7 +1392,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd,
             {
                 MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam;
 
-                if (!IsIconic(hwnd) && ci->hwndActiveChild && !ci->hwndChildMaximized)
+                if (!IsIconic(hwnd) && ci->hwndActiveChild && !IsZoomed(ci->hwndActiveChild))
                 {
                     /* control menu is between the frame system menu and
                      * the first entry of menu bar */
@@ -1574,9 +1432,9 @@ LRESULT WINAPI DefMDIChildProcA( HWND hw
     {
     case WM_SETTEXT:
 	DefWindowProcA(hwnd, message, wParam, lParam);
-        MDI_MenuModifyItem( client, hwnd );
-	if( ci->hwndChildMaximized == hwnd )
-	    MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
+        MDI_RefreshMenu(ci);
+	if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild) )
+	    MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL );
         return 1; /* success. FIXME: check text length */
 
     case WM_GETMINMAXINFO:
@@ -1611,9 +1469,9 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw
     {
     case WM_SETTEXT:
         DefWindowProcW(hwnd, message, wParam, lParam);
-        MDI_MenuModifyItem( client, hwnd );
-        if( ci->hwndChildMaximized == hwnd )
-            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
+        MDI_RefreshMenu(ci);
+        if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild) )
+            MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL );
         return 1; /* success. FIXME: check text length */
 
     case WM_GETMINMAXINFO:
@@ -1639,7 +1497,8 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw
         switch( wParam )
         {
         case SC_MOVE:
-            if( ci->hwndChildMaximized == hwnd) return 0;
+            if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild))
+                return 0;
             break;
         case SC_RESTORE:
         case SC_MINIMIZE:
@@ -1647,7 +1506,7 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw
                             GetWindowLongW( hwnd, GWL_STYLE ) | WS_SYSMENU );
             break;
         case SC_MAXIMIZE:
-            if (ci->hwndChildMaximized == hwnd)
+            if (ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild))
                 return SendMessageW( GetParent(client), message, wParam, lParam);
             SetWindowLongW( hwnd, GWL_STYLE,
                             GetWindowLongW( hwnd, GWL_STYLE ) & ~WS_SYSMENU );
@@ -1662,39 +1521,23 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw
         break;
 
     case WM_SETVISIBLE:
-        if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
+        if (IsZoomed(ci->hwndActiveChild)) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
         else MDI_PostUpdate(client, ci, SB_BOTH+1);
         break;
 
     case WM_SIZE:
-        if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
+        if( wParam != SIZE_MAXIMIZED )
         {
-            ci->hwndChildMaximized = 0;
             MDI_RestoreFrameMenu( GetParent(client), hwnd );
-            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
+            MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL );
         }
 
         if( wParam == SIZE_MAXIMIZED )
         {
-            HWND hMaxChild = ci->hwndChildMaximized;
-
-            if( hMaxChild == hwnd ) break;
-            if( hMaxChild)
-            {
-                SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 );
-                MDI_RestoreFrameMenu( GetParent(client), hMaxChild );
-                ShowWindow( hMaxChild, SW_SHOWNOACTIVATE );
-                SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 );
-            }
             TRACE("maximizing child %p\n", hwnd );
 
-            /* keep track of the maximized window. */
-            ci->hwndChildMaximized = hwnd; /* !!! */
-
-            /* The maximized window should also be the active window */
-            MDI_ChildActivate( client, hwnd );
             MDI_AugmentFrameMenu( GetParent(client), hwnd );
-            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
+            MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL );
         }
 
         if( wParam == SIZE_MINIMIZED )
@@ -1755,29 +1598,13 @@ HWND WINAPI CreateMDIWindowA(
     HINSTANCE hInstance, /* [in] Handle to application instance */
     LPARAM lParam)         /* [in] Application-defined value */
 {
-    MDICLIENTINFO *pCi = get_client_info( hWndParent );
-    MDICREATESTRUCTA cs;
-
-    TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n",
+    TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n",
           debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
           nWidth,nHeight,hWndParent,hInstance,lParam);
 
-    if (!pCi)
-    {
-        ERR("bad hwnd for MDI-client: %p\n", hWndParent);
-        return 0;
-    }
-    cs.szClass=lpClassName;
-    cs.szTitle=lpWindowName;
-    cs.hOwner=hInstance;
-    cs.x=X;
-    cs.y=Y;
-    cs.cx=nWidth;
-    cs.cy=nHeight;
-    cs.style=dwStyle;
-    cs.lParam=lParam;
-
-    return MDICreateChild(hWndParent, pCi, &cs, FALSE);
+    return CreateWindowExA(WS_EX_MDICHILD, lpClassName, lpWindowName,
+                           dwStyle, X, Y, nWidth, nHeight, hWndParent,
+                           0, hInstance, (LPVOID)lParam);
 }
 
 /***********************************************************************
@@ -1799,29 +1626,13 @@ HWND WINAPI CreateMDIWindowW(
     HINSTANCE hInstance, /* [in] Handle to application instance */
     LPARAM lParam)         /* [in] Application-defined value */
 {
-    MDICLIENTINFO *pCi = get_client_info( hWndParent );
-    MDICREATESTRUCTW cs;
-
-    TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n",
+    TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n",
           debugstr_w(lpClassName), debugstr_w(lpWindowName), dwStyle, X, Y,
           nWidth, nHeight, hWndParent, hInstance, lParam);
 
-    if (!pCi)
-    {
-        ERR("bad hwnd for MDI-client: %p\n", hWndParent);
-        return 0;
-    }
-    cs.szClass = lpClassName;
-    cs.szTitle = lpWindowName;
-    cs.hOwner = hInstance;
-    cs.x = X;
-    cs.y = Y;
-    cs.cx = nWidth;
-    cs.cy = nHeight;
-    cs.style = dwStyle;
-    cs.lParam = lParam;
-
-    return MDICreateChild(hWndParent, pCi, (MDICREATESTRUCTA *)&cs, TRUE);
+    return CreateWindowExW(WS_EX_MDICHILD, lpClassName, lpWindowName,
+                           dwStyle, X, Y, nWidth, nHeight, hWndParent,
+                           0, hInstance, (LPVOID)lParam);
 }
 
 /**********************************************************************
@@ -2056,32 +1867,15 @@ static INT_PTR WINAPI MDI_MoreWindowsDlg
            UINT i;
            MDICLIENTINFO *ci = get_client_info( (HWND)lParam );
            HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
-           HWND *list, *sorted_list;
-
-           if (!(list = WIN_ListChildren( (HWND)lParam ))) return TRUE;
-           if (!(sorted_list = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                          sizeof(HWND) * ci->nActiveChildren )))
-           {
-               HeapFree( GetProcessHeap(), 0, list );
-               return FALSE;
-           }
-
-           /* Fill the list, sorted by id... */
-           for (i = 0; list[i]; i++)
-           {
-               UINT id = GetWindowLongW( list[i], GWL_ID ) - ci->idFirstChild;
-               if (id < ci->nActiveChildren) sorted_list[id] = list[i];
-           }
-           HeapFree( GetProcessHeap(), 0, list );
 
            for (i = 0; i < ci->nActiveChildren; i++)
            {
-               WCHAR buffer[128];
+               WCHAR buffer[MDI_MAXTITLELENGTH];
 
-               if (!GetWindowTextW( sorted_list[i], buffer, sizeof(buffer)/sizeof(WCHAR) ))
+               if (!InternalGetWindowText( ci->child[i], buffer, sizeof(buffer)/sizeof(WCHAR) ))
                    continue;
                SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer );
-               SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)sorted_list[i] );
+               SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)ci->child[i] );
                length = strlenW(buffer);  /* FIXME: should use GetTextExtentPoint */
                if (length > widest)
                    widest = length;
@@ -2156,28 +1950,3 @@ static HWND MDI_MoreWindowsDialog(HWND h
                                           (LPDLGTEMPLATEA) template,
                                           hwnd, MDI_MoreWindowsDlgProc, (LPARAM) hwnd);
 }
-
-/*
- *
- *                      MDI_SwapMenuItems
- *
- *      Will swap the menu IDs for the given 2 positions.
- *      pos1 and pos2 are menu IDs
- *
- *
- */
-
-static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
-{
-    HWND *list;
-    int i;
-
-    if (!(list = WIN_ListChildren( parent ))) return;
-    for (i = 0; list[i]; i++)
-    {
-        UINT id = GetWindowLongW( list[i], GWL_ID );
-        if (id == pos1) SetWindowLongW( list[i], GWL_ID, pos2 );
-        else if (id == pos2) SetWindowLongW( list[i], GWL_ID, pos1 );
-    }
-    HeapFree( GetProcessHeap(), 0, list );
-}
diff -u cvs/hq/wine/windows/win.c wine/windows/win.c
--- cvs/hq/wine/windows/win.c	2004-01-01 15:33:57.000000000 +0800
+++ wine/windows/win.c	2004-01-15 23:14:07.000000000 +0800
@@ -805,7 +805,18 @@ static void WIN_FixCoordinates( CREATEST
     {
         if (cs->style & (WS_CHILD | WS_POPUP))
         {
-            if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
+            if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
+            {
+                if (cs->dwExStyle & WS_EX_MDICHILD)
+                {
+                    POINT pos[2];
+                    MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
+                    cs->x = pos[0].x;
+                    cs->y = pos[0].y;
+                }
+                else
+                    cs->x = cs->y = 0;
+            }
             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
         }
         else  /* overlapped window */
@@ -979,7 +990,7 @@ static HWND WIN_CreateWindowEx( CREATEST
 {
     INT sw = SW_SHOW;
     WND *wndPtr;
-    HWND hwnd, parent, owner;
+    HWND hwnd, parent, owner, top_child = 0;
     BOOL unicode = (type == WIN_PROC_32W);
 
     TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
@@ -1024,6 +1035,61 @@ static HWND WIN_CreateWindowEx( CREATEST
         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
     }
 
+    if (cs->dwExStyle & WS_EX_MDICHILD)
+    {
+        MDICREATESTRUCTA mdi_cs;
+        UINT flags = 0;
+
+        wndPtr = WIN_GetPtr(cs->hwndParent);
+        if (wndPtr && wndPtr != WND_OTHER_PROCESS)
+        {
+            flags = wndPtr->flags;
+            WIN_ReleasePtr(wndPtr);
+        }
+
+        if (!(flags & WIN_ISMDICLIENT))
+        {
+            WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
+            return 0;
+        }
+
+        /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
+         * MDICREATESTRUCT members have the originally passed values.
+         *
+         * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
+         * have the same layout.
+         */
+        mdi_cs.szClass = cs->lpszClass;
+        mdi_cs.szTitle = cs->lpszName;
+        mdi_cs.hOwner = cs->hInstance;
+        mdi_cs.x = cs->x;
+        mdi_cs.y = cs->y;
+        mdi_cs.cx = cs->cx;
+        mdi_cs.cy = cs->cy;
+        mdi_cs.style = cs->style;
+        mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
+
+        cs->lpCreateParams = (LPVOID)&mdi_cs;
+
+        if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
+        {
+            if (cs->style & WS_POPUP)
+            {
+                TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
+                return 0;
+            }
+            cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
+        }
+        else
+        {
+            cs->style &= ~WS_POPUP;
+            cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
+                WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
+        }
+
+        top_child = GetWindow(cs->hwndParent, GW_CHILD);
+    }
+
     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
 
     /* Correct the window style - stage 1
@@ -1136,6 +1202,21 @@ static HWND WIN_CreateWindowEx( CREATEST
     send_parent_notify( hwnd, WM_CREATE );
     if (!IsWindow( hwnd )) return 0;
 
+    if (cs->dwExStyle & WS_EX_MDICHILD)
+    {
+        if (top_child)
+        {
+            /* Restore current maximized child */
+            if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
+            {
+                TRACE("Restoring current maximized child %p\n", top_child);
+                ShowWindow(top_child, SW_SHOWNOACTIVATE);
+            }
+        }
+
+        SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
+    }
+
     if (cs->style & WS_VISIBLE)
     {
         /* in case WS_VISIBLE got set in the meantime */
@@ -1237,9 +1318,6 @@ HWND WINAPI CreateWindowExA( DWORD exSty
     CREATESTRUCTA cs;
     char buffer[256];
 
-    if(exStyle & WS_EX_MDICHILD)
-        return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
-
     /* Find the class atom */
 
     if (HIWORD(className))
@@ -1293,9 +1371,6 @@ HWND WINAPI CreateWindowExW( DWORD exSty
     CREATESTRUCTW cs;
     WCHAR buffer[256];
 
-    if(exStyle & WS_EX_MDICHILD)
-        return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
-
     /* Find the class atom */
 
     if (HIWORD(className))
@@ -1398,6 +1473,13 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
 
     TRACE("(%p)\n", hwnd);
 
+    /* Hide the window */
+    if (!ShowWindow( hwnd, SW_HIDE ))
+    {
+        if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
+    }
+    if (!IsWindow(hwnd)) return TRUE;
+
     /* Look whether the focus is within the tree of windows we will
      * be destroying.
      */
@@ -1409,6 +1491,9 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
         SetFocus( parent );
     }
 
+    if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
+        SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
+
       /* Call hooks */
 
     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
@@ -1431,14 +1516,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
     if (USER_Driver.pResetSelectionOwner)
         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
 
-      /* Hide the window */
-
-    if (!ShowWindow( hwnd, SW_HIDE ))
-    {
-        if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
-    }
-    if (!IsWindow(hwnd)) return TRUE;
-
       /* Recursively destroy owned windows */
 
     if (!is_child)
diff -u cvs/hq/wine/windows/winproc.c wine/windows/winproc.c
--- cvs/hq/wine/windows/winproc.c	2003-11-12 14:44:31.000000000 +0800
+++ wine/windows/winproc.c	2004-01-13 20:10:17.000000000 +0800
@@ -671,6 +671,25 @@ INT WINPROC_MapMsg32ATo32W( HWND hwnd, U
                 RtlCreateUnicodeStringFromAsciiz(&usBuffer,(LPCSTR)xs->cs.lpszClass);
                 xs->lpszClass = xs->cs.lpszClass = usBuffer.Buffer;
             }
+
+            if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
+            {
+                MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0,
+                                                                         sizeof(*mdi_cs));
+                *mdi_cs = *(MDICREATESTRUCTW *)xs->cs.lpCreateParams;
+                if (HIWORD(mdi_cs->szTitle))
+                {
+                    RtlCreateUnicodeStringFromAsciiz(&usBuffer, (LPCSTR)mdi_cs->szTitle);
+                    mdi_cs->szTitle = usBuffer.Buffer;
+                }
+                if (HIWORD(mdi_cs->szClass))
+                {
+                    RtlCreateUnicodeStringFromAsciiz(&usBuffer, (LPCSTR)mdi_cs->szClass);
+                    mdi_cs->szClass = usBuffer.Buffer;
+                }
+                xs->cs.lpCreateParams = mdi_cs;
+            }
+
             *plparam = (LPARAM)xs;
         }
         return 1;
@@ -829,6 +848,16 @@ LRESULT WINPROC_UnmapMsg32ATo32W( HWND h
             struct s *xs = (struct s *)lParam;
             if (xs->lpszName)  HeapFree( GetProcessHeap(), 0, xs->lpszName );
             if (xs->lpszClass) HeapFree( GetProcessHeap(), 0, xs->lpszClass );
+
+            if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
+            {
+                MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)xs->cs.lpCreateParams;
+                if (HIWORD(mdi_cs->szTitle))
+                    HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szTitle);
+                if (HIWORD(mdi_cs->szClass))
+                    HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szClass);
+                HeapFree(GetProcessHeap(), 0, mdi_cs);
+            }
             HeapFree( GetProcessHeap(), 0, xs );
         }
         break;
@@ -952,6 +981,25 @@ INT WINPROC_MapMsg32WTo32A( HWND hwnd, U
             if (HIWORD(cs->lpszClass))
                 cs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0,
                                                  (LPCWSTR)cs->lpszClass);
+
+            if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
+            {
+                MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0,
+                                                                         sizeof(*mdi_cs));
+                if (!mdi_cs)
+                {
+                    HeapFree(GetProcessHeap(), 0, cs);
+                    return -1;
+                }
+                *mdi_cs = *(MDICREATESTRUCTA *)cs->lpCreateParams;
+                if (HIWORD(mdi_cs->szTitle))
+                    mdi_cs->szTitle = HEAP_strdupWtoA(GetProcessHeap(), 0,
+                                                      (LPCWSTR)mdi_cs->szTitle);
+                if (HIWORD(mdi_cs->szClass))
+                    mdi_cs->szClass = HEAP_strdupWtoA(GetProcessHeap(), 0,
+                                                      (LPCWSTR)mdi_cs->szClass);
+                cs->lpCreateParams = (LPVOID)mdi_cs;
+            }
             *plparam = (LPARAM)cs;
         }
         return 1;
@@ -1100,6 +1148,15 @@ void WINPROC_UnmapMsg32WTo32A( HWND hwnd
                 HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszName );
             if (HIWORD(cs->lpszClass))
                 HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszClass );
+            if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
+            {
+                MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams;
+                if (HIWORD(mdi_cs->szTitle))
+                    HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szTitle);
+                if (HIWORD(mdi_cs->szClass))
+                    HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szClass);
+                HeapFree(GetProcessHeap(), 0, mdi_cs);
+            }
             HeapFree( GetProcessHeap(), 0, cs );
         }
         break;


More information about the wine-devel mailing list