reactos/win32ss/user/ntuser/main.c
Hermès Bélusca-Maïto fd39f92fcb
[INCLUDE][WINLOGON] Rename the STARTF_SCRNSAVER flag to STARTF_SCREENSAVER,
as documented in "Advanced Windows NT" by Jeffrey M. Richter (Microsoft Press),
and in https://is.muni.cz/el/1433/jaro2010/PB167/um/cv5/undocumented_CreateProcess.pdf .

[INCLUDE][SERVICES][WIN32K:NTUSER] Add an undocumented STARTF_INHERITDESKTOP flag
for the STARTUPINFO::dwFlags structure member, whose purpose is to tell Win32k
that the created handles to the window station and desktop to which the
process is connecting to, can be inherited by its child processes.
It is used when starting interactive services.
Observed via API monitoring on Windows 2003.
2018-08-19 22:18:40 +02:00

1025 lines
30 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Driver entry and initialization of win32k
* FILE: win32ss/user/ntuser/main.c
* PROGRAMER:
*/
#include <win32k.h>
#include <napi.h>
#define NDEBUG
#include <debug.h>
#include <kdros.h>
HANDLE hModuleWin;
NTSTATUS ExitProcessCallback(PEPROCESS Process);
NTSTATUS NTAPI ExitThreadCallback(PETHREAD Thread);
// TODO: Should be moved to some GDI header
NTSTATUS GdiProcessCreate(PEPROCESS Process);
NTSTATUS GdiProcessDestroy(PEPROCESS Process);
NTSTATUS GdiThreadCreate(PETHREAD Thread);
NTSTATUS GdiThreadDestroy(PETHREAD Thread);
PSERVERINFO gpsi = NULL; // Global User Server Information.
SHORT gusLanguageID;
PPROCESSINFO ppiScrnSaver;
PPROCESSINFO gppiList = NULL;
extern ULONG_PTR Win32kSSDT[];
extern UCHAR Win32kSSPT[];
extern ULONG Win32kNumberOfSysCalls;
#if DBG
void
NTAPI
DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
{
GdiDbgPreServiceHook(ulSyscallId, pulArguments);
UserDbgPreServiceHook(ulSyscallId, pulArguments);
}
ULONG_PTR
NTAPI
DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
{
ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
return ulResult;
}
#endif
NTSTATUS
AllocW32Process(IN PEPROCESS Process,
OUT PPROCESSINFO* W32Process)
{
PPROCESSINFO ppiCurrent;
TRACE_CH(UserProcess, "In AllocW32Process(0x%p)\n", Process);
/* Check that we were not called with an already existing Win32 process info */
ppiCurrent = PsGetProcessWin32Process(Process);
if (ppiCurrent) return STATUS_SUCCESS;
/* Allocate a new Win32 process info */
ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
sizeof(*ppiCurrent),
USERTAG_PROCESSINFO);
if (ppiCurrent == NULL)
{
ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
HandleToUlong(Process->UniqueProcessId));
return STATUS_NO_MEMORY;
}
TRACE_CH(UserProcess, "Allocated ppi 0x%p for PID:0x%lx\n",
ppiCurrent, HandleToUlong(Process->UniqueProcessId));
RtlZeroMemory(ppiCurrent, sizeof(*ppiCurrent));
PsSetProcessWin32Process(Process, ppiCurrent, NULL);
IntReferenceProcessInfo(ppiCurrent);
*W32Process = ppiCurrent;
return STATUS_SUCCESS;
}
#define FreeW32Process(/*Process*/ W32Process) \
do { \
/*PPROCESSINFO W32Process = PsGetProcessWin32Process(Process);*/ \
/*ASSERT(W32Process);*/ \
IntDereferenceProcessInfo(W32Process); \
} while(0)
/*
* Called from IntDereferenceProcessInfo
*/
VOID
UserDeleteW32Process(
_Pre_notnull_ __drv_freesMem(Mem) PPROCESSINFO ppiCurrent)
{
if (ppiCurrent->InputIdleEvent)
{
/* Free the allocated memory */
ExFreePoolWithTag(ppiCurrent->InputIdleEvent, USERTAG_EVENT);
}
/* Close the startup desktop */
if (ppiCurrent->rpdeskStartup)
ObDereferenceObject(ppiCurrent->rpdeskStartup);
#if DBG
if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
{
TRACE_PPI(ppiCurrent, UserObj, "Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
DbgUserDumpHandleTable();
}
#endif
/* Free the PROCESSINFO */
ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
}
NTSTATUS
UserProcessCreate(PEPROCESS Process)
{
PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
ASSERT(ppiCurrent);
InitializeListHead(&ppiCurrent->DriverObjListHead);
ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
{
PKEVENT Event;
/* Allocate memory for the event structure */
Event = ExAllocatePoolWithTag(NonPagedPool,
sizeof(*Event),
USERTAG_EVENT);
if (Event)
{
/* Initialize the kernel event */
KeInitializeEvent(Event,
SynchronizationEvent,
FALSE);
}
else
{
/* Out of memory */
DPRINT("CreateEvent() failed\n");
KeBugCheck(0);
}
/* Set the event */
ppiCurrent->InputIdleEvent = Event;
KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
}
ppiCurrent->peProcess = Process;
ppiCurrent->W32Pid = HandleToUlong(PsGetProcessId(Process));
/* Setup process flags */
ppiCurrent->W32PF_flags |= W32PF_PROCESSCONNECTED;
if (Process->Peb->ProcessParameters &&
(Process->Peb->ProcessParameters->WindowFlags & STARTF_SCREENSAVER))
{
ppiScrnSaver = ppiCurrent;
ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
}
// FIXME: check if this process is allowed.
ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application will get it toggled off.
return STATUS_SUCCESS;
}
NTSTATUS
UserProcessDestroy(PEPROCESS Process)
{
PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
ASSERT(ppiCurrent);
if (ppiScrnSaver == ppiCurrent)
ppiScrnSaver = NULL;
/* Destroy user objects */
UserDestroyObjectsForOwner(gHandleTable, ppiCurrent);
TRACE_CH(UserProcess, "Freeing ppi 0x%p\n", ppiCurrent);
#if DBG
if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
{
TRACE_CH(UserObj, "Dumping user handles at the end of the process %s (Info %p).\n",
ppiCurrent->peProcess->ImageFileName, ppiCurrent);
DbgUserDumpHandleTable();
}
#endif
/* Remove it from the list of GUI apps */
co_IntGraphicsCheck(FALSE);
/*
* Deregister logon application automatically
*/
if (gpidLogon == ppiCurrent->peProcess->UniqueProcessId)
gpidLogon = 0;
/* Close the current window station */
UserSetProcessWindowStation(NULL);
if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL;
if (ppiCurrent->hdeskStartup)
{
ZwClose(ppiCurrent->hdeskStartup);
ppiCurrent->hdeskStartup = NULL;
}
/* Clean up the process icon cache */
IntCleanupCurIconCache(ppiCurrent);
return STATUS_SUCCESS;
}
NTSTATUS
InitProcessCallback(PEPROCESS Process)
{
NTSTATUS Status;
PPROCESSINFO ppiCurrent;
PVOID KernelMapping = NULL, UserMapping = NULL;
/* We might be called with an already allocated win32 process */
ppiCurrent = PsGetProcessWin32Process(Process);
if (ppiCurrent != NULL)
{
/* There is no more to do for us (this is a success code!) */
return STATUS_ALREADY_WIN32;
}
// if (ppiCurrent->W32PF_flags & W32PF_PROCESSCONNECTED)
// return STATUS_ALREADY_WIN32;
/* Allocate a new Win32 process info */
Status = AllocW32Process(Process, &ppiCurrent);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
HandleToUlong(Process->UniqueProcessId));
return Status;
}
#if DBG
DbgInitDebugChannels();
#if defined(KDBG)
KdRosRegisterCliCallback(DbgGdiKdbgCliCallback);
#endif
#endif
/* Map the global user heap into the process */
Status = MapGlobalUserHeap(Process, &KernelMapping, &UserMapping);
if (!NT_SUCCESS(Status))
{
TRACE_CH(UserProcess, "Failed to map the global heap! 0x%x\n", Status);
goto error;
}
TRACE_CH(UserProcess, "InitProcessCallback -- We have KernelMapping 0x%p and UserMapping 0x%p with delta = 0x%x\n",
KernelMapping, UserMapping, (ULONG_PTR)KernelMapping - (ULONG_PTR)UserMapping);
/* Initialize USER process info */
Status = UserProcessCreate(Process);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserProcess, "UserProcessCreate failed, Status 0x%08lx\n", Status);
goto error;
}
/* Initialize GDI process info */
Status = GdiProcessCreate(Process);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserProcess, "GdiProcessCreate failed, Status 0x%08lx\n", Status);
goto error;
}
/* Add the process to the global list */
ppiCurrent->ppiNext = gppiList;
gppiList = ppiCurrent;
return STATUS_SUCCESS;
error:
ERR_CH(UserProcess, "InitProcessCallback failed! Freeing ppi 0x%p for PID:0x%lx\n",
ppiCurrent, HandleToUlong(Process->UniqueProcessId));
ExitProcessCallback(Process);
return Status;
}
NTSTATUS
ExitProcessCallback(PEPROCESS Process)
{
PPROCESSINFO ppiCurrent, *pppi;
/* Get the Win32 Process */
ppiCurrent = PsGetProcessWin32Process(Process);
ASSERT(ppiCurrent);
ASSERT(ppiCurrent->peProcess == Process);
TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent);
ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
/* Remove it from the list */
pppi = &gppiList;
while (*pppi != NULL && *pppi != ppiCurrent)
{
pppi = &(*pppi)->ppiNext;
}
ASSERT(*pppi == ppiCurrent);
*pppi = ppiCurrent->ppiNext;
/* Cleanup GDI info */
GdiProcessDestroy(Process);
/* Cleanup USER info */
UserProcessDestroy(Process);
/* The process is dying */
PsSetProcessWin32Process(Process, NULL, ppiCurrent);
ppiCurrent->peProcess = NULL;
/* Finally, dereference */
FreeW32Process(/*Process*/ ppiCurrent); // IntDereferenceProcessInfo(ppiCurrent);
return STATUS_SUCCESS;
}
NTSTATUS
APIENTRY
Win32kProcessCallback(PEPROCESS Process,
BOOLEAN Initialize)
{
NTSTATUS Status;
ASSERT(Process->Peb);
TRACE_CH(UserProcess, "Win32kProcessCallback -->\n");
UserEnterExclusive();
if (Initialize)
{
Status = InitProcessCallback(Process);
}
else
{
Status = ExitProcessCallback(Process);
}
UserLeave();
TRACE_CH(UserProcess, "<-- Win32kProcessCallback\n");
return Status;
}
NTSTATUS
AllocW32Thread(IN PETHREAD Thread,
OUT PTHREADINFO* W32Thread)
{
PTHREADINFO ptiCurrent;
TRACE_CH(UserThread, "In AllocW32Thread(0x%p)\n", Thread);
/* Check that we were not called with an already existing Win32 thread info */
ptiCurrent = PsGetThreadWin32Thread(Thread);
NT_ASSERT(ptiCurrent == NULL);
/* Allocate a new Win32 thread info */
ptiCurrent = ExAllocatePoolWithTag(NonPagedPool,
sizeof(*ptiCurrent),
USERTAG_THREADINFO);
if (ptiCurrent == NULL)
{
ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
HandleToUlong(Thread->Cid.UniqueThread));
return STATUS_NO_MEMORY;
}
TRACE_CH(UserThread, "Allocated pti 0x%p for TID:0x%lx\n",
ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
RtlZeroMemory(ptiCurrent, sizeof(*ptiCurrent));
PsSetThreadWin32Thread(Thread, ptiCurrent, NULL);
IntReferenceThreadInfo(ptiCurrent);
*W32Thread = ptiCurrent;
return STATUS_SUCCESS;
}
#define FreeW32Thread(/*Thread*/ W32Thread) \
do { \
/*PTHREADINFO W32Thread = PsGetThreadWin32Thread(Thread);*/ \
/*ASSERT(W32Thread);*/ \
IntDereferenceThreadInfo(W32Thread); \
} while(0)
/*
* Called from IntDereferenceThreadInfo
*/
VOID
UserDeleteW32Thread(PTHREADINFO pti)
{
PPROCESSINFO ppi = pti->ppi;
TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
/* Free the message queue */
if (pti->MessageQueue)
{
MsqDestroyMessageQueue(pti);
}
MsqCleanupThreadMsgs(pti);
ExFreePoolWithTag(pti, USERTAG_THREADINFO);
IntDereferenceProcessInfo(ppi);
}
NTSTATUS
UserThreadCreate(PETHREAD Thread)
{
return STATUS_SUCCESS;
}
NTSTATUS
UserThreadDestroy(PETHREAD Thread)
{
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
InitThreadCallback(PETHREAD Thread)
{
PEPROCESS Process;
PCLIENTINFO pci;
PTHREADINFO ptiCurrent;
int i;
NTSTATUS Status = STATUS_SUCCESS;
PTEB pTeb;
LARGE_INTEGER LargeTickCount;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
Process = Thread->ThreadsProcess;
pTeb = NtCurrentTeb();
ASSERT(pTeb);
ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
/* Allocate a new Win32 thread info */
Status = AllocW32Thread(Thread, &ptiCurrent);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
HandleToUlong(Thread->Cid.UniqueThread));
return Status;
}
/* Initialize the THREADINFO */
ptiCurrent->pEThread = Thread;
ptiCurrent->ppi = PsGetProcessWin32Process(Process);
IntReferenceProcessInfo(ptiCurrent->ppi);
pTeb->Win32ThreadInfo = ptiCurrent;
ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
/* Mark the process as having threads */
ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
InitializeListHead(&ptiCurrent->WindowListHead);
InitializeListHead(&ptiCurrent->W32CallbackListHead);
InitializeListHead(&ptiCurrent->PostedMessagesListHead);
InitializeListHead(&ptiCurrent->SentMessagesListHead);
InitializeListHead(&ptiCurrent->PtiLink);
for (i = 0; i < NB_HOOKS; i++)
{
InitializeListHead(&ptiCurrent->aphkStart[i]);
}
ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
ptiCurrent->ppi->ptiList = ptiCurrent;
ptiCurrent->ppi->cThreads++;
ptiCurrent->hEventQueueClient = NULL;
Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
NULL, SynchronizationEvent, FALSE);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
goto error;
}
Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
*ExEventObjectType, UserMode,
(PVOID*)&ptiCurrent->pEventQueueServer, NULL);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
ptiCurrent->hEventQueueClient = NULL;
goto error;
}
KeQueryTickCount(&LargeTickCount);
ptiCurrent->timeLast = LargeTickCount.u.LowPart;
ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
if (ptiCurrent->MessageQueue == NULL)
{
ERR_CH(UserThread, "Failed to allocate message loop\n");
Status = STATUS_NO_MEMORY;
goto error;
}
ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
if (ptiCurrent->KeyboardLayout)
UserReferenceObject(ptiCurrent->KeyboardLayout);
ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
// FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
/* CSRSS threads have some special features */
if (Process == gpepCSRSS)
ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
ptiCurrent->pcti = &ptiCurrent->cti;
/* Initialize the CLIENTINFO */
pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
RtlZeroMemory(pci, sizeof(*pci));
pci->ppi = ptiCurrent->ppi;
pci->fsHooks = ptiCurrent->fsHooks;
pci->dwTIFlags = ptiCurrent->TIF_flags;
if (ptiCurrent->KeyboardLayout)
{
pci->hKL = ptiCurrent->KeyboardLayout->hkl;
pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
}
/* Need to pass the user Startup Information to the current process. */
if ( ProcessParams )
{
if ( ptiCurrent->ppi->usi.cb == 0 ) // Not initialized yet.
{
if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
{
ptiCurrent->ppi->usi.cb = sizeof(USERSTARTUPINFO);
ptiCurrent->ppi->usi.dwX = ProcessParams->StartingX;
ptiCurrent->ppi->usi.dwY = ProcessParams->StartingY;
ptiCurrent->ppi->usi.dwXSize = ProcessParams->CountX;
ptiCurrent->ppi->usi.dwYSize = ProcessParams->CountY;
ptiCurrent->ppi->usi.dwFlags = ProcessParams->WindowFlags;
ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
}
}
}
/*
* Assign a default window station and desktop to the process.
* Do not try to open a desktop or window station before the very first
* (interactive) window station has been created by Winlogon.
*/
// if (ptiCurrent->ppi->hdeskStartup == NULL && InputWindowStation != NULL)
/* Last things to do only if we are not a SYSTEM or CSRSS thread */
if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
/**/ptiCurrent->ppi->hdeskStartup == NULL &&/**/
InputWindowStation != NULL)
{
HWINSTA hWinSta = NULL;
HDESK hDesk = NULL;
UNICODE_STRING DesktopPath;
PDESKTOP pdesk;
/*
* Inherit the thread desktop and process window station (if not yet inherited)
* from the process startup info structure. See documentation of CreateProcess().
*/
Status = STATUS_UNSUCCESSFUL;
if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
{
Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
}
if (!NT_SUCCESS(Status))
{
RtlInitUnicodeString(&DesktopPath, NULL);
}
Status = IntResolveDesktop(Process,
&DesktopPath,
!!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP),
&hWinSta,
&hDesk);
if (DesktopPath.Buffer)
ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n");
goto error;
}
if (!UserSetProcessWindowStation(hWinSta))
{
Status = STATUS_UNSUCCESSFUL;
ERR_CH(UserThread, "Failed to set initial process winsta\n");
goto error;
}
/* Validate the new desktop */
Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
goto error;
}
/* Store the parsed desktop as the initial desktop */
ASSERT(ptiCurrent->ppi->hdeskStartup == NULL);
ASSERT(Process->UniqueProcessId != gpidLogon);
ptiCurrent->ppi->hdeskStartup = hDesk;
ptiCurrent->ppi->rpdeskStartup = pdesk;
}
if (ptiCurrent->ppi->hdeskStartup != NULL)
{
if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
{
ERR_CH(UserThread, "Failed to set thread desktop\n");
Status = STATUS_UNSUCCESSFUL;
goto error;
}
}
/* Mark the thread as fully initialized */
ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
(gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
{
ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
}
ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
/* Last things to do only if we are not a SYSTEM or CSRSS thread */
if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
{
/* Callback to User32 Client Thread Setup */
TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
Status = co_IntClientThreadSetup();
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
goto error;
}
TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
}
else
{
TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
}
TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
return STATUS_SUCCESS;
error:
ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
ExitThreadCallback(Thread);
return Status;
}
VOID
UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
NTSTATUS
NTAPI
ExitThreadCallback(PETHREAD Thread)
{
PTHREADINFO *ppti;
PSINGLE_LIST_ENTRY psle;
PPROCESSINFO ppiCurrent;
PEPROCESS Process;
PTHREADINFO ptiCurrent;
Process = Thread->ThreadsProcess;
/* Get the Win32 Thread */
ptiCurrent = PsGetThreadWin32Thread(Thread);
ASSERT(ptiCurrent);
TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
ptiCurrent->TIF_flags |= TIF_INCLEANUP;
ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
ppiCurrent = ptiCurrent->ppi;
ASSERT(ppiCurrent);
IsRemoveAttachThread(ptiCurrent);
ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
UserCloseClipboard();
/* Decrement thread count and check if its 0 */
ppiCurrent->cThreads--;
if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
{
/* Do now some process cleanup that requires a valid win32 thread */
if (ptiCurrent->ppi->cThreads == 0)
{
/* Check if we have registered the user api hook */
if (ptiCurrent->ppi == ppiUahServer)
{
/* Unregister the api hook */
UserUnregisterUserApiHook();
}
/* Notify logon application to restart shell if needed */
if (ptiCurrent->pDeskInfo)
{
if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
{
DWORD ExitCode = PsGetProcessExitStatus(Process);
TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
UserPostMessage(hwndSAS,
WM_LOGONNOTIFY,
LN_SHELL_EXITED,
ExitCode);
ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
}
}
}
DceFreeThreadDCE(ptiCurrent);
DestroyTimersForThread(ptiCurrent);
KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
UnregisterThreadHotKeys(ptiCurrent);
if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
{
DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
{
TRACE_CH(UserThread, "DestroyProcessClasses\n");
/* no process windows should exist at this point, or the function will assert! */
DestroyProcessClasses(ppiCurrent);
ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
}
IntBlockInput(ptiCurrent, FALSE);
IntCleanupThreadCallbacks(ptiCurrent);
/* cleanup user object references stack */
psle = PopEntryList(&ptiCurrent->ReferencesList);
while (psle)
{
PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
UserDereferenceObject(ref->obj);
psle = PopEntryList(&ptiCurrent->ReferencesList);
}
}
if (ptiCurrent->cEnterCount)
{
KeSetKernelStackSwapEnable(TRUE);
ptiCurrent->cEnterCount = 0;
}
/* Find the THREADINFO in the PROCESSINFO's list */
ppti = &ppiCurrent->ptiList;
while (*ppti != NULL && *ppti != ptiCurrent)
{
ppti = &((*ppti)->ptiSibling);
}
/* we must have found it */
ASSERT(*ppti == ptiCurrent);
/* Remove it from the list */
*ppti = ptiCurrent->ptiSibling;
if (ptiCurrent->KeyboardLayout)
UserDereferenceObject(ptiCurrent->KeyboardLayout);
if (gptiForeground == ptiCurrent)
{
// IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
// IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
gptiForeground = NULL;
}
/* Restore display mode when we are the last thread, and we changed the display mode */
if (ppiCurrent->cThreads == 0)
UserDisplayNotifyShutdown(ppiCurrent);
// Fixes CORE-6384 & CORE-7030.
/* if (ptiLastInput == ptiCurrent)
{
if (!ppiCurrent->ptiList)
ptiLastInput = gptiForeground;
else
ptiLastInput = ppiCurrent->ptiList;
ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
}
*/
TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
IntSetThreadDesktop(NULL, TRUE);
if (ptiCurrent->hEventQueueClient != NULL)
{
ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
ObDereferenceObject(ptiCurrent->pEventQueueServer);
}
ptiCurrent->hEventQueueClient = NULL;
/* The thread is dying */
PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
ptiCurrent->pEThread = NULL;
/* Free the THREADINFO */
FreeW32Thread(/*Thread*/ ptiCurrent); // IntDereferenceThreadInfo(ptiCurrent);
return STATUS_SUCCESS;
}
NTSTATUS
APIENTRY
Win32kThreadCallback(PETHREAD Thread,
PSW32THREADCALLOUTTYPE Type)
{
NTSTATUS Status;
ASSERT(NtCurrentTeb());
UserEnterExclusive();
if (Type == PsW32ThreadCalloutInitialize)
{
ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
Status = InitThreadCallback(Thread);
}
else // if (Type == PsW32ThreadCalloutExit)
{
ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
Status = ExitThreadCallback(Thread);
}
UserLeave();
return Status;
}
_Function_class_(DRIVER_UNLOAD)
VOID NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
// TODO: Do more cleanup!
ResetCsrApiPort();
ResetCsrProcess();
}
// Return on failure
#define NT_ROF(x) \
{ \
Status = (x); \
if (!NT_SUCCESS(Status)) \
{ \
DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
return Status; \
} \
}
/*
* This definition doesn't work
*/
INIT_SECTION
NTSTATUS
APIENTRY
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
NTSTATUS Status;
BOOLEAN Result;
WIN32_CALLOUTS_FPNS CalloutData = {0};
PVOID GlobalUserHeapBase = NULL;
/*
* Register user mode call interface
* (system service table index = 1)
*/
Result = KeAddSystemServiceTable(Win32kSSDT,
NULL,
Win32kNumberOfSysCalls,
Win32kSSPT,
1);
if (Result == FALSE)
{
DPRINT1("Adding system services failed!\n");
return STATUS_UNSUCCESSFUL;
}
hModuleWin = MmPageEntireDriver(DriverEntry);
DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
DriverObject->DriverUnload = DriverUnload;
/* Register Object Manager Callbacks */
CalloutData.ProcessCallout = Win32kProcessCallback;
CalloutData.ThreadCallout = Win32kThreadCallback;
// CalloutData.GlobalAtomTableCallout = NULL;
// CalloutData.PowerEventCallout = NULL;
// CalloutData.PowerStateCallout = NULL;
// CalloutData.JobCallout = NULL;
CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose;
// CalloutData.WindowStationCloseProcedure = NULL;
CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
// CalloutData.WindowStationOpenProcedure = NULL;
/* Register our per-process and per-thread structures. */
PsEstablishWin32Callouts(&CalloutData);
/* Register service hook callbacks */
#if DBG && defined(KDBG)
KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
#endif
/* Create the global USER heap */
GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
&GlobalUserHeapBase,
1 * 1024 * 1024); /* FIXME: 1 MB for now... */
if (GlobalUserHeap == NULL)
{
DPRINT1("Failed to initialize the global heap!\n");
return STATUS_UNSUCCESSFUL;
}
/* Allocate global server info structure */
gpsi = UserHeapAlloc(sizeof(*gpsi));
if (!gpsi)
{
DPRINT1("Failed allocate server info structure!\n");
return STATUS_UNSUCCESSFUL;
}
RtlZeroMemory(gpsi, sizeof(*gpsi));
DPRINT("Global Server Data -> %p\n", gpsi);
NT_ROF(InitGdiHandleTable());
NT_ROF(InitPaletteImpl());
/* Create stock objects, ie. precreated objects commonly
used by win32 applications */
CreateStockObjects();
CreateSysColorObjects();
NT_ROF(InitBrushImpl());
NT_ROF(InitPDEVImpl());
NT_ROF(InitLDEVImpl());
NT_ROF(InitDeviceImpl());
NT_ROF(InitDcImpl());
NT_ROF(InitUserImpl());
NT_ROF(InitWindowStationImpl());
NT_ROF(InitDesktopImpl());
NT_ROF(InitInputImpl());
NT_ROF(InitKeyboardImpl());
NT_ROF(MsqInitializeImpl());
NT_ROF(InitTimerImpl());
NT_ROF(InitDCEImpl());
gusLanguageID = UserGetLanguageID();
/* Initialize FreeType library */
if (!InitFontSupport())
{
DPRINT1("Unable to initialize font support\n");
return Status;
}
return STATUS_SUCCESS;
}
/* EOF */