From ed47eaa79aca57a88569845b2de4d7b4f553fb60 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sat, 11 Dec 2004 19:39:18 +0000 Subject: [PATCH] 1. don't dispatch sent messages to windows during destruction 2. fixed class lookup in a hacky way (get's rewritten soon anyway) svn path=/trunk/; revision=12026 --- reactos/subsys/win32k/include/class.h | 1 + reactos/subsys/win32k/include/msgqueue.h | 1 + reactos/subsys/win32k/ntuser/class.c | 43 +++++++++---- reactos/subsys/win32k/ntuser/message.c | 22 ++++++- reactos/subsys/win32k/ntuser/msgqueue.c | 82 +++++++++++++++++++++++- reactos/subsys/win32k/ntuser/window.c | 64 ++++++------------ reactos/subsys/win32k/ntuser/winpos.c | 5 +- 7 files changed, 157 insertions(+), 61 deletions(-) diff --git a/reactos/subsys/win32k/include/class.h b/reactos/subsys/win32k/include/class.h index 527b50fc2d7..d532003c41d 100644 --- a/reactos/subsys/win32k/include/class.h +++ b/reactos/subsys/win32k/include/class.h @@ -27,6 +27,7 @@ typedef struct _WNDCLASS_OBJECT BOOL Unicode; BOOL Global; LIST_ENTRY ListEntry; + LIST_ENTRY GlobalListEntry; /* HACK!!! */ PCHAR ExtraData; /* list of windows */ FAST_MUTEX ClassWindowsListLock; diff --git a/reactos/subsys/win32k/include/msgqueue.h b/reactos/subsys/win32k/include/msgqueue.h index a90c5a4dea9..b6fd84087d9 100644 --- a/reactos/subsys/win32k/include/msgqueue.h +++ b/reactos/subsys/win32k/include/msgqueue.h @@ -203,6 +203,7 @@ VOID FASTCALL MsqSetHooks(PUSER_MESSAGE_QUEUE Queue, PHOOKTABLE Hooks); LPARAM FASTCALL MsqSetMessageExtraInfo(LPARAM lParam); LPARAM FASTCALL MsqGetMessageExtraInfo(VOID); +VOID STDCALL MsqRemoveWindowMessagesFromQueue(PVOID pWindow); /* F*(&$ headers, will be gone in the rewrite! */ #define IntLockMessageQueue(MsgQueue) \ ExAcquireFastMutex(&(MsgQueue)->Lock) diff --git a/reactos/subsys/win32k/ntuser/class.c b/reactos/subsys/win32k/ntuser/class.c index 030bb379e5f..6056ce743ce 100644 --- a/reactos/subsys/win32k/ntuser/class.c +++ b/reactos/subsys/win32k/ntuser/class.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: class.c,v 1.60 2004/11/20 16:46:06 weiden Exp $ +/* $Id: class.c,v 1.61 2004/12/11 19:39:18 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -33,11 +33,22 @@ #define NDEBUG #include +/* FIXME: Just a bad hack for now... */ +LIST_ENTRY GlobalClassListHead; +FAST_MUTEX GlobalClassListLock; +#define IntLockGlobalClassList() \ + ExAcquireFastMutex(&GlobalClassListLock) +#define IntUnlockGlobalClassList() \ + ExReleaseFastMutex(&GlobalClassListLock) + + /* FUNCTIONS *****************************************************************/ NTSTATUS FASTCALL InitClassImpl(VOID) { + ExInitializeFastMutex(&GlobalClassListLock); + InitializeListHead(&GlobalClassListHead); return(STATUS_SUCCESS); } @@ -55,19 +66,19 @@ ClassReferenceClassByAtom( { PWNDCLASS_OBJECT Current, BestMatch = NULL; PLIST_ENTRY CurrentEntry; - PW32PROCESS Process = PsGetWin32Process(); - IntLockProcessClasses(Process); - CurrentEntry = Process->ClassListHead.Flink; - while (CurrentEntry != &Process->ClassListHead) + /* HACK!! */ + IntLockGlobalClassList(); + CurrentEntry = GlobalClassListHead.Flink; + while (CurrentEntry != &GlobalClassListHead) { - Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry); + Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, GlobalListEntry); if (Current->Atom == Atom && (hInstance == NULL || Current->hInstance == hInstance)) { *Class = Current; ObmReferenceObject(Current); - IntUnLockProcessClasses(Process); + IntUnlockGlobalClassList(); return TRUE; } @@ -76,7 +87,7 @@ ClassReferenceClassByAtom( CurrentEntry = CurrentEntry->Flink; } - IntUnLockProcessClasses(Process); + IntUnlockGlobalClassList(); if (BestMatch != NULL) { @@ -111,6 +122,7 @@ ClassReferenceClassByName( if (!NT_SUCCESS(Status)) { + DPRINT1("Failed to lookup class atom!\n"); return FALSE; } @@ -413,16 +425,16 @@ NtUserRegisterClassExWOW( WinStaObject = PsGetWin32Thread()->Desktop->WindowStation; - if (ClassName->Length) + if (ClassName->Length > 0) { - DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer); + DPRINT1("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer); /* FIXME - Safely copy/verify the buffer first!!! */ Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable, ClassName->Buffer, &Atom); if (!NT_SUCCESS(Status)) { - DPRINT("Failed adding class name (%S) to atom table\n", + DPRINT1("Failed adding class name (%S) to atom table\n", ClassName->Buffer); SetLastNtError(Status); return((RTL_ATOM)0); @@ -445,6 +457,11 @@ NtUserRegisterClassExWOW( IntLockProcessClasses(PsGetWin32Process()); InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry); IntUnLockProcessClasses(PsGetWin32Process()); + + /* HACK!!! */ + IntLockGlobalClassList(); + InsertTailList(&GlobalClassListHead, &ClassObject->GlobalListEntry); + IntUnlockGlobalClassList(); return(Atom); } @@ -681,6 +698,10 @@ NtUserUnregisterClass( ClassDereferenceObject(Class); RemoveEntryList(&Class->ListEntry); + + IntLockGlobalClassList(); + RemoveEntryList(&Class->GlobalListEntry); + IntUnlockGlobalClassList(); RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Class->Atom); diff --git a/reactos/subsys/win32k/ntuser/message.c b/reactos/subsys/win32k/ntuser/message.c index 725dba03518..7f5ea4fe9f1 100644 --- a/reactos/subsys/win32k/ntuser/message.c +++ b/reactos/subsys/win32k/ntuser/message.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: message.c,v 1.75 2004/11/20 16:46:06 weiden Exp $ +/* $Id: message.c,v 1.76 2004/12/11 19:39:18 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -519,7 +519,10 @@ IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *Hit { /* post the message to the other window */ Msg->hwnd = Wnd->Self; - MsqPostMessage(Wnd->MessageQueue, Msg, FALSE); + if(!(Wnd->Status & WINDOWSTATUS_DESTROYING)) + { + MsqPostMessage(Wnd->MessageQueue, Msg, FALSE); + } /* eat the message */ IntReleaseWindowObject(Wnd); @@ -1114,6 +1117,13 @@ NtUserPostMessage(HWND Wnd, SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE); return FALSE; } + if(Window->Status & WINDOWSTATUS_DESTROYING) + { + IntReleaseWindowObject(Window); + DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd); + /* FIXME - last error code? */ + return FALSE; + } UserModeMsg.hwnd = Wnd; UserModeMsg.message = Msg; @@ -1293,6 +1303,14 @@ IntSendMessageTimeoutSingle(HWND hWnd, return FALSE; } + if(Window->Status & WINDOWSTATUS_DESTROYING) + { + IntReleaseWindowObject(Window); + /* FIXME - last error? */ + DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd); + return FALSE; + } + Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam, uTimeout, (uFlags & SMTO_BLOCK), uResult); IntReleaseWindowObject(Window); diff --git a/reactos/subsys/win32k/ntuser/msgqueue.c b/reactos/subsys/win32k/ntuser/msgqueue.c index 769722c58dd..2efccbffe3a 100644 --- a/reactos/subsys/win32k/ntuser/msgqueue.c +++ b/reactos/subsys/win32k/ntuser/msgqueue.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: msgqueue.c,v 1.109 2004/12/10 22:40:29 weiden Exp $ +/* $Id: msgqueue.c,v 1.110 2004/12/11 19:39:18 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -809,6 +809,84 @@ Notified: return(TRUE); } +VOID STDCALL +MsqRemoveWindowMessagesFromQueue(PVOID pWindow) +{ + PUSER_SENT_MESSAGE SentMessage; + PUSER_MESSAGE PostedMessage; + PUSER_MESSAGE_QUEUE MessageQueue; + PLIST_ENTRY CurrentEntry, ListHead; + PWINDOW_OBJECT Window = pWindow; + + ASSERT(Window); + + MessageQueue = Window->MessageQueue; + ASSERT(MessageQueue); + + IntLockMessageQueue(MessageQueue); + + /* remove the posted messages for this window */ + CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; + ListHead = &MessageQueue->PostedMessagesListHead; + while (CurrentEntry != ListHead) + { + PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, + ListEntry); + if (PostedMessage->Msg.hwnd == Window->Self) + { + RemoveEntryList(&PostedMessage->ListEntry); + MsqDestroyMessage(PostedMessage); + CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; + } + else + { + CurrentEntry = CurrentEntry->Flink; + } + } + + /* remove the sent messages for this window */ + CurrentEntry = MessageQueue->SentMessagesListHead.Flink; + ListHead = &MessageQueue->SentMessagesListHead; + while (CurrentEntry != ListHead) + { + CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead); + SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, + ListEntry); + if(SentMessage->Msg.hwnd == Window->Self) + { + IntLockMessageQueue(SentMessage->SenderQueue); + DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n"); + + /* remove the message from the dispatching list */ + if(SentMessage->DispatchingListEntry.Flink != NULL) + { + RemoveEntryList(&SentMessage->DispatchingListEntry); + } + + /* wake the sender's thread */ + if (SentMessage->CompletionEvent != NULL) + { + KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE); + } + IntUnLockMessageQueue(SentMessage->SenderQueue); + + /* dereference our and the sender's message queue */ + IntDereferenceMessageQueue(MessageQueue); + IntDereferenceMessageQueue(SentMessage->SenderQueue); + + /* free the message */ + ExFreePool(SentMessage); + + CurrentEntry = MessageQueue->SentMessagesListHead.Flink; + } + else + { + CurrentEntry = CurrentEntry->Flink; + } + } + IntUnLockMessageQueue(MessageQueue); +} + VOID FASTCALL MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue, PUSER_SENT_MESSAGE_NOTIFY NotifyMessage) @@ -1138,6 +1216,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry); + IntLockMessageQueue(CurrentSentMessage->SenderQueue); DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n"); /* remove the message from the dispatching list */ @@ -1151,6 +1230,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) { KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE); } + IntUnLockMessageQueue(CurrentSentMessage->SenderQueue); /* dereference our and the sender's message queue */ IntDereferenceMessageQueue(MessageQueue); diff --git a/reactos/subsys/win32k/ntuser/window.c b/reactos/subsys/win32k/ntuser/window.c index 7f6bb77506f..9a4416e0295 100644 --- a/reactos/subsys/win32k/ntuser/window.c +++ b/reactos/subsys/win32k/ntuser/window.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: window.c,v 1.250 2004/11/20 19:08:37 weiden Exp $ +/* $Id: window.c,v 1.251 2004/12/11 19:39:18 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -278,6 +278,7 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window, return 0; } Window->Status |= WINDOWSTATUS_DESTROYING; + Window->Flags &= ~WS_VISIBLE; /* 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() */ @@ -290,7 +291,18 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window, { /* Send destroy messages */ IntSendDestroyMsg(Window->Self); + if(BelongsToThreadData) + IntSendMessage(Window->Self, WM_NCDESTROY, 0, 0); } + + /* from now on no messages can be sent to this window anymore */ + IntLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread); + Window->Status |= WINDOWSTATUS_DESTROYED; + /* don't remove the WINDOWSTATUS_DESTROYING bit */ + IntUnLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread); + + /* flush the message queue */ + MsqRemoveWindowMessagesFromQueue(Window); /* free child windows */ Children = IntWinListChildren(Window); @@ -313,23 +325,6 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window, ExFreePool(Children); } - if (SendMessages) - { - /* - * Clear the update region to make sure no WM_PAINT messages will be - * generated for this window while processing the WM_NCDESTROY. - */ - IntRedrawWindow(Window, NULL, 0, - RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | - RDW_NOINTERNALPAINT | RDW_NOCHILDREN); - - /* - * Send the WM_NCDESTROY to the window being destroyed. - */ - if(BelongsToThreadData) - IntSendMessage(Window->Self, WM_NCDESTROY, 0, 0); - } - /* reset shell window handles */ if(ThreadData->Desktop) { @@ -385,11 +380,6 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window, IntDestroyScrollBars(Window); - IntLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread); - Window->Status |= WINDOWSTATUS_DESTROYED; - /* don't remove the WINDOWSTATUS_DESTROYING bit */ - IntUnLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread); - /* remove the window from the class object */ IntLockClassWindows(Window->Class); RemoveEntryList(&Window->ClassListEntry); @@ -1403,7 +1393,6 @@ IntCreateWindowEx(DWORD dwExStyle, HWND ParentWindowHandle; HWND OwnerWindowHandle; PMENU_OBJECT SystemMenu; - NTSTATUS Status; HANDLE Handle; POINT Pos; SIZE Size; @@ -1417,7 +1406,6 @@ IntCreateWindowEx(DWORD dwExStyle, LRESULT Result; BOOL MenuChanged; BOOL ClassFound; - PWSTR ClassNameString; ParentWindowHandle = PsGetWin32Thread()->Desktop->DesktopWindow; OwnerWindowHandle = NULL; @@ -1454,24 +1442,7 @@ IntCreateWindowEx(DWORD dwExStyle, /* FIXME: parent must belong to the current process */ /* Check the class. */ - if (IS_ATOM(ClassName->Buffer)) - { - ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName->Buffer, hInstance); - } - else - { - Status = IntUnicodeStringToNULLTerminated(&ClassNameString, ClassName); - if (! NT_SUCCESS(Status)) - { - if (NULL != ParentWindow) - { - IntReleaseWindowObject(ParentWindow); - } - return NULL; - } - ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassNameString, hInstance); - IntFreeNULLTerminatedFromUnicodeString(ClassNameString, ClassName); - } + ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName->Buffer, hInstance); if (!ClassFound) { if (IS_ATOM(ClassName->Buffer)) @@ -1486,6 +1457,7 @@ IntCreateWindowEx(DWORD dwExStyle, { IntReleaseWindowObject(ParentWindow); } + SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS); return((HWND)0); } @@ -2045,7 +2017,7 @@ NtUserCreateWindowEx(DWORD dwExStyle, } if (! IS_ATOM(ClassName.Buffer)) { - Status = IntSafeCopyUnicodeString(&ClassName, UnsafeClassName); + Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); @@ -2111,6 +2083,8 @@ NtUserDestroyWindow(HWND Wnd) { PWINDOW_OBJECT Window; BOOLEAN isChild; + + DbgPrint("DestroyWindow:0x%x\n", Wnd); Window = IntGetWindowObject(Wnd); if (Window == NULL) @@ -2453,7 +2427,7 @@ NtUserFindWindowEx(HWND hwndParent, DPRINT1("Window class not found (%lx)\n", (ULONG_PTR)ClassName.Buffer); else DPRINT1("Window class not found (%S)\n", ClassName.Buffer); - SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST); + SetLastWin32Error(ERROR_FILE_NOT_FOUND); goto Cleanup; } } diff --git a/reactos/subsys/win32k/ntuser/winpos.c b/reactos/subsys/win32k/ntuser/winpos.c index 5e269d6642a..208b2c19b36 100644 --- a/reactos/subsys/win32k/ntuser/winpos.c +++ b/reactos/subsys/win32k/ntuser/winpos.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: winpos.c,v 1.124 2004/11/21 12:14:34 navaraf Exp $ +/* $Id: winpos.c,v 1.125 2004/12/11 19:39:18 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -1321,7 +1321,8 @@ WinPosShowWindow(HWND Wnd, INT Cmd) /* FIXME: Check for window destruction. */ - if (Window->Flags & WINDOWOBJECT_NEED_SIZE) + if ((Window->Flags & WINDOWOBJECT_NEED_SIZE) && + !(Window->Status & WINDOWSTATUS_DESTROYING)) { WPARAM wParam = SIZE_RESTORED;