42 GdiDbgPreServiceHook(ulSyscallId, pulArguments);
50 ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
73 if (ppiCurrent ==
NULL)
75 ERR_CH(UserProcess,
"Failed to allocate ppi for PID:0x%lx\n",
80 TRACE_CH(UserProcess,
"Allocated ppi 0x%p for PID:0x%lx\n",
88 *W32Process = ppiCurrent;
99 if (ppiCurrent->InputIdleEvent)
106 if (ppiCurrent->rpdeskStartup)
112 TRACE_PPI(ppiCurrent, UserObj,
"Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
147 DPRINT(
"CreateEvent() failed\n");
152 ppiCurrent->InputIdleEvent =
Event;
156 ppiCurrent->peProcess =
Process;
161 if (
Process->Peb->ProcessParameters &&
194 TRACE_CH(UserProcess,
"Freeing ppi 0x%p\n", ppiCurrent);
198 TRACE_CH(UserObj,
"Dumping user handles at the end of the process %s (Info %p).\n",
199 ppiCurrent->peProcess->ImageFileName, ppiCurrent);
210 if (
gpidLogon == ppiCurrent->peProcess->UniqueProcessId)
239 if (ppiCurrent !=
NULL)
251 ERR_CH(UserProcess,
"Failed to allocate ppi for PID:0x%lx\n",
267 TRACE_CH(UserProcess,
"Failed to map the global heap! 0x%x\n",
Status);
271 TRACE_CH(UserProcess,
"InitProcessCallback -- We have KernelMapping 0x%p and UserMapping 0x%p with delta = 0x%x\n",
278 ERR_CH(UserProcess,
"UserProcessCreate failed, Status 0x%08lx\n",
Status);
286 ERR_CH(UserProcess,
"GdiProcessCreate failed, Status 0x%08lx\n",
Status);
297 ERR_CH(UserProcess,
"InitProcessCallback failed! Freeing ppi 0x%p for PID:0x%lx\n",
313 TRACE_CH(UserProcess,
"Destroying ppi 0x%p\n", ppiCurrent);
318 while (*pppi !=
NULL && *pppi != ppiCurrent)
322 ASSERT(*pppi == ppiCurrent);
333 ppiCurrent->peProcess =
NULL;
350 TRACE_CH(UserProcess,
"Win32kProcessCallback -->\n");
365 TRACE_CH(UserProcess,
"<-- Win32kProcessCallback\n");
388 if (ptiCurrent ==
NULL)
390 ERR_CH(UserThread,
"Failed to allocate pti for TID:0x%lx\n",
395 TRACE_CH(UserThread,
"Allocated pti 0x%p for TID:0x%lx\n",
404 *W32Thread = ptiCurrent;
416 TRACE_CH(UserThread,
"UserDeleteW32Thread pti 0x%p\n",pti);
479 ERR_CH(UserThread,
"Failed to allocate pti for TID:0x%lx\n",
485 ptiCurrent->pEThread =
Thread;
490 ptiCurrent->
pcti = &ptiCurrent->
cti;
513 ERR_CH(UserThread,
"Event creation failed, Status 0x%08x.\n",
Status);
521 ERR_CH(UserThread,
"Failed referencing the event object, Status 0x%08x.\n",
Status);
532 ERR_CH(UserThread,
"Failed to allocate message loop\n");
551 pci->
ppi = ptiCurrent->
ppi;
587 HWINSTA hWinSta =
NULL;
617 ERR_CH(UserThread,
"Failed to assign default desktop and winsta to process\n");
624 ERR_CH(UserThread,
"Failed to set initial process winsta\n");
632 ERR_CH(UserThread,
"Failed to validate initial desktop handle\n");
647 ERR_CH(UserThread,
"Failed to set thread desktop\n");
673 TRACE_CH(UserThread,
"Call co_IntClientThreadSetup...\n");
677 ERR_CH(UserThread,
"ClientThreadSetup failed with Status 0x%08lx\n",
Status);
680 TRACE_CH(UserThread,
"co_IntClientThreadSetup succeeded!\n");
684 TRACE_CH(UserThread,
"co_IntClientThreadSetup cannot be called...\n");
687 TRACE_CH(UserThread,
"UserCreateW32Thread pti 0x%p\n", ptiCurrent);
691 ERR_CH(UserThread,
"InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
718 TRACE_CH(UserThread,
"Destroying pti 0x%p eThread 0x%p\n", ptiCurrent,
Thread);
723 ppiCurrent = ptiCurrent->
ppi;
730 for (pwl =
gpwlList; pwl; pwl = pwlNext)
733 if (pwl->
pti == ptiCurrent)
761 if (ptiCurrent->
pDeskInfo->ppiShellProcess == ppiCurrent)
765 TRACE_CH(UserProcess,
"Shell process is exiting (%lu)\n", ExitCode);
784 DPRINT1(
"Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
790 if (ppiCurrent && ppiCurrent->
ptiList == ptiCurrent && !ptiCurrent->
ptiSibling &&
793 TRACE_CH(UserThread,
"DestroyProcessClasses\n");
807 TRACE_CH(UserThread,
"thread clean: remove reference obj 0x%p\n",
ref->obj);
822 while (*ppti !=
NULL && *ppti != ptiCurrent)
824 ppti = &((*ppti)->ptiSibling);
828 ASSERT(*ppti == ptiCurrent);
859 TRACE_CH(UserThread,
"Freeing pti 0x%p\n", ptiCurrent);
920 if (!NT_SUCCESS(Status)) \ 922 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 928 #define USERLOCK_AND_ROF(x) \ 930 UserEnterExclusive(); \ 933 if (!NT_SUCCESS(Status)) \ 935 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 968 DPRINT1(
"Adding system services failed!\n");
999 #if DBG && defined(KDBG) 1006 &GlobalUserHeapBase,
1010 DPRINT1(
"Failed to initialize the global heap!\n");
1025 DPRINT1(
"Failed allocate server info structure!\n");
1059 DPRINT1(
"Unable to initialize font support\n");
NTSTATUS APIENTRY Win32kThreadCallback(PETHREAD Thread, PSW32THREADCALLOUTTYPE Type)
PVOID NTAPI PsSetThreadWin32Thread(_Inout_ PETHREAD Thread, _In_ PVOID Win32Thread, _In_ PVOID OldWin32Thread)
PVOID NTAPI PsGetThreadWin32Thread(IN PETHREAD Thread)
BOOL FASTCALL UserPostMessage(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
ULONG Win32ClientInfo[31]
NTSTATUS NTAPI IntDesktopObjectOpen(_In_ PVOID Parameters)
PPROCESSINFO ppiScrnSaver
VOID FASTCALL co_MsqInsertMouseMessage(MSG *Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
NTSTATUS InitProcessCallback(PEPROCESS Process)
PPEB ProcessEnvironmentBlock
void FASTCALL DestroyProcessClasses(PPROCESSINFO Process)
struct tagIMC * spDefaultImc
PKWIN32_SESSION_CALLOUT WindowStationOkToCloseProcedure
NTSTATUS GdiThreadDestroy(PETHREAD Thread)
NTSTATUS AllocW32Process(IN PEPROCESS Process, OUT PPROCESSINFO *W32Process)
PVOID FASTCALL UserAssignmentLock(PVOID *ppvObj, PVOID pvNew)
VOID ResetCsrProcess(VOID)
PGDI_BATCHFLUSH_ROUTINE BatchFlushRoutine
LIST_ENTRY WindowListHead
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define TIF_DONTATTACHQUEUE
#define EngGetTickCount32()
NTSTATUS NTAPI InitPDEVImpl(VOID)
struct tagWINDOWLIST * pNextList
BOOLEAN NTAPI KeAddSystemServiceTable(IN PULONG_PTR Base, IN PULONG Count OPTIONAL, IN ULONG Limit, IN PUCHAR Number, IN ULONG Index)
PVOID NTAPI PsGetProcessWin32Process(PEPROCESS Process)
TW_UINT32 TW_UINT16 TW_UINT16 MSG
PWINSTATION_OBJECT InputWindowStation
NTSTATUS NTAPI InitTimerImpl(VOID)
_Must_inspect_result_ _In_ PDRIVER_OBJECT _In_ PCUNICODE_STRING RegistryPath
NTSTATUS NTAPI IntDesktopOkToClose(_In_ PVOID Parameters)
NTSTATUS ExInitializeResourceLite(PULONG res)
BOOL FASTCALL DestroyTimersForThread(PTHREADINFO pti)
USHORT FASTCALL UserGetLanguageID(VOID)
NTSTATUS ExitProcessCallback(PEPROCESS Process)
BOOL FASTCALL UserDereferenceObject(PVOID Object)
PKWIN32_THREAD_CALLOUT ThreadCallout
NTSTATUS NTAPI InitKeyboardImpl(VOID)
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
ULONG Win32kNumberOfSysCalls
static __inline PVOID UserHeapAlloc(SIZE_T Bytes)
NTSTATUS APIENTRY NtGdiFlushUserBatch(VOID)
UNICODE_STRING DesktopInfo
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
POBJECT_TYPE ExEventObjectType
PKWIN32_SESSION_CALLOUT DesktopCloseProcedure
NTSTATUS MapGlobalUserHeap(IN PEPROCESS Process, OUT PVOID *KernelMapping, OUT PVOID *UserMapping)
NTSTATUS NTAPI IntWinStaObjectParse(_In_ PVOID Parameters)
static GENERIC_MAPPING UserMapping
PTHREADINFO gptiForeground
#define W32PF_PROCESSCONNECTED
BOOL FASTCALL InitFontSupport(VOID)
PKWIN32_SESSION_CALLOUT WindowStationDeleteProcedure
#define W32PF_ALLOWFOREGROUNDACTIVATE
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
NTSTATUS NTAPI InitLDEVImpl(VOID)
VOID FASTCALL CreateSysColorObjects(VOID)
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
NTSTATUS FASTCALL IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest, PUNICODE_STRING Source)
NTSTATUS NTAPI PsGetProcessExitStatus(PEPROCESS Process)
BOOL NTAPI UserCloseClipboard(VOID)
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
NTSTATUS NTAPI PsSetProcessWin32Process(_Inout_ PEPROCESS Process, _In_opt_ PVOID Win32Process, _In_opt_ PVOID OldWin32Process)
NTSTATUS NTAPI InitBrushImpl(VOID)
NTSTATUS NTAPI InitDesktopImpl(VOID)
LIST_ENTRY SentMessagesListHead
void FASTCALL DceFreeThreadDCE(PTHREADINFO)
VOID FASTCALL CreateStockObjects(VOID)
NTSTATUS AllocW32Thread(IN PETHREAD Thread, OUT PTHREADINFO *W32Thread)
_Function_class_(DRIVER_UNLOAD)
#define STARTF_INHERITDESKTOP
_In_ PVOID _In_ ULONG Event
#define USERLOCK_AND_ROF(x)
NTSTATUS NTAPI IntWinStaObjectDelete(_In_ PVOID Parameters)
VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget)
NTSTATUS GdiProcessDestroy(PEPROCESS Process)
PPROCESSINFO gppiInputProvider
#define IntReferenceProcessInfo(ppi)
LIST_ENTRY W32CallbackListHead
VOID UserDeleteW32Process(_Pre_notnull_ __drv_freesMem(Mem) PPROCESSINFO ppiCurrent)
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
#define TIF_GUITHREADINITIALIZED
NTSTATUS GdiThreadCreate(PETHREAD Thread)
PKWIN32_SESSION_CALLOUT DesktopOkToCloseProcedure
NTSTATUS APIENTRY Win32kProcessCallback(PEPROCESS Process, BOOLEAN Initialize)
enum _PSW32THREADCALLOUTTYPE PSW32THREADCALLOUTTYPE
struct _CLIENTTHREADINFO * pcti
PKWIN32_SESSION_CALLOUT DesktopDeleteProcedure
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
FORCEINLINE PSINGLE_LIST_ENTRY PopEntryList(_Inout_ PSINGLE_LIST_ENTRY ListHead)
#define TIF_ALLOWFOREGROUNDACTIVATE
_Must_inspect_result_ _In_ PDRIVER_OBJECT DriverObject
#define IntReferenceThreadInfo(pti)
void NTAPI UserDbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
VOID FASTCALL UserEnterExclusive(VOID)
NTSTATUS NTAPI InitPaletteImpl(VOID)
BOOLEAN NTAPI DbgGdiKdbgCliCallback(IN PCHAR pszCommand, IN ULONG argc, IN PCH argv[])
VOID FASTCALL MsqDestroyMessageQueue(_In_ PTHREADINFO pti)
NTSTATUS UserThreadDestroy(PETHREAD Thread)
#define NT_SUCCESS(StatCode)
PUSER_MESSAGE_QUEUE FASTCALL MsqCreateMessageQueue(PTHREADINFO pti)
NTSTATUS NTAPI InitGdiHandleTable(void)
struct _DESKTOP * rpdeskStartup
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
PKEVENT pEventQueueServer
PVOID NTAPI MmPageEntireDriver(IN PVOID AddressWithinSection)
#define ObDereferenceObject
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
struct _CLIENTINFO * pClientInfo
#define STATUS_UNSUCCESSFUL
NTSTATUS NTAPI InitWindowStationImpl(VOID)
#define ExAllocatePoolWithTag(hernya, size, tag)
NTSTATUS UserProcessCreate(PEPROCESS Process)
BOOL DbgInitDebugChannels()
NTSTATUS NTAPI ObCloseHandle(IN HANDLE Handle, IN KPROCESSOR_MODE AccessMode)
struct _CLIENTINFO * PCLIENTINFO
BOOL FASTCALL UserSetProcessWindowStation(HWINSTA hWindowStation)
ULONG_PTR NTAPI UserDbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
PKWIN32_SESSION_CALLOUT DesktopOpenProcedure
BOOL FASTCALL co_IntGraphicsCheck(BOOL Create)
NTSTATUS GdiProcessCreate(PEPROCESS Process)
LIST_ENTRY aphkStart[NB_HOOKS]
FIXME!
NTSTATUS UserThreadCreate(PETHREAD Thread)
NTSTATUS NTAPI InitThreadCallback(PETHREAD Thread)
PPROCESSINFO ppiUahServer
static BOOL Initialize(LPCWSTR lpDriverPath)
NTSTATUS NTAPI IntWinStaOkToClose(_In_ PVOID Parameters)
VOID ResetCsrApiPort(VOID)
PVOID GlobalUserHeapSection
NTSTATUS NTAPI ExitThreadCallback(PETHREAD Thread)
struct tagKL * KeyboardLayout
VOID FASTCALL UnregisterThreadHotKeys(PTHREADINFO pti)
NTSTATUS NTAPI InitDcImpl(VOID)
LIST_ENTRY DriverObjListHead
NTSTATUS UserProcessDestroy(PEPROCESS Process)
struct _USER_MESSAGE_QUEUE * MessageQueue
VOID FASTCALL UserLeave(VOID)
#define TRACE_CH(ch, fmt,...)
#define DBG_IS_CHANNEL_ENABLED(ppi, ch, level)
#define TRACE_PPI(ppi, ch, fmt,...)
#define W32PF_CLASSESREGISTERED
#define KeInitializeEvent(pEvt, foo, foo2)
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
VOID FASTCALL IntCleanupThreadCallbacks(PTHREADINFO W32Thread)
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
LIST_ENTRY PostedMessagesListHead
#define STATUS_ALREADY_WIN32
NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
BOOL IntSetThreadDesktop(IN HDESK hDesktop, IN BOOL FreeOnFailure)
#define InitializeListHead(ListHead)
NTSTATUS NTAPI IntDesktopObjectDelete(_In_ PVOID Parameters)
struct tagUSERSTARTUPINFO USERSTARTUPINFO
static DRIVER_UNLOAD DriverUnload
VOID FASTCALL IntCleanupCurIconCache(PPROCESSINFO Win32Process)
#define STARTF_SCREENSAVER
NTSTATUS FASTCALL IntResolveDesktop(IN PEPROCESS Process, IN PUNICODE_STRING DesktopPath, IN BOOL bInherit, OUT HWINSTA *phWinSta, OUT HDESK *phDesktop)
NTSTATUS FASTCALL IntValidateDesktopHandle(HDESK Desktop, KPROCESSOR_MODE AccessMode, ACCESS_MASK DesiredAccess, PDESKTOP *Object)
VOID FASTCALL MsqCleanupThreadMsgs(PTHREADINFO pti)
#define __drv_freesMem(kind)
NTSTATUS APIENTRY co_IntClientThreadSetup(VOID)
NTSTATUS NTAPI MsqInitializeImpl(VOID)
#define W32PF_APPSTARTING
NTSTATUS NTAPI IntDesktopObjectClose(_In_ PVOID Parameters)
#define ERR_CH(ch, fmt,...)
BOOLEAN UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
NTSTATUS NTAPI InitUserImpl(VOID)
VOID NTAPI PsEstablishWin32Callouts(IN PWIN32_CALLOUTS_FPNS CalloutData)
void DbgUserDumpHandleTable()
PVOID FASTCALL UserAssignmentUnlock(PVOID *ppvObj)
NTSTATUS NTAPI InitDeviceImpl(VOID)
#define ObReferenceObject
SINGLE_LIST_ENTRY ReferencesList
PWIN32HEAP UserCreateHeap(OUT PVOID *SectionObject, IN OUT PVOID *SystemBase, IN SIZE_T HeapSize)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
VOID UserDeleteW32Thread(PTHREADINFO pti)
NTSTATUS NTAPI KdSystemDebugControl(_In_ SYSDBG_COMMAND Command, _In_ PVOID InputBuffer, _In_ ULONG InputBufferLength, _Out_ PVOID OutputBuffer, _In_ ULONG OutputBufferLength, _Inout_ PULONG ReturnLength, _In_ KPROCESSOR_MODE PreviousMode)
HANDLE NTAPI PsGetProcessId(PEPROCESS Process)
PKWIN32_SESSION_CALLOUT WindowStationParseProcedure
PKWIN32_PROCESS_CALLOUT ProcessCallout
NTSTATUS NTAPI InitDCEImpl(VOID)
FAST_MUTEX DriverObjListLock
struct _DESKTOPINFO * pDeskInfo
struct _PROCESSINFO * ppi
PUSER_HANDLE_TABLE gHandleTable
#define ExFreePoolWithTag(_P, _T)
#define IntDereferenceProcessInfo(ppi)
#define IntDereferenceThreadInfo(pti)
VOID FASTCALL IntFreeImeHotKeys(VOID)
PIMC FASTCALL UserCreateInputContext(ULONG_PTR dwClientImcData)
VOID UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent)
base of all file and directory entries
#define W32PF_THREADCONNECTED
BOOLEAN NTAPI KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
BOOL FASTCALL UserUnregisterUserApiHook(VOID)
#define W32PF_SCREENSAVER