mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
implementation of window enumeration. thread window enumeration appears to have a problem. Would someone who understands it better please fix it?
svn path=/trunk/; revision=5268
This commit is contained in:
parent
8a66dfeaad
commit
bf34364f74
9 changed files with 266 additions and 60 deletions
|
@ -7,7 +7,7 @@ PATH_TO_TOP = ../..
|
||||||
include $(PATH_TO_TOP)/rules.mak
|
include $(PATH_TO_TOP)/rules.mak
|
||||||
|
|
||||||
TEST_APPS = alive apc args atomtest bench bitblt button button2 \
|
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 \
|
gditest hello isotest lineclip lpc messagebox mstest mutex nptest pteb \
|
||||||
regtest sectest shm thread tokentest vmtest winhello dibtest lock SampleWindow \
|
regtest sectest shm thread tokentest vmtest winhello dibtest lock SampleWindow \
|
||||||
hivetest shaptest wm_paint multiwin icontest suspend tests/volinfo terminate
|
hivetest shaptest wm_paint multiwin icontest suspend tests/volinfo terminate
|
||||||
|
|
|
@ -65,16 +65,16 @@ STDCALL
|
||||||
NtUserBlockInput(
|
NtUserBlockInput(
|
||||||
DWORD Unknown0);
|
DWORD Unknown0);
|
||||||
|
|
||||||
DWORD
|
ULONG
|
||||||
STDCALL
|
STDCALL
|
||||||
NtUserBuildHwndList(
|
NtUserBuildHwndList(
|
||||||
DWORD Unknown0,
|
HDESK hDesktop,
|
||||||
DWORD Unknown1,
|
HWND hwndParent,
|
||||||
DWORD Unknown2,
|
BOOLEAN bChildren,
|
||||||
DWORD Unknown3,
|
ULONG dwThreadId,
|
||||||
DWORD Unknown4,
|
ULONG lParam,
|
||||||
DWORD Unknown5,
|
HWND* pWnd,
|
||||||
DWORD Unknown6);
|
ULONG nBufSize);
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
STDCALL
|
STDCALL
|
||||||
|
|
|
@ -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\lpcsrv.exe %ROS_INSTALL%\bin
|
||||||
copy apps\tests\lpc\lpcclt.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\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\event\event.exe %ROS_INSTALL%\bin
|
||||||
copy apps\tests\file\file.exe %ROS_INSTALL%\bin
|
copy apps\tests\file\file.exe %ROS_INSTALL%\bin
|
||||||
copy apps\tests\pteb\pteb.exe %ROS_INSTALL%\bin
|
copy apps\tests\pteb\pteb.exe %ROS_INSTALL%\bin
|
||||||
|
|
|
@ -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
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS user32.dll
|
* 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
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS user32.dll
|
* PROJECT: ReactOS user32.dll
|
||||||
|
@ -748,41 +748,128 @@ EndDeferWindowPos(HDWP hWinPosInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
WINBOOL
|
||||||
* @unimplemented
|
STATIC
|
||||||
*/
|
User32EnumWindows (
|
||||||
WINBOOL STDCALL
|
HDESK hDesktop,
|
||||||
EnumChildWindows(HWND hWndParent,
|
HWND hWndparent,
|
||||||
ENUMWINDOWSPROC lpEnumFunc,
|
ENUMWINDOWSPROC lpfn,
|
||||||
LPARAM lParam)
|
LPARAM lParam,
|
||||||
|
DWORD dwThreadId,
|
||||||
|
BOOL bChildren )
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
DWORD i, dwCount = 0;
|
||||||
return FALSE;
|
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,
|
EnumThreadWindows(DWORD dwThreadId,
|
||||||
ENUMWINDOWSPROC lpfn,
|
ENUMWINDOWSPROC lpfn,
|
||||||
LPARAM lParam)
|
LPARAM lParam)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
if ( !dwThreadId )
|
||||||
return FALSE;
|
dwThreadId = GetCurrentThreadId();
|
||||||
|
return User32EnumWindows ( NULL, NULL, lpfn, lParam, dwThreadId, FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
WINBOOL STDCALL
|
WINBOOL STDCALL
|
||||||
EnumWindows(ENUMWINDOWSPROC lpEnumFunc,
|
EnumWindows(ENUMWINDOWSPROC lpEnumFunc,
|
||||||
LPARAM lParam)
|
LPARAM lParam)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
return User32EnumWindows ( NULL, NULL, lpEnumFunc, lParam, 0, FALSE );
|
||||||
return FALSE;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
WINBOOL
|
||||||
|
STDCALL
|
||||||
|
EnumDesktopWindows(
|
||||||
|
HDESK hDesktop,
|
||||||
|
ENUMWINDOWSPROC lpfn,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
return User32EnumWindows ( hDesktop, NULL, lpfn, lParam, 0, FALSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ LRESULT CALLBACK
|
||||||
W32kDesktopWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
W32kDesktopWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
PDESKTOP_OBJECT FASTCALL
|
PDESKTOP_OBJECT FASTCALL
|
||||||
W32kGetActiveDesktop(VOID);
|
W32kGetActiveDesktop(VOID);
|
||||||
|
PDESKTOP_OBJECT FASTCALL
|
||||||
|
W32kGetDesktopObject ( HDESK hDesk );
|
||||||
PUSER_MESSAGE_QUEUE FASTCALL
|
PUSER_MESSAGE_QUEUE FASTCALL
|
||||||
W32kGetFocusMessageQueue(VOID);
|
W32kGetFocusMessageQueue(VOID);
|
||||||
VOID FASTCALL
|
VOID FASTCALL
|
||||||
|
|
|
@ -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
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -65,21 +65,6 @@ NtUserBlockInput(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD
|
|
||||||
STDCALL
|
|
||||||
NtUserBuildHwndList(
|
|
||||||
DWORD Unknown0,
|
|
||||||
DWORD Unknown1,
|
|
||||||
DWORD Unknown2,
|
|
||||||
DWORD Unknown3,
|
|
||||||
DWORD Unknown4,
|
|
||||||
DWORD Unknown5,
|
|
||||||
DWORD Unknown6)
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
STDCALL
|
STDCALL
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -1998,4 +1998,143 @@ NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
|
||||||
return tid;
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -74,6 +74,13 @@ W32kGetActiveDesktop(VOID)
|
||||||
return(InputDesktop);
|
return(InputDesktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDESKTOP_OBJECT FASTCALL
|
||||||
|
W32kGetDesktopObject ( HDESK hDesk )
|
||||||
|
{
|
||||||
|
/* FIXME - this obviously isn't right */
|
||||||
|
return W32kGetActiveDesktop();
|
||||||
|
}
|
||||||
|
|
||||||
PUSER_MESSAGE_QUEUE FASTCALL
|
PUSER_MESSAGE_QUEUE FASTCALL
|
||||||
W32kGetFocusMessageQueue(VOID)
|
W32kGetFocusMessageQueue(VOID)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue