diff --git a/reactos/apps/tests/Makefile b/reactos/apps/tests/Makefile index c1e8c4fde75..b98697e02c7 100644 --- a/reactos/apps/tests/Makefile +++ b/reactos/apps/tests/Makefile @@ -7,7 +7,7 @@ PATH_TO_TOP = ../.. include $(PATH_TO_TOP)/rules.mak TEST_APPS = alive apc args atomtest bench bitblt button button2 \ -combo consume copymove count dump_shared_data edit event file \ +combo consume copymove count dump_shared_data edit enumwnd event file \ gditest hello isotest lineclip lpc messagebox mstest mutex nptest pteb \ regtest sectest shm thread tokentest vmtest winhello dibtest lock SampleWindow \ hivetest shaptest wm_paint multiwin icontest suspend tests/volinfo terminate diff --git a/reactos/include/win32k/ntuser.h b/reactos/include/win32k/ntuser.h index 32f218d476b..76d8bbae46b 100644 --- a/reactos/include/win32k/ntuser.h +++ b/reactos/include/win32k/ntuser.h @@ -65,16 +65,16 @@ STDCALL NtUserBlockInput( DWORD Unknown0); -DWORD +ULONG STDCALL NtUserBuildHwndList( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3, - DWORD Unknown4, - DWORD Unknown5, - DWORD Unknown6); + HDESK hDesktop, + HWND hwndParent, + BOOLEAN bChildren, + ULONG dwThreadId, + ULONG lParam, + HWND* pWnd, + ULONG nBufSize); DWORD STDCALL diff --git a/reactos/install.bat b/reactos/install.bat index f19dd564ba9..9467964bcb8 100644 --- a/reactos/install.bat +++ b/reactos/install.bat @@ -119,6 +119,7 @@ copy apps\tests\shm\shmclt.exe %ROS_INSTALL%\bin copy apps\tests\lpc\lpcsrv.exe %ROS_INSTALL%\bin copy apps\tests\lpc\lpcclt.exe %ROS_INSTALL%\bin copy apps\tests\thread\thread.exe %ROS_INSTALL%\bin +copy apps\tests\enumwnd\enumwnd.exe %ROS_INSTALL%\bin copy apps\tests\event\event.exe %ROS_INSTALL%\bin copy apps\tests\file\file.exe %ROS_INSTALL%\bin copy apps\tests\pteb\pteb.exe %ROS_INSTALL%\bin diff --git a/reactos/lib/user32/misc/desktop.c b/reactos/lib/user32/misc/desktop.c index e750b733438..3274cb1d104 100644 --- a/reactos/lib/user32/misc/desktop.c +++ b/reactos/lib/user32/misc/desktop.c @@ -1,4 +1,4 @@ -/* $Id: desktop.c,v 1.15 2003/07/21 01:59:51 royce Exp $ +/* $Id: desktop.c,v 1.16 2003/07/25 23:02:21 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll @@ -156,21 +156,6 @@ CreateDesktopW(LPCWSTR lpszDesktop, } -/* - * @unimplemented - */ -WINBOOL -STDCALL -EnumDesktopWindows( - HDESK hDesktop, - ENUMWINDOWSPROC lpfn, - LPARAM lParam) -{ - UNIMPLEMENTED; - return FALSE; -} - - /* * @unimplemented */ diff --git a/reactos/lib/user32/windows/window.c b/reactos/lib/user32/windows/window.c index c1d6cede86f..5bccc78589e 100644 --- a/reactos/lib/user32/windows/window.c +++ b/reactos/lib/user32/windows/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.46 2003/07/25 19:37:14 gdalsnes Exp $ +/* $Id: window.c,v 1.47 2003/07/25 23:02:21 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll @@ -748,41 +748,128 @@ EndDeferWindowPos(HDWP hWinPosInfo) } -/* - * @unimplemented - */ -WINBOOL STDCALL -EnumChildWindows(HWND hWndParent, - ENUMWINDOWSPROC lpEnumFunc, - LPARAM lParam) +WINBOOL +STATIC +User32EnumWindows ( + HDESK hDesktop, + HWND hWndparent, + ENUMWINDOWSPROC lpfn, + LPARAM lParam, + DWORD dwThreadId, + BOOL bChildren ) { - UNIMPLEMENTED; - return FALSE; + DWORD i, dwCount = 0; + HWND* pHwnd = NULL; + HANDLE hHeap; + + if ( !lpfn ) + { + SetLastError ( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + /* FIXME instead of always making two calls, should we use some + sort of persistent buffer and only grow it ( requiring a 2nd + call ) when the buffer wasn't already big enough? */ + /* first get how many window entries there are */ + SetLastError(0); + dwCount = NtUserBuildHwndList ( + hDesktop, hWndparent, bChildren, dwThreadId, lParam, NULL, 0 ); + if ( !dwCount || GetLastError() ) + return FALSE; + + /* allocate buffer to receive HWND handles */ + hHeap = GetProcessHeap(); + pHwnd = HeapAlloc ( hHeap, 0, sizeof(HWND)*(dwCount+1) ); + if ( !pHwnd ) + { + SetLastError ( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + + /* now call kernel again to fill the buffer this time */ + dwCount = NtUserBuildHwndList ( + hDesktop, hWndparent, bChildren, dwThreadId, lParam, pHwnd, dwCount ); + if ( !dwCount || GetLastError() ) + { + if ( pHwnd ) + HeapFree ( hHeap, 0, pHwnd ); + return FALSE; + } + + /* call the user's callback function until we're done or + they tell us to quit */ + for ( i = 0; i < dwCount; i++ ) + { + /* 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 + */ + if ( !(ULONG)pHwnd[i] ) /* don't enumerate a NULL HWND */ + continue; + if ( !(*lpfn)( pHwnd[i], lParam ) ) + break; + } + if ( pHwnd ) + HeapFree ( hHeap, 0, pHwnd ); + return TRUE; } /* - * @unimplemented + * @implemented */ -WINBOOL STDCALL +WINBOOL +STDCALL +EnumChildWindows( + HWND hWndParent, + ENUMWINDOWSPROC lpEnumFunc, + LPARAM lParam) +{ + if ( !hWndParent ) + hWndParent = GetDesktopWindow(); + return User32EnumWindows ( NULL, hWndParent, lpEnumFunc, lParam, 0, FALSE ); +} + + +/* + * @implemented + */ +WINBOOL +STDCALL EnumThreadWindows(DWORD dwThreadId, ENUMWINDOWSPROC lpfn, LPARAM lParam) { - UNIMPLEMENTED; - return FALSE; + if ( !dwThreadId ) + dwThreadId = GetCurrentThreadId(); + return User32EnumWindows ( NULL, NULL, lpfn, lParam, dwThreadId, FALSE ); } /* - * @unimplemented + * @implemented */ WINBOOL STDCALL EnumWindows(ENUMWINDOWSPROC lpEnumFunc, LPARAM lParam) { - UNIMPLEMENTED; - return FALSE; + return User32EnumWindows ( NULL, NULL, lpEnumFunc, lParam, 0, FALSE ); +} + + +/* + * @implemented + */ +WINBOOL +STDCALL +EnumDesktopWindows( + HDESK hDesktop, + ENUMWINDOWSPROC lpfn, + LPARAM lParam) +{ + return User32EnumWindows ( hDesktop, NULL, lpfn, lParam, 0, FALSE ); } diff --git a/reactos/subsys/win32k/include/winsta.h b/reactos/subsys/win32k/include/winsta.h index 7c71a12105d..b55cab56b72 100644 --- a/reactos/subsys/win32k/include/winsta.h +++ b/reactos/subsys/win32k/include/winsta.h @@ -35,6 +35,8 @@ LRESULT CALLBACK W32kDesktopWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); PDESKTOP_OBJECT FASTCALL W32kGetActiveDesktop(VOID); +PDESKTOP_OBJECT FASTCALL +W32kGetDesktopObject ( HDESK hDesk ); PUSER_MESSAGE_QUEUE FASTCALL W32kGetFocusMessageQueue(VOID); VOID FASTCALL diff --git a/reactos/subsys/win32k/ntuser/stubs.c b/reactos/subsys/win32k/ntuser/stubs.c index b7fcf4b038a..2d2b6558f79 100644 --- a/reactos/subsys/win32k/ntuser/stubs.c +++ b/reactos/subsys/win32k/ntuser/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.16 2003/07/20 05:32:19 jimtabor Exp $ +/* $Id: stubs.c,v 1.17 2003/07/25 23:02:21 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -65,21 +65,6 @@ NtUserBlockInput( return 0; } -DWORD -STDCALL -NtUserBuildHwndList( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3, - DWORD Unknown4, - DWORD Unknown5, - DWORD Unknown6) -{ - UNIMPLEMENTED - - return 0; -} DWORD STDCALL diff --git a/reactos/subsys/win32k/ntuser/window.c b/reactos/subsys/win32k/ntuser/window.c index f834d00ccdf..e8725e364ee 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.67 2003/07/25 19:35:51 gdalsnes Exp $ +/* $Id: window.c,v 1.68 2003/07/25 23:02:21 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -1998,4 +1998,143 @@ NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid) return tid; } + +/* + * As best as I can figure, this function is used by EnumWindows, + * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows. + * + * It's supposed to build a list of HWNDs to return to the caller. + * We can figure out what kind of list by what parameters are + * passed to us. + */ +ULONG +STDCALL +NtUserBuildHwndList( + HDESK hDesktop, + HWND hwndParent, + BOOLEAN bChildren, + ULONG dwThreadId, + ULONG lParam, + HWND* pWnd, + ULONG nBufSize) +{ + ULONG dwCount = 0; + + /* FIXME handle bChildren */ + if ( hwndParent ) + { + PWINDOW_OBJECT WindowObject = NULL; + PLIST_ENTRY ChildListEntry; + + WindowObject = W32kGetWindowObject ( hwndParent ); + if ( !WindowObject ) + { + DPRINT("Bad window handle 0x%x\n", hWnd); + SetLastWin32Error(ERROR_INVALID_HANDLE); + return 0; + } + + ExAcquireFastMutex ( &WindowObject->ChildrenListLock ); + ChildListEntry = WindowObject->ChildrenListHead.Flink; + while (ChildListEntry != &WindowObject->ChildrenListHead) + { + PWINDOW_OBJECT Child; + Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT, + SiblingListEntry); + if ( pWnd && dwCount < nBufSize ) + pWnd[dwCount] = Child->Self; + dwCount++; + ChildListEntry = ChildListEntry->Flink; + } + ExReleaseFastMutex ( &WindowObject->ChildrenListLock ); + W32kReleaseWindowObject ( WindowObject ); + } + else if ( dwThreadId ) + { + NTSTATUS Status; + struct _ETHREAD* Thread; + struct _EPROCESS* ThreadsProcess; + struct _W32PROCESS* Win32Process; + struct _WINSTATION_OBJECT* WindowStation; + PUSER_HANDLE_TABLE HandleTable; + PLIST_ENTRY Current; + PUSER_HANDLE_BLOCK Block = NULL; + int i; + + Status = PsLookupThreadByThreadId ( (PVOID)dwThreadId, &Thread ); + if ( !NT_SUCCESS(Status) || !Thread ) + { + DPRINT("Bad ThreadId 0x%x\n", dwThreadId ); + SetLastWin32Error(ERROR_INVALID_HANDLE); + return 0; + } + ThreadsProcess = Thread->ThreadsProcess; + ASSERT(ThreadsProcess); + Win32Process = ThreadsProcess->Win32Process; + ASSERT(Win32Process); + WindowStation = Win32Process->WindowStation; + ASSERT(WindowStation); + HandleTable = (PUSER_HANDLE_TABLE)(WindowStation->HandleTable); + ASSERT(HandleTable); + + ExAcquireFastMutex(&HandleTable->ListLock); + + Current = HandleTable->ListHead.Flink; + while ( Current != &HandleTable->ListHead ) + { + Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry); + for ( i = 0; i < HANDLE_BLOCK_ENTRIES; i++ ) + { + PVOID ObjectBody = Block->Handles[i].ObjectBody; + if ( ObjectBody ) + { + if ( pWnd && dwCount < nBufSize ) + { + pWnd[dwCount] = + (HWND)ObmReferenceObjectByPointer ( ObjectBody, otWindow ); + } + dwCount++; + } + } + Current = Current->Flink; + } + + ExReleaseFastMutex(&HandleTable->ListLock); + } + else + { + PDESKTOP_OBJECT DesktopObject = NULL; + KIRQL OldIrql; + PLIST_ENTRY WindowListEntry; + + if ( hDesktop ) + DesktopObject = W32kGetDesktopObject ( hDesktop ); + else + DesktopObject = W32kGetActiveDesktop(); + if (!DesktopObject) + { + DPRINT("Bad desktop handle 0x%x\n", hDesktop ); + SetLastWin32Error(ERROR_INVALID_HANDLE); + return 0; + } + + KeAcquireSpinLock ( &DesktopObject->Lock, &OldIrql ); + WindowListEntry = DesktopObject->WindowListHead.Flink; + while ( WindowListEntry != &DesktopObject->WindowListHead ) + { + PWINDOW_OBJECT Child; + Child = CONTAINING_RECORD(WindowListEntry, WINDOW_OBJECT, + SiblingListEntry); + if ( pWnd && dwCount < nBufSize ) + pWnd[dwCount] = Child->Self; + dwCount++; + WindowListEntry = WindowListEntry->Flink; + } + KeReleaseSpinLock ( &DesktopObject->Lock, OldIrql ); + } + + return dwCount; +} + + /* EOF */ diff --git a/reactos/subsys/win32k/ntuser/winsta.c b/reactos/subsys/win32k/ntuser/winsta.c index 69d9e56df2d..5af179469d7 100644 --- a/reactos/subsys/win32k/ntuser/winsta.c +++ b/reactos/subsys/win32k/ntuser/winsta.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: winsta.c,v 1.17 2003/07/05 16:04:01 chorns Exp $ +/* $Id: winsta.c,v 1.18 2003/07/25 23:02:21 royce Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -74,6 +74,13 @@ W32kGetActiveDesktop(VOID) return(InputDesktop); } +PDESKTOP_OBJECT FASTCALL +W32kGetDesktopObject ( HDESK hDesk ) +{ + /* FIXME - this obviously isn't right */ + return W32kGetActiveDesktop(); +} + PUSER_MESSAGE_QUEUE FASTCALL W32kGetFocusMessageQueue(VOID) {