[WIN32SS][USER32] Ghost is a hung window (#1244)
[reactos.git] / win32ss / user / user32 / windows / window.c
index a260807..4485c24 100644 (file)
@@ -1,22 +1,21 @@
 /*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
- * FILE:            lib/user32/windows/window.c
+ * FILE:            win32ss/user/user32/windows/window.c
  * PURPOSE:         Window management
- * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
  * UPDATE HISTORY:
  *      06-06-2001  CSH  Created
  */
 
-/* INCLUDES ******************************************************************/
 #define DEBUG
 #include <user32.h>
 
-#include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(user32);
 
-LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active);
 void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id );
+extern LPCWSTR FASTCALL ClassNameToVersion(const void *lpszClass, LPCWSTR lpszMenuName, LPCWSTR *plpLibFileName, HANDLE *pContext, BOOL bAnsi);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -80,9 +79,9 @@ BringWindowToTop(HWND hWnd)
 
 
 VOID WINAPI
-SwitchToThisWindow(HWND hwnd, BOOL fUnknown)
+SwitchToThisWindow(HWND hwnd, BOOL fAltTab)
 {
-    ShowWindow(hwnd, SW_SHOW);
+    NtUserxSwitchToThisWindow(hwnd, fAltTab);
 }
 
 
@@ -115,13 +114,13 @@ ChildWindowFromPointEx(HWND hwndParent,
 BOOL WINAPI
 CloseWindow(HWND hWnd)
 {
-    SendMessageA(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
-
-    return HandleToUlong(hWnd);
+    /* NOTE: CloseWindow does minimizes, and doesn't close. */
+    SetActiveWindow(hWnd);
+    return ShowWindow(hWnd, SW_SHOWMINIMIZED);
 }
 
-VOID
 FORCEINLINE
+VOID
 RtlInitLargeString(
     OUT PLARGE_STRING plstr,
     LPCVOID psz,
@@ -166,11 +165,18 @@ User32CreateWindowEx(DWORD dwExStyle,
 {
     LARGE_STRING WindowName;
     LARGE_STRING lstrClassName, *plstrClassName;
+    LARGE_STRING lstrClassVersion, *plstrClassVersion;
     UNICODE_STRING ClassName;
+    UNICODE_STRING ClassVersion;
     WNDCLASSEXA wceA;
     WNDCLASSEXW wceW;
-    BOOL Unicode;
+    HMODULE hLibModule = NULL;
+    DWORD dwLastError;
+    BOOL Unicode, ClassFound = FALSE;
     HWND Handle = NULL;
+    LPCWSTR lpszClsVersion;
+    LPCWSTR lpLibFileName = NULL;
+    HANDLE pCtx = NULL;
 
 #if 0
     DbgPrint("[window] User32CreateWindowEx style %d, exstyle %d, parent %d\n", dwStyle, dwExStyle, hWndParent);
@@ -178,8 +184,8 @@ User32CreateWindowEx(DWORD dwExStyle,
 
     if (!RegisterDefaultClasses)
     {
-       ERR("User32CreateWindowEx RegisterSystemControls\n");
-       RegisterSystemControls();
+        TRACE("RegisterSystemControls\n");
+        RegisterSystemControls();
     }
 
     Unicode = !(dwFlags & NUCWE_ANSI);
@@ -190,17 +196,19 @@ User32CreateWindowEx(DWORD dwExStyle,
     }
     else
     {
-        if(Unicode)
+        if (Unicode)
+        {
             RtlInitUnicodeString(&ClassName, (PCWSTR)lpClassName);
+        }
         else
         {
             if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, (PCSZ)lpClassName))
             {
                 SetLastError(ERROR_OUTOFMEMORY);
-                return (HWND)0;
+                return NULL;
             }
         }
-        
+
         /* Copy it to a LARGE_STRING */
         lstrClassName.Buffer = ClassName.Buffer;
         lstrClassName.Length = ClassName.Length;
@@ -217,7 +225,7 @@ User32CreateWindowEx(DWORD dwExStyle,
         NTSTATUS Status;
         PSTR AnsiBuffer = WindowName.Buffer;
         ULONG AnsiLength = WindowName.Length;
-        
+
         WindowName.Length = 0;
         WindowName.MaximumLength = AnsiLength * sizeof(WCHAR);
         WindowName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
@@ -240,20 +248,20 @@ User32CreateWindowEx(DWORD dwExStyle,
         }
     }
 
-    if(!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))
+    if (!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))
     {
-        if(Unicode)
+        if (Unicode)
         {
-            wceW.cbSize = sizeof(WNDCLASSEXW);
-            if(GetClassInfoExW(hInstance, (LPCWSTR)lpClassName, &wceW) && wceW.lpszMenuName)
+            wceW.cbSize = sizeof(wceW);
+            if (GetClassInfoExW(hInstance, (LPCWSTR)lpClassName, &wceW) && wceW.lpszMenuName)
             {
                 hMenu = LoadMenuW(hInstance, wceW.lpszMenuName);
             }
         }
         else
         {
-            wceA.cbSize = sizeof(WNDCLASSEXA);
-            if(GetClassInfoExA(hInstance, lpClassName, &wceA) && wceA.lpszMenuName)
+            wceA.cbSize = sizeof(wceA);
+            if (GetClassInfoExA(hInstance, lpClassName, &wceA) && wceA.lpszMenuName)
             {
                 hMenu = LoadMenuA(hInstance, wceA.lpszMenuName);
             }
@@ -262,33 +270,68 @@ User32CreateWindowEx(DWORD dwExStyle,
 
     if (!Unicode) dwExStyle |= WS_EX_SETANSICREATOR;
 
-    Handle = NtUserCreateWindowEx(dwExStyle,
-                                  plstrClassName,
-                                  NULL,
-                                  &WindowName,
-                                  dwStyle,
-                                  x,
-                                  y,
-                                  nWidth,
-                                  nHeight,
-                                  hWndParent,
-                                  hMenu,
-                                  hInstance,
-                                  lpParam,
-                                  dwFlags,
-                                  NULL);
+    lpszClsVersion = ClassNameToVersion(lpClassName, NULL, &lpLibFileName, &pCtx, !Unicode);
+    if (!lpszClsVersion)
+    {
+        plstrClassVersion = plstrClassName;
+    }
+    else
+    {
+        RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
+        lstrClassVersion.Buffer = ClassVersion.Buffer;
+        lstrClassVersion.Length = ClassVersion.Length;
+        lstrClassVersion.MaximumLength = ClassVersion.MaximumLength;
+        plstrClassVersion = &lstrClassVersion;
+    }
+
+    for (;;)
+    {
+        Handle = NtUserCreateWindowEx(dwExStyle,
+                                      plstrClassName,
+                                      plstrClassVersion,
+                                      &WindowName,
+                                      dwStyle,
+                                      x,
+                                      y,
+                                      nWidth,
+                                      nHeight,
+                                      hWndParent,
+                                      hMenu,
+                                      hInstance,
+                                      lpParam,
+                                      dwFlags,
+                                      NULL);
+        if (Handle) break;
+        if (!lpLibFileName) break;
+        if (!ClassFound)
+        {
+            dwLastError = GetLastError();
+            if (dwLastError == ERROR_CANNOT_FIND_WND_CLASS)
+            {
+                ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
+                if (ClassFound) continue;
+            }
+        }
+        if (hLibModule)
+        {
+            dwLastError = GetLastError();
+            FreeLibrary(hLibModule);
+            SetLastError(dwLastError);
+            hLibModule = NULL;
+        }
+        break;
+    }
 
 #if 0
     DbgPrint("[window] NtUserCreateWindowEx() == %d\n", Handle);
 #endif
+
 cleanup:
-    if(!Unicode)
+    if (!Unicode)
     {
         if (!IS_ATOM(lpClassName))
-        {
             RtlFreeUnicodeString(&ClassName);
-        }
-        
+
         RtlFreeLargeString(&WindowName);
     }
 
@@ -299,7 +342,9 @@ cleanup:
 /*
  * @implemented
  */
-HWND WINAPI
+HWND
+WINAPI
+DECLSPEC_HOTPATCH
 CreateWindowExA(DWORD dwExStyle,
                 LPCSTR lpClassName,
                 LPCSTR lpWindowName,
@@ -318,7 +363,7 @@ CreateWindowExA(DWORD dwExStyle,
 
     if (!RegisterDefaultClasses)
     {
-       ERR("CreateWindowExA RegisterSystemControls\n");
+       TRACE("CreateWindowExA RegisterSystemControls\n");
        RegisterSystemControls();
     }
 
@@ -422,7 +467,9 @@ CreateWindowExA(DWORD dwExStyle,
 /*
  * @implemented
  */
-HWND WINAPI
+HWND
+WINAPI
+DECLSPEC_HOTPATCH
 CreateWindowExW(DWORD dwExStyle,
                 LPCWSTR lpClassName,
                 LPCWSTR lpWindowName,
@@ -461,7 +508,7 @@ CreateWindowExW(DWORD dwExStyle,
            WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", hWndParent);
            return NULL;
         }
-        
+
         /* lpParams of WM_[NC]CREATE is different for MDI children.
         * MDICREATESTRUCT members have the originally passed values.
         */
@@ -526,8 +573,8 @@ CreateWindowExW(DWORD dwExStyle,
     }
 
     hwnd = User32CreateWindowEx(dwExStyle,
-                                (LPCSTR) lpClassName,
-                                (LPCSTR) lpWindowName,
+                                (LPCSTR)lpClassName,
+                                (LPCSTR)lpWindowName,
                                 dwStyle,
                                 x,
                                 y,
@@ -626,6 +673,14 @@ User32EnumWindows(HDESK hDesktop,
     if (!NT_SUCCESS(Status))
         return FALSE;
 
+    if (!dwCount)
+    {
+       if (!dwThreadId)
+          return FALSE;
+       else
+          return TRUE;
+    }
+
     /* allocate buffer to receive HWND handles */
     hHeap = GetProcessHeap();
     pHwnd = HeapAlloc(hHeap, 0, sizeof(HWND)*(dwCount+1));
@@ -650,14 +705,6 @@ User32EnumWindows(HDESK hDesktop,
         return FALSE;
     }
 
-    if (!dwCount)
-    {
-       if (!dwThreadId)
-          return FALSE; 
-       else
-          return TRUE;
-    }
-
     /* call the user's callback function until we're done or
        they tell us to quit */
     for ( i = 0; i < dwCount; i++ )
@@ -665,7 +712,7 @@ User32EnumWindows(HDESK hDesktop,
         /* FIXME I'm only getting NULLs from Thread Enumeration, and it's
          * probably because I'm not doing it right in NtUserBuildHwndList.
          * Once that's fixed, we shouldn't have to check for a NULL HWND
-         * here 
+         * here
          * This is now fixed in revision 50205. (jt)
          */
         if (!pHwnd[i]) /* don't enumerate a NULL HWND */
@@ -845,7 +892,7 @@ FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName)
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL WINAPI
 GetAltTabInfoA(HWND hwnd,
@@ -854,13 +901,12 @@ GetAltTabInfoA(HWND hwnd,
                LPSTR pszItemText,
                UINT cchItemText)
 {
-    UNIMPLEMENTED;
-    return FALSE;
+    return NtUserGetAltTabInfo(hwnd,iItem,pati,(LPWSTR)pszItemText,cchItemText,TRUE);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL WINAPI
 GetAltTabInfoW(HWND hwnd,
@@ -869,8 +915,7 @@ GetAltTabInfoW(HWND hwnd,
                LPWSTR pszItemText,
                UINT cchItemText)
 {
-    UNIMPLEMENTED;
-    return FALSE;
+    return NtUserGetAltTabInfo(hwnd,iItem,pati,pszItemText,cchItemText,FALSE);
 }
 
 
@@ -882,7 +927,7 @@ GetAncestor(HWND hwnd, UINT gaFlags)
 {
     HWND Ret = NULL;
     PWND Ancestor, Wnd;
-    
+
     Wnd = ValidateHwnd(hwnd);
     if (!Wnd)
         return NULL;
@@ -935,7 +980,7 @@ GetClientRect(HWND hWnd, LPRECT lpRect)
        lpRect->bottom = GetSystemMetrics(SM_CYMINIMIZED);
        return TRUE;
     }
-    if ( hWnd != GetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP ) 
+    if ( hWnd != GetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
     {
 /*        lpRect->left = lpRect->top = 0;
         lpRect->right = Wnd->rcClient.right - Wnd->rcClient.left;
@@ -952,7 +997,7 @@ GetClientRect(HWND hWnd, LPRECT lpRect)
 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
         lpRect->right = GetSystemMetrics(SM_CXSCREEN);
         lpRect->bottom = GetSystemMetrics(SM_CYSCREEN);
-*/    } 
+*/    }
     return TRUE;
 }
 
@@ -1078,7 +1123,7 @@ GetWindow(HWND hWnd,
                 if (Wnd->spwndPrev != NULL)
                     FoundWnd = DesktopPtrToUser(Wnd->spwndPrev);
                 break;
-   
+
             case GW_CHILD:
                 if (Wnd->spwndChild != NULL)
                     FoundWnd = DesktopPtrToUser(Wnd->spwndChild);
@@ -1122,7 +1167,9 @@ GetTopWindow(HWND hWnd)
 /*
  * @implemented
  */
-BOOL WINAPI
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
 GetWindowInfo(HWND hWnd,
               PWINDOWINFO pwi)
 {
@@ -1150,7 +1197,7 @@ GetWindowInfo(HWND hWnd,
        pwi->cxWindowBorders = Size.cx;
        pwi->cyWindowBorders = Size.cy;
        pwi->dwWindowStatus = 0;
-       if (pWnd->state & WNDS_ACTIVEFRAME)
+       if (pWnd->state & WNDS_ACTIVEFRAME || (GetActiveWindow() == hWnd))
           pwi->dwWindowStatus = WS_ACTIVECAPTION;
        pwi->atomWindowType = (pCls ? pCls->atomClassName : 0 );
 
@@ -1216,7 +1263,6 @@ GetWindowModuleFileNameW(HWND hwnd,
     return GetModuleFileNameW( Wnd->hModule, lpszFileName, cchFileNameMax );
 }
 
-
 /*
  * @implemented
  */
@@ -1243,7 +1289,6 @@ GetWindowRect(HWND hWnd,
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
@@ -1251,78 +1296,58 @@ int WINAPI
 GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
 {
     PWND Wnd;
-    PCWSTR Buffer;
     INT Length = 0;
 
-    if (lpString == NULL)
+    if (lpString == NULL || nMaxCount == 0)
         return 0;
 
     Wnd = ValidateHwnd(hWnd);
     if (!Wnd)
         return 0;
 
-    _SEH2_TRY
+    lpString[0] = '\0';
+
+    if (!TestWindowProcess(Wnd))
     {
-        if (!TestWindowProcess( Wnd))
+        _SEH2_TRY
         {
-            if (nMaxCount > 0)
-            {
-                /* do not send WM_GETTEXT messages to other processes */
-                Length = Wnd->strName.Length / sizeof(WCHAR);
-                if (Length != 0)
-                {
-                    Buffer = DesktopPtrToUser(Wnd->strName.Buffer);
-                    if (Buffer != NULL)
-                    {
-                        if (!WideCharToMultiByte(CP_ACP,
-                                               0,
-                                               Buffer,
-                                               Length + 1,
-                                               lpString,
-                                               nMaxCount,
-                                               NULL,
-                                               NULL))
-                        {
-                            lpString[nMaxCount - 1] = '\0';
-                        }
-                    }
-                    else
-                    {
-                        Length = 0;
-                        lpString[0] = '\0';
-                    }
-                }
-                else
-                    lpString[0] = '\0';
-            }
-
-            Wnd = NULL; /* Don't send a message */
+            Length = DefWindowProcA(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
         }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Length = 0;
+        }
+        _SEH2_END;
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    else
     {
-        lpString[0] = '\0';
-        Length = 0;
-        Wnd = NULL; /* Don't send a message */
-    }
-    _SEH2_END;
-
-    if (Wnd != NULL)
         Length = SendMessageA(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
-
+    }
+    //ERR("GWTA Len %d : %s\n",Length,lpString);
     return Length;
 }
 
-
 /*
  * @implemented
  */
 int WINAPI
 GetWindowTextLengthA(HWND hWnd)
 {
-    return(SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0));
-}
+    PWND Wnd;
+
+    Wnd = ValidateHwnd(hWnd);
+    if (!Wnd)
+        return 0;
 
+    if (!TestWindowProcess(Wnd))
+    {
+        return DefWindowProcA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+    }
+    else
+    {
+        return SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+    }
+}
 
 /*
  * @implemented
@@ -1330,9 +1355,21 @@ GetWindowTextLengthA(HWND hWnd)
 int WINAPI
 GetWindowTextLengthW(HWND hWnd)
 {
-    return(SendMessageW(hWnd, WM_GETTEXTLENGTH, 0, 0));
-}
+    PWND Wnd;
 
+    Wnd = ValidateHwnd(hWnd);
+    if (!Wnd)
+        return 0;
+
+    if (!TestWindowProcess(Wnd))
+    {
+        return DefWindowProcW(hWnd, WM_GETTEXTLENGTH, 0, 0);
+    }
+    else
+    {
+        return SendMessageW(hWnd, WM_GETTEXTLENGTH, 0, 0);
+    }
+}
 
 /*
  * @implemented
@@ -1341,57 +1378,34 @@ int WINAPI
 GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount)
 {
     PWND Wnd;
-    PCWSTR Buffer;
     INT Length = 0;
 
-    if (lpString == NULL)
+    if (lpString == NULL || nMaxCount == 0)
         return 0;
 
     Wnd = ValidateHwnd(hWnd);
     if (!Wnd)
         return 0;
 
-    _SEH2_TRY
+    lpString[0] = L'\0';
+
+    if (!TestWindowProcess(Wnd))
     {
-        if (!TestWindowProcess( Wnd))
+        _SEH2_TRY
         {
-            if (nMaxCount > 0)
-            {
-                /* do not send WM_GETTEXT messages to other processes */
-                Length = Wnd->strName.Length / sizeof(WCHAR);
-                if (Length != 0)
-                {
-                    Buffer = DesktopPtrToUser(Wnd->strName.Buffer);
-                    if (Buffer != NULL)
-                    {
-                        RtlCopyMemory(lpString,
-                                      Buffer,
-                                      (Length + 1) * sizeof(WCHAR));
-                    }
-                    else
-                    {
-                        Length = 0;
-                        lpString[0] = '\0';
-                    }
-                }
-                else
-                    lpString[0] = '\0';
-            }
-
-            Wnd = NULL; /* Don't send a message */
+            Length = DefWindowProcW(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Length = 0;
         }
+        _SEH2_END;
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    else
     {
-        lpString[0] = '\0';
-        Length = 0;
-        Wnd = NULL; /* Don't send a message */
-    }
-    _SEH2_END;
-
-    if (Wnd != NULL)
         Length = SendMessageW(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
-
+    }
+    //ERR("GWTW Len %d : %S\n",Length,lpString);
     return Length;
 }
 
@@ -1406,7 +1420,7 @@ GetWindowThreadProcessId(HWND hWnd,
     if (!pWnd) return Ret;
 
     ti = pWnd->head.pti;
+
     if (ti)
     {
         if (ti == GetW32ThreadInfo())
@@ -1678,7 +1692,9 @@ return NtUserCallOneParam( (DWORD_PTR)dwDefaultLayout, ONEPARAM_ROUTINE_SETPROCD
 /*
  * @implemented
  */
-BOOL WINAPI
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
 SetWindowTextA(HWND hWnd,
                LPCSTR lpString)
 {
@@ -1701,7 +1717,9 @@ SetWindowTextA(HWND hWnd,
 /*
  * @implemented
  */
-BOOL WINAPI
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
 SetWindowTextW(HWND hWnd,
                LPCWSTR lpString)
 {
@@ -1745,8 +1763,11 @@ UpdateLayeredWindow( HWND hwnd,
                      BLENDFUNCTION *pbl,
                      DWORD dwFlags)
 {
-  if ( dwFlags & ULW_EX_NORESIZE)
-     dwFlags = ~(ULW_EX_NORESIZE|ULW_OPAQUE|ULW_ALPHA|ULW_COLORKEY);
+  if (dwFlags & ULW_EX_NORESIZE)  /* only valid for UpdateLayeredWindowIndirect */
+  {
+     SetLastError( ERROR_INVALID_PARAMETER );
+     return FALSE;
+  }
   return NtUserUpdateLayeredWindow( hwnd,
                                     hdcDst,
                                     pptDst,
@@ -1809,7 +1830,7 @@ int WINAPI
 InternalGetWindowText(HWND hWnd, LPWSTR lpString, int nMaxCount)
 {
     INT Ret = NtUserInternalGetWindowText(hWnd, lpString, nMaxCount);
-    if (Ret == 0)
+    if (Ret == 0 && lpString)
         *lpString = L'\0';
     return Ret;
 }
@@ -1820,6 +1841,18 @@ InternalGetWindowText(HWND hWnd, LPWSTR lpString, int nMaxCount)
 BOOL WINAPI
 IsHungAppWindow(HWND hwnd)
 {
+    UNICODE_STRING ClassName;
+    WCHAR szClass[16];
+    static const UNICODE_STRING GhostClass = RTL_CONSTANT_STRING(L"Ghost");
+
+    /* Ghost is a hung window */
+    RtlInitEmptyUnicodeString(&ClassName, szClass, sizeof(szClass));
+    if (NtUserGetClassName(hwnd, FALSE, &ClassName) &&
+        RtlEqualUnicodeString(&ClassName, &GhostClass, TRUE))
+    {
+        return TRUE;
+    }
+
     return (NtUserQueryWindow(hwnd, QUERY_WINDOW_ISHUNG) != 0);
 }