reactos/win32ss/user/ntuser/main.c

1069 lines
31 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.
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;
}
/*
* 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;
IntFreeImeHotKeys();
if (gpwlCache)
{
ExFreePoolWithTag(gpwlCache, USERTAG_WINDOWLIST);
gpwlCache = 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 */
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);
ObReferenceObject(Thread);
IntReferenceThreadInfo(ptiCurrent);
*W32Thread = ptiCurrent;
return STATUS_SUCCESS;
}
/*
* 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);
ObDereferenceObject(pti->pEThread);
ExFreePoolWithTag(pti, USERTAG_THREADINFO);
IntDereferenceProcessInfo(ppi);
{
// Find another queue for mouse cursor.
MSG msg;
msg.message = WM_MOUSEMOVE;
msg.wParam = UserGetMouseButtonsState();
msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
msg.pt = gpsi->ptCursor;
co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
}
}
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;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
PKL pDefKL;
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;
ptiCurrent->pcti = &ptiCurrent->cti;
/* 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;
}
ptiCurrent->pcti->timeLastRead = EngGetTickCount32();
ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
if (ptiCurrent->MessageQueue == NULL)
{
ERR_CH(UserThread, "Failed to allocate message loop\n");
Status = STATUS_NO_MEMORY;
goto error;
}
pDefKL = W32kGetDefaultKeyLayout();
UserAssignmentLock((PVOID*)&(ptiCurrent->KeyboardLayout), pDefKL);
ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
// FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
/* CSRSS threads have some special features */
if (Process == gpepCSRSS || !gpepCSRSS)
ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
/* 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 (pDefKL)
{
pci->hKL = pDefKL->hkl;
pci->CodePage = pDefKL->CodePage;
}
/* Populate dwExpWinVer */
if (Process->Peb)
ptiCurrent->dwExpWinVer = RtlGetExpWinVer(Process->SectionBaseAddress);
else
ptiCurrent->dwExpWinVer = WINVER_WINNT4;
pci->dwExpWinVer = ptiCurrent->dwExpWinVer;
/* 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->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;
/* Create the default input context */
if (IS_IMM_MODE())
{
(VOID)UserCreateInputContext(0);
}
/* 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);
// Win: xxxDestroyThreadInfo
NTSTATUS
NTAPI
ExitThreadCallback(PETHREAD Thread)
{
PTHREADINFO *ppti;
PSINGLE_LIST_ENTRY psle;
PPROCESSINFO ppiCurrent;
PEPROCESS Process;
PTHREADINFO ptiCurrent;
PWINDOWLIST pwl, pwlNext;
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);
if (gpwlList)
{
for (pwl = gpwlList; pwl; pwl = pwlNext)
{
pwlNext = pwl->pNextList;
if (pwl->pti == ptiCurrent)
IntFreeHwndList(pwl);
}
}
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;
}
UserAssignmentUnlock((PVOID*)&ptiCurrent->spDefaultImc);
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 DBG
ptiCurrent->cRefObjectCo--;
#endif
}
}
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 (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout)))
ptiCurrent->pClientInfo->hKL = NULL;
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;
ASSERT(ptiCurrent->cRefObjectCo == 0);
/* The thread is dying */
PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
/* Dereference the THREADINFO */
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!
FreeFontSupport();
ResetCsrApiPort();
ResetCsrProcess();
IntWin32PowerManagementCleanup();
}
// Return on failure
#define NT_ROF(x) \
{ \
Status = (x); \
if (!NT_SUCCESS(Status)) \
{ \
DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
return Status; \
} \
}
// Lock & return on failure
#define USERLOCK_AND_ROF(x) \
{ \
UserEnterExclusive(); \
Status = (x); \
UserLeave(); \
if (!NT_SUCCESS(Status)) \
{ \
DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
return Status; \
} \
}
/*
* This definition doesn't work
*/
CODE_SEG("INIT")
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 = IntHandlePowerEvent;
CalloutData.PowerStateCallout = IntHandlePowerState;
// 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;
}
/* Init the global user lock */
ExInitializeResourceLite(&UserLock);
/* Lock while we use the heap (UserHeapAlloc asserts on this) */
UserEnterExclusive();
/* Allocate global server info structure */
gpsi = UserHeapAlloc(sizeof(*gpsi));
UserLeave();
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());
USERLOCK_AND_ROF(InitUserImpl());
NT_ROF(InitWindowStationImpl());
NT_ROF(InitDesktopImpl());
NT_ROF(InitInputImpl());
NT_ROF(InitKeyboardImpl());
NT_ROF(MsqInitializeImpl());
NT_ROF(InitTimerImpl());
NT_ROF(InitDCEImpl());
return STATUS_SUCCESS;
}
/* EOF */