[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / window.c
index ba6b6fc..861b266 100644 (file)
@@ -65,9 +65,12 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
 {
    HWND hWnd;
    UINT State, State2;
+   ULONG Error;
 
    if (!pWnd) return NULL;
 
+   Error = EngGetLastError();
+
    _SEH2_TRY
    {
       hWnd = UserHMGetHandle(pWnd);
@@ -76,6 +79,7 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
+      EngSetLastError(Error);
       _SEH2_YIELD(return NULL);
    }
    _SEH2_END
@@ -83,8 +87,9 @@ PWND FASTCALL VerifyWnd(PWND pWnd)
    if ( UserObjectInDestroy(hWnd) ||
         State & WNDS_DESTROYED ||
         State2 & WNDS2_INDESTROY )
-      return NULL;
+      pWnd = NULL;
 
+   EngSetLastError(Error);
    return pWnd;
 }
 
@@ -362,6 +367,20 @@ IntGetWindow(HWND hWnd,
     return Ret;
 }
 
+DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd )
+{
+   DWORD HelpId;
+
+   do
+   {
+      HelpId = (DWORD)(DWORD_PTR)UserGetProp(pWnd, gpsi->atomContextHelpIdProp, TRUE);
+      if (!HelpId) break;
+      pWnd = IntGetParent(pWnd);
+   }
+   while (pWnd && pWnd->fnid != FNID_DESKTOP);
+   return HelpId;
+}
+
 /***********************************************************************
  *           IntSendDestroyMsg
  */
@@ -375,8 +394,9 @@ static void IntSendDestroyMsg(HWND hWnd)
 
    if (Window)
    {
-      /* Look whether the focus is within the tree of windows we will
-       * be destroying.
+      /*
+       * Look whether the focus is within the tree of windows
+       * we will be destroying.
        */
       // Rule #1
       if ( ti->MessageQueue->spwndActive == Window || // Fixes CORE-106 RegSvr32 exit and return focus to CMD.
@@ -398,23 +418,26 @@ static void IntSendDestroyMsg(HWND hWnd)
          }
       }
 
-      if (ti->MessageQueue->CaretInfo->hWnd == UserHMGetHandle(Window))
+      if (ti->MessageQueue->CaretInfo.hWnd == UserHMGetHandle(Window))
       {
          co_IntDestroyCaret(ti);
       }
    }
 
-   /*
-    * Send the WM_DESTROY to the window.
-    */
+   /* If the window being destroyed is the current clipboard owner... */
+   if (ti->ppi->prpwinsta != NULL && Window == ti->ppi->prpwinsta->spwndClipOwner)
+   {
+       /* ... make it release the clipboard */
+       UserClipboardRelease(Window);
+   }
 
+   /* Send the WM_DESTROY to the window */
    co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
 
    /*
     * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
     * make sure that the window still exists when we come back.
     */
-
    if (IntIsWindow(hWnd))
    {
       HWND* pWndArray;
@@ -461,13 +484,12 @@ UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
 }
 
 /***********************************************************************
- *           IntDestroyWindow
+ *           co_UserFreeWindow
  *
  * Destroy storage associated to a window. "Internals" p.358
  *
- * This is the "functional" DestroyWindows function ei. all stuff
- * done in CreateWindow is undone here and not in DestroyWindow:-P
-
+ * This is the "functional" DestroyWindows function i.e. all stuff
+ * done in CreateWindow is undone here and not in DestroyWindow :-P
  */
 LRESULT co_UserFreeWindow(PWND Window,
                           PPROCESSINFO ProcessData,
@@ -484,7 +506,7 @@ LRESULT co_UserFreeWindow(PWND Window,
 
    if(Window->state2 & WNDS2_INDESTROY)
    {
-      TRACE("Tried to call IntDestroyWindow() twice\n");
+      TRACE("Tried to call co_UserFreeWindow() twice\n");
       return 0;
    }
    Window->state2 |= WNDS2_INDESTROY;
@@ -494,7 +516,7 @@ LRESULT co_UserFreeWindow(PWND Window,
 
    /* remove the window already at this point from the thread window list so we
       don't get into trouble when destroying the thread windows while we're still
-      in IntDestroyWindow() */
+      in co_UserFreeWindow() */
    RemoveEntryList(&Window->ThreadListEntry);
 
    BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
@@ -509,7 +531,7 @@ LRESULT co_UserFreeWindow(PWND Window,
       {
          if ((Child = IntGetWindowObject(*ChildHandle)))
          {
-            if(!IntWndBelongsToThread(Child, ThreadData))
+            if (!IntWndBelongsToThread(Child, ThreadData))
             {
                /* send WM_DESTROY messages to windows not belonging to the same thread */
                co_IntSendMessage( UserHMGetHandle(Child), WM_ASYNC_DESTROYWINDOW, 0, 0 );
@@ -523,7 +545,7 @@ LRESULT co_UserFreeWindow(PWND Window,
       ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
    }
 
-   if(SendMessages)
+   if (SendMessages)
    {
       /*
        * Clear the update region to make sure no WM_PAINT messages will be
@@ -532,10 +554,12 @@ LRESULT co_UserFreeWindow(PWND Window,
       co_UserRedrawWindow(Window, NULL, 0,
                           RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
                           RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
-      if(BelongsToThreadData)
+      if (BelongsToThreadData)
          co_IntSendMessage(UserHMGetHandle(Window), WM_NCDESTROY, 0, 0);
    }
 
+   UserClipboardFreeWindow(Window);
+
    DestroyTimersForWindow(ThreadData, Window);
 
    /* Unregister hot keys */
@@ -551,7 +575,7 @@ LRESULT co_UserFreeWindow(PWND Window,
    /* don't remove the WINDOWSTATUS_DESTROYING bit */
 
    /* reset shell window handles */
-   if(ThreadData->rpdesk)
+   if (ThreadData->rpdesk)
    {
       if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
          ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
@@ -578,6 +602,7 @@ LRESULT co_UserFreeWindow(PWND Window,
       MsqDecPaintCountQueue(Window->head.pti);
       if (Window->hrgnUpdate > HRGN_WINDOW && GreIsHandleValid(Window->hrgnUpdate))
       {
+         IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
          GreDeleteObject(Window->hrgnUpdate);
       }
       Window->hrgnUpdate = NULL;
@@ -593,12 +618,13 @@ LRESULT co_UserFreeWindow(PWND Window,
         Window->IDMenu &&
         (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
    {
+      TRACE("UFW: IDMenu %p\n",Window->IDMenu);
       IntDestroyMenuObject(Menu, TRUE);
       Window->IDMenu = 0;
    }
 
-   if(Window->SystemMenu
-         && (Menu = UserGetMenuObject(Window->SystemMenu)))
+   if (Window->SystemMenu
+        && (Menu = UserGetMenuObject(Window->SystemMenu)))
    {
       IntDestroyMenuObject(Menu, TRUE);
       Window->SystemMenu = (HMENU)0;
@@ -610,13 +636,13 @@ LRESULT co_UserFreeWindow(PWND Window,
 
    if (Window->PropListItems)
    {
-      IntRemoveWindowProp(Window);
+      UserRemoveWindowProps(Window);
       TRACE("Window->PropListItems %lu\n",Window->PropListItems);
       ASSERT(Window->PropListItems==0);
    }
 
    UserReferenceObject(Window);
-   UserDeleteObject(UserHMGetHandle(Window), TYPE_WINDOW);
+   UserMarkObjectDestroy(Window);
 
    IntDestroyScrollBars(Window);
 
@@ -633,7 +659,7 @@ LRESULT co_UserFreeWindow(PWND Window,
                        Window->head.pti->ppi);
    Window->pcls = NULL;
 
-   if(Window->hrgnClip)
+   if (Window->hrgnClip)
    {
       IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
       GreDeleteObject(Window->hrgnClip);
@@ -645,8 +671,7 @@ LRESULT co_UserFreeWindow(PWND Window,
    UserFreeWindowInfo(Window->head.pti, Window);
 
    UserDereferenceObject(Window);
-
-   UserClipboardFreeWindow(Window);
+   UserDeleteObject(UserHMGetHandle(Window), TYPE_WINDOW);
 
    return 0;
 }
@@ -794,77 +819,6 @@ IntSetWindowProc(PWND pWnd,
    return Ret;
 }
 
-static BOOL FASTCALL
-IntSetMenu(
-   PWND Wnd,
-   HMENU Menu,
-   BOOL *Changed)
-{
-   PMENU OldMenu, NewMenu = NULL;
-
-   if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
-   {
-      ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
-      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
-      return FALSE;
-   }
-
-   *Changed = (Wnd->IDMenu != (UINT) Menu);
-   if (! *Changed)
-   {
-      return TRUE;
-   }
-
-   if (Wnd->IDMenu)
-   {
-      OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
-      ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
-   }
-   else
-   {
-      OldMenu = NULL;
-   }
-
-   if (NULL != Menu)
-   {
-      NewMenu = IntGetMenuObject(Menu);
-      if (NULL == NewMenu)
-      {
-         if (NULL != OldMenu)
-         {
-            IntReleaseMenuObject(OldMenu);
-         }
-         EngSetLastError(ERROR_INVALID_MENU_HANDLE);
-         return FALSE;
-      }
-      if (NULL != NewMenu->hWnd)
-      {
-         /* Can't use the same menu for two windows */
-         if (NULL != OldMenu)
-         {
-            IntReleaseMenuObject(OldMenu);
-         }
-         EngSetLastError(ERROR_INVALID_MENU_HANDLE);
-         return FALSE;
-      }
-
-   }
-
-   Wnd->IDMenu = (UINT) Menu;
-   if (NULL != NewMenu)
-   {
-      NewMenu->hWnd = Wnd->head.h;
-      IntReleaseMenuObject(NewMenu);
-   }
-   if (NULL != OldMenu)
-   {
-      OldMenu->hWnd = NULL;
-      IntReleaseMenuObject(OldMenu);
-   }
-
-   return TRUE;
-}
-
 
 /* INTERNAL ******************************************************************/
 
@@ -1969,6 +1923,7 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs,
    Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
    if(!Class)
    {
+       EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
        ERR("Failed to find class %wZ\n", ClassName);
        goto cleanup;
    }
@@ -1998,9 +1953,27 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs,
     ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
     OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
 
-    /* FIXME: Is this correct? */
+    if (hWndParent && !ParentWindow)
+    {
+        ERR("Got invalid parent window handle\n");
+        goto cleanup;
+    }
+
     if(OwnerWindow)
-        OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
+    {
+       if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
+       else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
+       {
+          ERR("an owned window must be created as top-level\n");
+          EngSetLastError( STATUS_ACCESS_DENIED );
+          goto cleanup;
+       }
+       else /* owner must be a top-level window */
+       {
+          while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
+                 OwnerWindow = OwnerWindow->spwndParent;
+       }
+    }
 
    /* Fix the position and the size of the window */
    if (ParentWindow)
@@ -2432,13 +2405,16 @@ NtUserCreateWindowEx(
     NTSTATUS Status;
     LARGE_STRING lstrWindowName;
     LARGE_STRING lstrClassName;
+    LARGE_STRING lstrClsVersion;
     UNICODE_STRING ustrClassName;
+    UNICODE_STRING ustrClsVersion;
     CREATESTRUCTW Cs;
     HWND hwnd = NULL;
     PWND pwnd;
 
     lstrWindowName.Buffer = NULL;
     lstrClassName.Buffer = NULL;
+    lstrClsVersion.Buffer = NULL;
 
     ASSERT(plstrWindowName);
 
@@ -2490,6 +2466,32 @@ NtUserCreateWindowEx(
         ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
     }
 
+    /* Check if the class version is an atom */
+    if (IS_ATOM(plstrClsVersion))
+    {
+        /* It is, pass the atom in the UNICODE_STRING */
+        ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
+        ustrClsVersion.Length = 0;
+        ustrClsVersion.MaximumLength = 0;
+    }
+    else
+    {
+        /* It's not, capture the class name */
+        Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
+            /* Set last error, cleanup and return */
+            SetLastNtError(Status);
+            goto cleanup;
+        }
+
+        /* We pass it on as a UNICODE_STRING */
+        ustrClsVersion.Buffer = lstrClsVersion.Buffer;
+        ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
+        ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
+    }
+
     /* Fill the CREATESTRUCTW */
     /* we will keep here the original parameters */
     Cs.style = dwStyle;
@@ -2508,7 +2510,7 @@ NtUserCreateWindowEx(
     UserEnterExclusive();
 
     /* Call the internal function */
-    pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
+    pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer);
 
     if(!pwnd)
     {
@@ -2527,6 +2529,10 @@ cleanup:
     {
         ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
     }
+    if (lstrClsVersion.Buffer)
+    {
+        ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
+    }
 
    return hwnd;
 }
@@ -2719,7 +2725,6 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
    IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
 
    /* Send destroy messages */
-
    IntSendDestroyMsg(UserHMGetHandle(Window));
 
    if (!IntIsWindow(UserHMGetHandle(Window)))
@@ -2803,7 +2808,7 @@ IntFindWindow(PWND Parent,
          /* Do not send WM_GETTEXT messages in the kernel mode version!
             The user mode version however calls GetWindowText() which will
             send WM_GETTEXT messages to windows belonging to its processes */
-         if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
+         if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
          {
              // FIXME: LARGE_STRING truncated
              CurrentWindowName.Buffer = Child->strName.Buffer;
@@ -2887,6 +2892,7 @@ NtUserFindWindowEx(HWND hwndParent,
                if (!IntGetAtomFromStringOrAtom(&ClassName,
                                                &ClassAtom))
                {
+                   EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
                    _SEH2_LEAVE;
                }
            }
@@ -2994,7 +3000,7 @@ NtUserFindWindowEx(HWND hwndParent,
                                 (TopLevelWindow->strName.Length < 0xFFFF &&
                                  !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
                 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
-                               ClassAtom == TopLevelWindow->pcls->atomClassName;
+                               ClassAtom == TopLevelWindow->pcls->atomNVClassName;
 
                 if (WindowMatches && ClassMatches)
                 {
@@ -3016,7 +3022,7 @@ NtUserFindWindowEx(HWND hwndParent,
        }
        else
        {
-          ERR("FindWindowEx: Not Desktop Parent!\n");
+          TRACE("FindWindowEx: Not Desktop Parent!\n");
           Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
        }
 
@@ -3402,7 +3408,7 @@ HWND FASTCALL UserGetShellWindow(VOID)
    HWND Ret;
 
    NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
-                     KernelMode,
+                     UserMode,
                      0,
                      &WinStaObject,
                      0);
@@ -3452,7 +3458,7 @@ NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
    }
 
    Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
-                     KernelMode,
+                     UserMode,
                      0,
                      &WinStaObject,
                      0);
@@ -3510,6 +3516,7 @@ NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
    {
        ti->pDeskInfo->hShellWindow = hwndShell;
        ti->pDeskInfo->spwndShell = WndShell;
+       ti->pDeskInfo->spwndBkGnd = WndListView;
        ti->pDeskInfo->ppiShellProcess = ti->ppi;
    }
 
@@ -3568,7 +3575,7 @@ co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlte
                                             Ansi);
          if (!OldValue) return 0;
       }
-*/
+ */
       *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
    }
    else
@@ -3597,6 +3604,11 @@ co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlte
             else
                Style.styleNew &= ~WS_EX_WINDOWEDGE;
 
+            if (!(Window->ExStyle & WS_EX_LAYERED))
+            {
+               SetLayeredStatus(Window, 0);
+            }
+
             Window->ExStyle = (DWORD)Style.styleNew;
 
             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
@@ -3610,14 +3622,40 @@ co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlte
             if (!bAlter)
                 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
 
-           /* WS_CLIPSIBLINGS can't be reset on top-level windows */
+            /* WS_CLIPSIBLINGS can't be reset on top-level windows */
             if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
+            /* WS_MINIMIZE can't be reset */
+            if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
             /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
             if (IntCheckFrameEdge(NewValue, Window->ExStyle))
                Window->ExStyle |= WS_EX_WINDOWEDGE;
             else
                Window->ExStyle &= ~WS_EX_WINDOWEDGE;
 
+            if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+            {
+               if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
+               {
+                  //// From child to non-child it should be null already.
+                  ERR("IDMenu going null! %d\n",Window->IDMenu);
+                  Window->IDMenu = 0; // Window->spmenu = 0;
+               }
+            }
+            else
+            {
+               if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+               {
+                  PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
+                  Window->state &= ~WNDS_HASMENU;
+                  if (pMenu)
+                  {
+                     ERR("IDMenu released 0x%p\n",pMenu);
+                     // ROS may not hold a lock after setting menu to window. But it should!
+                     //IntReleaseMenuObject(pMenu);
+                  }
+               }
+            }
+
             if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
             {
                if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
@@ -3939,51 +3977,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-/*
- * @implemented
- */
-BOOL APIENTRY
-NtUserSetMenu(
-   HWND hWnd,
-   HMENU Menu,
-   BOOL Repaint)
-{
-   PWND Window;
-   BOOL Changed;
-   DECLARE_RETURN(BOOL);
-
-   TRACE("Enter NtUserSetMenu\n");
-   UserEnterExclusive();
-
-   if (!(Window = UserGetWindowObject(hWnd)))
-   {
-      RETURN( FALSE);
-   }
-
-   if (! IntSetMenu(Window, Menu, &Changed))
-   {
-      RETURN( FALSE);
-   }
-
-   if (Changed && Repaint)
-   {
-      USER_REFERENCE_ENTRY Ref;
-
-      UserRefObjectCo(Window, &Ref);
-      co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
-                            SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
-
-      UserDerefObjectCo(Window);
-   }
-
-   RETURN( TRUE);
-
-CLEANUP:
-   TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
-}
-
 /*
  * @implemented
  */
@@ -4029,6 +4022,78 @@ CLEANUP:
    END_CLEANUP;
 }
 
+BOOL APIENTRY
+DefSetText(PWND Wnd, PCWSTR WindowText)
+{
+   UNICODE_STRING UnicodeString;
+   BOOL Ret = FALSE;
+
+   RtlInitUnicodeString(&UnicodeString, WindowText);
+
+   if (UnicodeString.Length != 0)
+   {
+      if (Wnd->strName.MaximumLength > 0 &&
+          UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
+      {
+         ASSERT(Wnd->strName.Buffer != NULL);
+
+         Wnd->strName.Length = UnicodeString.Length;
+         Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+         RtlCopyMemory(Wnd->strName.Buffer,
+                              UnicodeString.Buffer,
+                              UnicodeString.Length);
+      }
+      else
+      {
+         PWCHAR buf;
+         Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
+         buf = Wnd->strName.Buffer;
+         Wnd->strName.Buffer = NULL;
+         if (buf != NULL)
+         {
+            DesktopHeapFree(Wnd->head.rpdesk, buf);
+         }
+
+         Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
+                                                   UnicodeString.Length + sizeof(UNICODE_NULL));
+         if (Wnd->strName.Buffer != NULL)
+         {
+            Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+            RtlCopyMemory(Wnd->strName.Buffer,
+                                 UnicodeString.Buffer,
+                                 UnicodeString.Length);
+            Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
+            Wnd->strName.Length = UnicodeString.Length;
+         }
+         else
+         {
+            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto Exit;
+         }
+      }
+   }
+   else
+   {
+      Wnd->strName.Length = 0;
+      if (Wnd->strName.Buffer != NULL)
+          Wnd->strName.Buffer[0] = L'\0';
+   }
+
+   // FIXME: HAX! Windows does not do this in here!
+   // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
+   // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
+   /* Send shell notifications */
+   if (!Wnd->spwndOwner && !IntGetParent(Wnd))
+   {
+      co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
+   }
+
+   Ret = TRUE;
+Exit:
+   if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
+   return Ret;
+}
+
 /*
  * NtUserDefSetText
  *