{
HWND hWnd;
UINT State, State2;
+ ULONG Error;
if (!pWnd) return NULL;
+ Error = EngGetLastError();
+
_SEH2_TRY
{
hWnd = UserHMGetHandle(pWnd);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
+ EngSetLastError(Error);
_SEH2_YIELD(return NULL);
}
_SEH2_END
if ( UserObjectInDestroy(hWnd) ||
State & WNDS_DESTROYED ||
State2 & WNDS2_INDESTROY )
- return NULL;
+ pWnd = NULL;
+ EngSetLastError(Error);
return pWnd;
}
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
*/
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.
}
}
- 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;
}
/***********************************************************************
- * 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,
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;
/* 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);
{
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 );
ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
}
- if(SendMessages)
+ if (SendMessages)
{
/*
* Clear the update region to make sure no WM_PAINT messages will be
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 */
/* 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;
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;
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;
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);
Window->head.pti->ppi);
Window->pcls = NULL;
- if(Window->hrgnClip)
+ if (Window->hrgnClip)
{
IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(Window->hrgnClip);
UserFreeWindowInfo(Window->head.pti, Window);
UserDereferenceObject(Window);
-
- UserClipboardFreeWindow(Window);
+ UserDeleteObject(UserHMGetHandle(Window), TYPE_WINDOW);
return 0;
}
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 ******************************************************************/
Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
if(!Class)
{
+ EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
ERR("Failed to find class %wZ\n", ClassName);
goto cleanup;
}
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)
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);
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;
UserEnterExclusive();
/* Call the internal function */
- pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
+ pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer);
if(!pwnd)
{
{
ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
}
+ if (lstrClsVersion.Buffer)
+ {
+ ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
+ }
return hwnd;
}
IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
/* Send destroy messages */
-
IntSendDestroyMsg(UserHMGetHandle(Window));
if (!IntIsWindow(UserHMGetHandle(Window)))
/* 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;
if (!IntGetAtomFromStringOrAtom(&ClassName,
&ClassAtom))
{
+ EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
_SEH2_LEAVE;
}
}
(TopLevelWindow->strName.Length < 0xFFFF &&
!RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
- ClassAtom == TopLevelWindow->pcls->atomClassName;
+ ClassAtom == TopLevelWindow->pcls->atomNVClassName;
if (WindowMatches && ClassMatches)
{
}
else
{
- ERR("FindWindowEx: Not Desktop Parent!\n");
+ TRACE("FindWindowEx: Not Desktop Parent!\n");
Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
}
HWND Ret;
NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
+ UserMode,
0,
&WinStaObject,
0);
}
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
+ UserMode,
0,
&WinStaObject,
0);
{
ti->pDeskInfo->hShellWindow = hwndShell;
ti->pDeskInfo->spwndShell = WndShell;
+ ti->pDeskInfo->spwndBkGnd = WndListView;
ti->pDeskInfo->ppiShellProcess = ti->ppi;
}
Ansi);
if (!OldValue) return 0;
}
-*/
+ */
*((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
}
else
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);
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--;
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
*/
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
*