Implemented GetAncestor and removed WIN_GetTopParent.
Removed a few more accesses to the WND structure.

diff --git a/windows/mdi.c b/windows/mdi.c
index feb2430..aea293a 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -193,25 +193,24 @@
 /**********************************************************************
  *			MDI_MenuModifyItem
  */
-static BOOL MDI_MenuModifyItem( HWND client, HWND hWndChild )
+static void MDI_MenuModifyItem( HWND client, HWND hWndChild )
 {
-    static const WCHAR format[] = {'%','d',' ',0};
-
     MDICLIENTINFO *clientInfo = get_client_info( client );
     WCHAR buffer[128];
     UINT n, id;
-    BOOL bRet;
 
-    if (!clientInfo || !clientInfo->hWindowMenu) return FALSE;
+    if (!clientInfo || !clientInfo->hWindowMenu) return;
 
     id = GetWindowLongA( hWndChild, GWL_ID );
-    n = wsprintfW(buffer, format, id - clientInfo->idFirstChild + 1);
-    GetWindowTextW( hWndChild, buffer + n, sizeof(buffer)/sizeof(WCHAR) - n );
+    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);
-    bRet = ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer );
+    n = GetMenuState(clientInfo->hWindowMenu, id, MF_BYCOMMAND);
+    ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer );
     CheckMenuItem(clientInfo->hWindowMenu, id, n & MF_CHECKED);
-    return bRet;
 }
 
 /**********************************************************************
@@ -276,28 +275,37 @@
 static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext,
                             DWORD dwStyleMask )
 {
-    WND *wndPtr, *pWnd, *pWndLast = NULL;
-    
+    int i;
+    HWND *list;
+    HWND last = 0;
+
     dwStyleMask |= WS_DISABLED | WS_VISIBLE;
     if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
 
-    if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
+    if (!(list = WIN_BuildWinArray( GetParent(hWnd) ))) return 0;
+    i = 0;
+    /* start from next after hWnd */
+    while (list[i] && list[i] != hWnd) i++;
+    if (list[i]) i++;
 
-    for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
+    for ( ; list[i]; i++)
     {
-        if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
-
-        if ( pWnd == wndPtr ) break; /* went full circle */
-
-        if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
-        {
-	    pWndLast = pWnd;
-	    if ( bNext ) break;
-        }
+        if (GetWindow( list[i], GW_OWNER )) continue;
+        if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
+        last = list[i];
+        if (bNext) goto found;
     }
-    WIN_ReleaseWndPtr(wndPtr);
-    WIN_ReleaseWndPtr(pWnd);
-    return pWndLast ? pWndLast->hwndSelf : 0;
+    /* now restart from the beginning */
+    for (i = 0; list[i] && list[i] != hWnd; i++)
+    {
+        if (GetWindow( list[i], GW_OWNER )) continue;
+        if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
+        last = list[i];
+        if (bNext) goto found;
+    }
+ found:
+    WIN_ReleaseWinArray( list );
+    return last;
 }
 
 /**********************************************************************
@@ -775,7 +783,9 @@
         /* 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);
+            MDI_SwapMenuItems( GetParent(child),
+                               id, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
+            id = clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1;
             MDI_MenuModifyItem( GetParent(child), child );
         }
 
@@ -1129,7 +1139,7 @@
     WCHAR   lpBuffer[MDI_MAXTITLELENGTH+1];
     MDICLIENTINFO *ci = get_client_info( hClient );
 
-    TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
+    TRACE("repaint %i, frameText %s\n", repaint, debugstr_w(lpTitle));
 
     if (!ci) return;
 
@@ -1149,42 +1159,30 @@
 
     if (ci->frameTitle)
     {
-	WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );     
-
-	if( childWnd && childWnd->text )
+	if (ci->hwndChildMaximized)
 	{
 	    /* combine frame title and child title if possible */
 
 	    static const WCHAR lpBracket[]  = {' ','-',' ','[',0};
 	    static const WCHAR lpBracket2[]  = {']',0};
 	    int	i_frame_text_length = strlenW(ci->frameTitle);
-	    int	i_child_text_length = strlenW(childWnd->text);
 
 	    lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
 
 	    if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
             {
 		strcatW( lpBuffer, lpBracket );
-
-		if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
-		{
-		    strcatW( lpBuffer, childWnd->text );
-		    strcatW( lpBuffer, lpBracket2 );
-		}
-		else
-		{
-		    lstrcpynW( lpBuffer + i_frame_text_length + 4, 
-				 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
-		    strcatW( lpBuffer, lpBracket2 );
-		}
-	    }
+                if (GetWindowTextW( ci->hwndChildMaximized, lpBuffer + i_frame_text_length + 4,
+                                    MDI_MAXTITLELENGTH - i_frame_text_length - 5 ))
+                    strcatW( lpBuffer, lpBracket2 );
+                else
+                    lpBuffer[i_frame_text_length] = 0;  /* remove bracket */
+            }
 	}
 	else
 	{
             lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
 	}
-        WIN_ReleaseWndPtr(childWnd);
-
     }
     else
 	lpBuffer[0] = '\0';
@@ -1514,7 +1512,7 @@
                     HWND childHwnd;
                     if (id - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
                         /* User chose "More Windows..." */
-                        childHwnd = MDI_MoreWindowsDialog(hwnd);
+                        childHwnd = MDI_MoreWindowsDialog(hwndMDIClient);
                     else
                         /* User chose one of the windows listed in the "Windows" menu */
                         childHwnd = MDI_GetChildByID(hwndMDIClient,id);
@@ -1945,24 +1943,32 @@
     SCROLLINFO info;
     RECT childRect, clientRect;
     INT  vmin, vmax, hmin, hmax, vpos, hpos;
-    WND *pWnd;
+    HWND *list;
 
-    if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
     GetClientRect( hwnd, &clientRect );
     SetRectEmpty( &childRect );
 
-    for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
+    if ((list = WIN_BuildWinArray( hwnd )))
     {
-	  if( pWnd->dwStyle & WS_MAXIMIZE )
-	  {
-              WIN_ReleaseWndPtr(pWnd);
-	      ShowScrollBar(hwnd, SB_BOTH, FALSE);
-	      return;
-	  }
-          if( pWnd->dwStyle & WS_VISIBLE )
-              UnionRect( &childRect, &pWnd->rectWindow, &childRect );
-    } 
-    WIN_ReleaseWndPtr(pWnd);
+        int i;
+        for (i = 0; list[i]; i++)
+        {
+            DWORD style = GetWindowLongW( list[i], GWL_STYLE );
+            if (style & WS_MAXIMIZE)
+            {
+                WIN_ReleaseWinArray( list );
+                ShowScrollBar( hwnd, SB_BOTH, FALSE );
+                return;
+            }
+            if (style & WS_VISIBLE)
+            {
+                WND *pWnd = WIN_FindWndPtr( list[i] );
+                UnionRect( &childRect, &pWnd->rectWindow, &childRect );
+                WIN_ReleaseWndPtr( pWnd );
+            }
+        }
+        WIN_ReleaseWinArray( list );
+    }
     UnionRect( &childRect, &clientRect, &childRect );
 
     hmin = childRect.left;
@@ -2132,28 +2138,38 @@
     {
        case WM_INITDIALOG:
        {
-           WND  *pWnd;
            UINT widest       = 0;
            UINT length;
            UINT i;
-           WND  *pParentWnd  = (WND *)WIN_FindWndPtr(lParam);
-           MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
+           MDICLIENTINFO *ci = get_client_info( (HWND)lParam );
            HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
+           HWND *list, *sorted_list;
+
+           if (!(list = WIN_BuildWinArray( (HWND)lParam ))) return TRUE;
+           if (!(sorted_list = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                          sizeof(HWND) * ci->nActiveChildren )))
+           {
+               WIN_ReleaseWinArray( 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];
+           }
+           WIN_ReleaseWinArray( list );
+
            for (i = 0; i < ci->nActiveChildren; i++)
            {
+               WCHAR buffer[128];
 
-               /* Find the window with the current ID */
-               for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
-                   if (pWnd->wIDmenu == ci->idFirstChild + i)
-                       break;
-
-               SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
-               SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
-               length = strlenW(pWnd->text);
-               WIN_ReleaseWndPtr(pWnd);
-
+               if (!GetWindowTextW( sorted_list[i], buffer, sizeof(buffer)/sizeof(WCHAR) ))
+                   continue;
+               SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer );
+               SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)sorted_list[i] );
+               length = strlenW(buffer);  /* FIXME: should use GetTextExtentPoint */
                if (length > widest)
                    widest = length;
            }
@@ -2168,6 +2184,9 @@
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
+                default:
+                    if (HIWORD(wParam) != LBN_DBLCLK) break;
+                    /* fall through */
                 case IDOK:
                 {
                     /*  windows are sorted by menu ID, so we must return the
@@ -2175,32 +2194,14 @@
                      */
                     HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
                     UINT index        = SendMessageW(hListBox, LB_GETCURSEL, 0, 0);
-                    WND *pWnd         = (WND *)SendMessageW(hListBox, LB_GETITEMDATA, index, 0);
+                    HWND hwnd         = SendMessageW(hListBox, LB_GETITEMDATA, index, 0);
 
-                    EndDialog(hDlg, pWnd->hwndSelf);
+                    EndDialog(hDlg, hwnd);
                     return TRUE;
                 }
                 case IDCANCEL:
                     EndDialog(hDlg, 0);
                     return TRUE;
-
-                default:
-                    switch (HIWORD(wParam))
-                    {
-                        case LBN_DBLCLK:
-                        {
-                            /*  windows are sorted by menu ID, so we must return the
-                             *  window associated to the given id
-                             */
-                            HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
-                            UINT index        = SendMessageW(hListBox, LB_GETCURSEL, 0, 0);
-                            WND *pWnd         = (WND *)SendMessageW(hListBox, LB_GETITEMDATA, index, 0);
-
-                            EndDialog(hDlg, pWnd->hwndSelf);
-                            return TRUE;
-                        }
-                    }
-                    break;
            }
            break;
     }
@@ -2256,17 +2257,16 @@
 
 static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
 {
-    WND *pWnd;
+    HWND *list;
+    int i;
 
-    pWnd = WIN_FindWndPtr( GetWindow( parent, GW_CHILD ) );
-    while (pWnd)
+    if (!(list = WIN_BuildWinArray( parent ))) return;
+    for (i = 0; list[i]; i++)
     {
-        if (pWnd->wIDmenu == pos1)
-            pWnd->wIDmenu = pos2;
-        else
-            if (pWnd->wIDmenu == pos2)
-                pWnd->wIDmenu = pos1;
-        WIN_UpdateWndPtr(&pWnd,pWnd->next);
+        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 );
     }
+    WIN_ReleaseWinArray( list );
 }