xref: /reactos/win32ss/user/ntuser/main.c (revision 139a3d66)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Driver entry and initialization of win32k
5  * FILE:             win32ss/user/ntuser/main.c
6  * PROGRAMER:
7  */
8 
9 #include <win32k.h>
10 #include <napi.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 #include <kdros.h>
15 
16 HANDLE hModuleWin;
17 
18 NTSTATUS ExitProcessCallback(PEPROCESS Process);
19 NTSTATUS NTAPI ExitThreadCallback(PETHREAD Thread);
20 
21 // TODO: Should be moved to some GDI header
22 NTSTATUS GdiProcessCreate(PEPROCESS Process);
23 NTSTATUS GdiProcessDestroy(PEPROCESS Process);
24 NTSTATUS GdiThreadCreate(PETHREAD Thread);
25 NTSTATUS GdiThreadDestroy(PETHREAD Thread);
26 
27 PSERVERINFO gpsi = NULL; // Global User Server Information.
28 
29 USHORT gusLanguageID;
30 PPROCESSINFO ppiScrnSaver;
31 PPROCESSINFO gppiList = NULL;
32 
33 extern ULONG_PTR Win32kSSDT[];
34 extern UCHAR Win32kSSPT[];
35 extern ULONG Win32kNumberOfSysCalls;
36 
37 #if DBG
38 void
39 NTAPI
40 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
41 {
42     GdiDbgPreServiceHook(ulSyscallId, pulArguments);
43     UserDbgPreServiceHook(ulSyscallId, pulArguments);
44 }
45 
46 ULONG_PTR
47 NTAPI
48 DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
49 {
50     ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
51     ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
52     return ulResult;
53 }
54 #endif
55 
56 
57 NTSTATUS
58 AllocW32Process(IN  PEPROCESS Process,
59                 OUT PPROCESSINFO* W32Process)
60 {
61     PPROCESSINFO ppiCurrent;
62 
63     TRACE_CH(UserProcess, "In AllocW32Process(0x%p)\n", Process);
64 
65     /* Check that we were not called with an already existing Win32 process info */
66     ppiCurrent = PsGetProcessWin32Process(Process);
67     if (ppiCurrent) return STATUS_SUCCESS;
68 
69     /* Allocate a new Win32 process info */
70     ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
71                                        sizeof(*ppiCurrent),
72                                        USERTAG_PROCESSINFO);
73     if (ppiCurrent == NULL)
74     {
75         ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
76                HandleToUlong(Process->UniqueProcessId));
77         return STATUS_NO_MEMORY;
78     }
79 
80     TRACE_CH(UserProcess, "Allocated ppi 0x%p for PID:0x%lx\n",
81              ppiCurrent, HandleToUlong(Process->UniqueProcessId));
82 
83     RtlZeroMemory(ppiCurrent, sizeof(*ppiCurrent));
84 
85     PsSetProcessWin32Process(Process, ppiCurrent, NULL);
86     IntReferenceProcessInfo(ppiCurrent);
87 
88     *W32Process = ppiCurrent;
89     return STATUS_SUCCESS;
90 }
91 
92 /*
93  * Called from IntDereferenceProcessInfo
94  */
95 VOID
96 UserDeleteW32Process(
97     _Pre_notnull_ __drv_freesMem(Mem) PPROCESSINFO ppiCurrent)
98 {
99     if (ppiCurrent->InputIdleEvent)
100     {
101         /* Free the allocated memory */
102         ExFreePoolWithTag(ppiCurrent->InputIdleEvent, USERTAG_EVENT);
103     }
104 
105     /* Close the startup desktop */
106     if (ppiCurrent->rpdeskStartup)
107         ObDereferenceObject(ppiCurrent->rpdeskStartup);
108 
109 #if DBG
110     if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
111     {
112         TRACE_PPI(ppiCurrent, UserObj, "Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
113         DbgUserDumpHandleTable();
114     }
115 #endif
116 
117     /* Free the PROCESSINFO */
118     ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
119 }
120 
121 NTSTATUS
122 UserProcessCreate(PEPROCESS Process)
123 {
124     PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
125     ASSERT(ppiCurrent);
126 
127     InitializeListHead(&ppiCurrent->DriverObjListHead);
128     ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
129 
130     {
131         PKEVENT Event;
132 
133         /* Allocate memory for the event structure */
134         Event = ExAllocatePoolWithTag(NonPagedPool,
135                                       sizeof(*Event),
136                                       USERTAG_EVENT);
137         if (Event)
138         {
139             /* Initialize the kernel event */
140             KeInitializeEvent(Event,
141                               SynchronizationEvent,
142                               FALSE);
143         }
144         else
145         {
146             /* Out of memory */
147             DPRINT("CreateEvent() failed\n");
148             KeBugCheck(0);
149         }
150 
151         /* Set the event */
152         ppiCurrent->InputIdleEvent = Event;
153         KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
154     }
155 
156     ppiCurrent->peProcess = Process;
157     ppiCurrent->W32Pid = HandleToUlong(PsGetProcessId(Process));
158 
159     /* Setup process flags */
160     ppiCurrent->W32PF_flags |= W32PF_PROCESSCONNECTED;
161     if (Process->Peb->ProcessParameters &&
162         (Process->Peb->ProcessParameters->WindowFlags & STARTF_SCREENSAVER))
163     {
164         ppiScrnSaver = ppiCurrent;
165         ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
166     }
167 
168     // FIXME: check if this process is allowed.
169     ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application will get it toggled off.
170 
171     return STATUS_SUCCESS;
172 }
173 
174 NTSTATUS
175 UserProcessDestroy(PEPROCESS Process)
176 {
177     PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
178     ASSERT(ppiCurrent);
179 
180     if (ppiScrnSaver == ppiCurrent)
181         ppiScrnSaver = NULL;
182 
183     /* Destroy user objects */
184     UserDestroyObjectsForOwner(gHandleTable, ppiCurrent);
185 
186     TRACE_CH(UserProcess, "Freeing ppi 0x%p\n", ppiCurrent);
187 #if DBG
188     if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
189     {
190         TRACE_CH(UserObj, "Dumping user handles at the end of the process %s (Info %p).\n",
191             ppiCurrent->peProcess->ImageFileName, ppiCurrent);
192         DbgUserDumpHandleTable();
193     }
194 #endif
195 
196     /* Remove it from the list of GUI apps */
197     co_IntGraphicsCheck(FALSE);
198 
199     /*
200      * Deregister logon application automatically
201      */
202     if (gpidLogon == ppiCurrent->peProcess->UniqueProcessId)
203         gpidLogon = 0;
204 
205     /* Close the current window station */
206     UserSetProcessWindowStation(NULL);
207 
208     if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL;
209 
210     if (ppiCurrent->hdeskStartup)
211     {
212         ZwClose(ppiCurrent->hdeskStartup);
213         ppiCurrent->hdeskStartup = NULL;
214     }
215 
216     /* Clean up the process icon cache */
217     IntCleanupCurIconCache(ppiCurrent);
218 
219     return STATUS_SUCCESS;
220 }
221 
222 NTSTATUS
223 InitProcessCallback(PEPROCESS Process)
224 {
225     NTSTATUS Status;
226     PPROCESSINFO ppiCurrent;
227     PVOID KernelMapping = NULL, UserMapping = NULL;
228 
229     /* We might be called with an already allocated win32 process */
230     ppiCurrent = PsGetProcessWin32Process(Process);
231     if (ppiCurrent != NULL)
232     {
233         /* There is no more to do for us (this is a success code!) */
234         return STATUS_ALREADY_WIN32;
235     }
236     // if (ppiCurrent->W32PF_flags & W32PF_PROCESSCONNECTED)
237         // return STATUS_ALREADY_WIN32;
238 
239     /* Allocate a new Win32 process info */
240     Status = AllocW32Process(Process, &ppiCurrent);
241     if (!NT_SUCCESS(Status))
242     {
243         ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
244                HandleToUlong(Process->UniqueProcessId));
245         return Status;
246     }
247 
248 #if DBG
249     DbgInitDebugChannels();
250 #if defined(KDBG)
251     KdRosRegisterCliCallback(DbgGdiKdbgCliCallback);
252 #endif
253 #endif
254 
255     /* Map the global user heap into the process */
256     Status = MapGlobalUserHeap(Process, &KernelMapping, &UserMapping);
257     if (!NT_SUCCESS(Status))
258     {
259         TRACE_CH(UserProcess, "Failed to map the global heap! 0x%x\n", Status);
260         goto error;
261     }
262 
263     TRACE_CH(UserProcess, "InitProcessCallback -- We have KernelMapping 0x%p and UserMapping 0x%p with delta = 0x%x\n",
264            KernelMapping, UserMapping, (ULONG_PTR)KernelMapping - (ULONG_PTR)UserMapping);
265 
266     /* Initialize USER process info */
267     Status = UserProcessCreate(Process);
268     if (!NT_SUCCESS(Status))
269     {
270         ERR_CH(UserProcess, "UserProcessCreate failed, Status 0x%08lx\n", Status);
271         goto error;
272     }
273 
274     /* Initialize GDI process info */
275     Status = GdiProcessCreate(Process);
276     if (!NT_SUCCESS(Status))
277     {
278         ERR_CH(UserProcess, "GdiProcessCreate failed, Status 0x%08lx\n", Status);
279         goto error;
280     }
281 
282     /* Add the process to the global list */
283     ppiCurrent->ppiNext = gppiList;
284     gppiList = ppiCurrent;
285 
286     return STATUS_SUCCESS;
287 
288 error:
289     ERR_CH(UserProcess, "InitProcessCallback failed! Freeing ppi 0x%p for PID:0x%lx\n",
290            ppiCurrent, HandleToUlong(Process->UniqueProcessId));
291     ExitProcessCallback(Process);
292     return Status;
293 }
294 
295 NTSTATUS
296 ExitProcessCallback(PEPROCESS Process)
297 {
298     PPROCESSINFO ppiCurrent, *pppi;
299 
300     /* Get the Win32 Process */
301     ppiCurrent = PsGetProcessWin32Process(Process);
302     ASSERT(ppiCurrent);
303     ASSERT(ppiCurrent->peProcess == Process);
304 
305     TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent);
306     ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
307 
308     /* Remove it from the list */
309     pppi = &gppiList;
310     while (*pppi != NULL && *pppi != ppiCurrent)
311     {
312         pppi = &(*pppi)->ppiNext;
313     }
314     ASSERT(*pppi == ppiCurrent);
315     *pppi = ppiCurrent->ppiNext;
316 
317     /* Cleanup GDI info */
318     GdiProcessDestroy(Process);
319 
320     /* Cleanup USER info */
321     UserProcessDestroy(Process);
322 
323     /* The process is dying */
324     PsSetProcessWin32Process(Process, NULL, ppiCurrent);
325     ppiCurrent->peProcess = NULL;
326 
327     /* Finally, dereference */
328     IntDereferenceProcessInfo(ppiCurrent);
329 
330     return STATUS_SUCCESS;
331 }
332 
333 NTSTATUS
334 APIENTRY
335 Win32kProcessCallback(PEPROCESS Process,
336                       BOOLEAN Initialize)
337 {
338     NTSTATUS Status;
339 
340     ASSERT(Process->Peb);
341 
342     TRACE_CH(UserProcess, "Win32kProcessCallback -->\n");
343 
344     UserEnterExclusive();
345 
346     if (Initialize)
347     {
348         Status = InitProcessCallback(Process);
349     }
350     else
351     {
352         Status = ExitProcessCallback(Process);
353     }
354 
355     UserLeave();
356 
357     TRACE_CH(UserProcess, "<-- Win32kProcessCallback\n");
358 
359     return Status;
360 }
361 
362 
363 
364 NTSTATUS
365 AllocW32Thread(IN  PETHREAD Thread,
366                OUT PTHREADINFO* W32Thread)
367 {
368     PTHREADINFO ptiCurrent;
369 
370     TRACE_CH(UserThread, "In AllocW32Thread(0x%p)\n", Thread);
371 
372     /* Check that we were not called with an already existing Win32 thread info */
373     ptiCurrent = PsGetThreadWin32Thread(Thread);
374     NT_ASSERT(ptiCurrent == NULL);
375 
376     /* Allocate a new Win32 thread info */
377     ptiCurrent = ExAllocatePoolWithTag(NonPagedPool,
378                                        sizeof(*ptiCurrent),
379                                        USERTAG_THREADINFO);
380     if (ptiCurrent == NULL)
381     {
382         ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
383                HandleToUlong(Thread->Cid.UniqueThread));
384         return STATUS_NO_MEMORY;
385     }
386 
387     TRACE_CH(UserThread, "Allocated pti 0x%p for TID:0x%lx\n",
388              ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
389 
390     RtlZeroMemory(ptiCurrent, sizeof(*ptiCurrent));
391 
392     PsSetThreadWin32Thread(Thread, ptiCurrent, NULL);
393     ObReferenceObject(Thread);
394     IntReferenceThreadInfo(ptiCurrent);
395 
396     *W32Thread = ptiCurrent;
397     return STATUS_SUCCESS;
398 }
399 
400 /*
401  * Called from IntDereferenceThreadInfo
402  */
403 VOID
404 UserDeleteW32Thread(PTHREADINFO pti)
405 {
406    PPROCESSINFO ppi = pti->ppi;
407 
408    TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
409 
410    /* Free the message queue */
411    if (pti->MessageQueue)
412    {
413       MsqDestroyMessageQueue(pti);
414    }
415 
416    MsqCleanupThreadMsgs(pti);
417 
418    ObDereferenceObject(pti->pEThread);
419 
420    ExFreePoolWithTag(pti, USERTAG_THREADINFO);
421 
422    IntDereferenceProcessInfo(ppi);
423 
424    {
425       // Find another queue for mouse cursor.
426       MSG msg;
427       msg.message = WM_MOUSEMOVE;
428       msg.wParam = UserGetMouseButtonsState();
429       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
430       msg.pt = gpsi->ptCursor;
431       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
432    }
433 }
434 
435 NTSTATUS
436 UserThreadCreate(PETHREAD Thread)
437 {
438     return STATUS_SUCCESS;
439 }
440 
441 NTSTATUS
442 UserThreadDestroy(PETHREAD Thread)
443 {
444     return STATUS_SUCCESS;
445 }
446 
447 NTSTATUS NTAPI
448 InitThreadCallback(PETHREAD Thread)
449 {
450     PEPROCESS Process;
451     PCLIENTINFO pci;
452     PTHREADINFO ptiCurrent;
453     int i;
454     NTSTATUS Status = STATUS_SUCCESS;
455     PTEB pTeb;
456     PRTL_USER_PROCESS_PARAMETERS ProcessParams;
457 
458     Process = Thread->ThreadsProcess;
459 
460     pTeb = NtCurrentTeb();
461     ASSERT(pTeb);
462 
463     ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
464 
465     /* Allocate a new Win32 thread info */
466     Status = AllocW32Thread(Thread, &ptiCurrent);
467     if (!NT_SUCCESS(Status))
468     {
469         ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
470                HandleToUlong(Thread->Cid.UniqueThread));
471         return Status;
472     }
473 
474     /* Initialize the THREADINFO */
475     ptiCurrent->pEThread = Thread;
476     ptiCurrent->ppi = PsGetProcessWin32Process(Process);
477     IntReferenceProcessInfo(ptiCurrent->ppi);
478     pTeb->Win32ThreadInfo = ptiCurrent;
479     ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
480     ptiCurrent->pcti = &ptiCurrent->cti;
481 
482     /* Mark the process as having threads */
483     ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
484 
485     InitializeListHead(&ptiCurrent->WindowListHead);
486     InitializeListHead(&ptiCurrent->W32CallbackListHead);
487     InitializeListHead(&ptiCurrent->PostedMessagesListHead);
488     InitializeListHead(&ptiCurrent->SentMessagesListHead);
489     InitializeListHead(&ptiCurrent->PtiLink);
490     for (i = 0; i < NB_HOOKS; i++)
491     {
492         InitializeListHead(&ptiCurrent->aphkStart[i]);
493     }
494     ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
495     ptiCurrent->ppi->ptiList = ptiCurrent;
496     ptiCurrent->ppi->cThreads++;
497 
498     ptiCurrent->hEventQueueClient = NULL;
499     Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
500                             NULL, SynchronizationEvent, FALSE);
501     if (!NT_SUCCESS(Status))
502     {
503         ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
504         goto error;
505     }
506     Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
507                                        *ExEventObjectType, UserMode,
508                                        (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
509     if (!NT_SUCCESS(Status))
510     {
511         ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
512         ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
513         ptiCurrent->hEventQueueClient = NULL;
514         goto error;
515     }
516 
517     ptiCurrent->pcti->timeLastRead = EngGetTickCount32();
518 
519     ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
520     if (ptiCurrent->MessageQueue == NULL)
521     {
522         ERR_CH(UserThread, "Failed to allocate message loop\n");
523         Status = STATUS_NO_MEMORY;
524         goto error;
525     }
526 
527     ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
528     if (ptiCurrent->KeyboardLayout)
529         UserReferenceObject(ptiCurrent->KeyboardLayout);
530 
531     ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
532 
533     // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
534 
535     /* CSRSS threads have some special features */
536     if (Process == gpepCSRSS || !gpepCSRSS)
537         ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
538 
539     /* Initialize the CLIENTINFO */
540     pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
541     RtlZeroMemory(pci, sizeof(*pci));
542     pci->ppi = ptiCurrent->ppi;
543     pci->fsHooks = ptiCurrent->fsHooks;
544     pci->dwTIFlags = ptiCurrent->TIF_flags;
545     if (ptiCurrent->KeyboardLayout)
546     {
547         pci->hKL = ptiCurrent->KeyboardLayout->hkl;
548         pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
549     }
550 
551     /* Need to pass the user Startup Information to the current process. */
552     if ( ProcessParams )
553     {
554        if ( ptiCurrent->ppi->usi.cb == 0 )      // Not initialized yet.
555        {
556           if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
557           {
558              ptiCurrent->ppi->usi.cb          = sizeof(USERSTARTUPINFO);
559              ptiCurrent->ppi->usi.dwX         = ProcessParams->StartingX;
560              ptiCurrent->ppi->usi.dwY         = ProcessParams->StartingY;
561              ptiCurrent->ppi->usi.dwXSize     = ProcessParams->CountX;
562              ptiCurrent->ppi->usi.dwYSize     = ProcessParams->CountY;
563              ptiCurrent->ppi->usi.dwFlags     = ProcessParams->WindowFlags;
564              ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
565           }
566        }
567     }
568 
569     /*
570      * Assign a default window station and desktop to the process.
571      * Do not try to open a desktop or window station before the very first
572      * (interactive) window station has been created by Winlogon.
573      */
574     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
575         ptiCurrent->ppi->hdeskStartup == NULL &&
576         InputWindowStation != NULL)
577     {
578         HWINSTA hWinSta = NULL;
579         HDESK hDesk = NULL;
580         UNICODE_STRING DesktopPath;
581         PDESKTOP pdesk;
582 
583         /*
584          * Inherit the thread desktop and process window station (if not yet inherited)
585          * from the process startup info structure. See documentation of CreateProcess().
586          */
587         Status = STATUS_UNSUCCESSFUL;
588         if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
589         {
590             Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
591         }
592         if (!NT_SUCCESS(Status))
593         {
594             RtlInitUnicodeString(&DesktopPath, NULL);
595         }
596 
597         Status = IntResolveDesktop(Process,
598                                    &DesktopPath,
599                                    !!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP),
600                                    &hWinSta,
601                                    &hDesk);
602 
603         if (DesktopPath.Buffer)
604             ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
605 
606         if (!NT_SUCCESS(Status))
607         {
608             ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n");
609             goto error;
610         }
611 
612         if (!UserSetProcessWindowStation(hWinSta))
613         {
614             Status = STATUS_UNSUCCESSFUL;
615             ERR_CH(UserThread, "Failed to set initial process winsta\n");
616             goto error;
617         }
618 
619         /* Validate the new desktop */
620         Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
621         if (!NT_SUCCESS(Status))
622         {
623             ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
624             goto error;
625         }
626 
627         /* Store the parsed desktop as the initial desktop */
628         ASSERT(ptiCurrent->ppi->hdeskStartup == NULL);
629         ASSERT(Process->UniqueProcessId != gpidLogon);
630         ptiCurrent->ppi->hdeskStartup = hDesk;
631         ptiCurrent->ppi->rpdeskStartup = pdesk;
632     }
633 
634     if (ptiCurrent->ppi->hdeskStartup != NULL)
635     {
636         if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
637         {
638             ERR_CH(UserThread, "Failed to set thread desktop\n");
639             Status = STATUS_UNSUCCESSFUL;
640             goto error;
641         }
642     }
643 
644     /* Mark the thread as fully initialized */
645     ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
646 
647     if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
648          (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
649     {
650         ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
651     }
652     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
653 
654     /* Last things to do only if we are not a SYSTEM or CSRSS thread */
655     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
656     {
657         /* Callback to User32 Client Thread Setup */
658         TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
659         Status = co_IntClientThreadSetup();
660         if (!NT_SUCCESS(Status))
661         {
662             ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
663             goto error;
664         }
665         TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
666     }
667     else
668     {
669         TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
670     }
671 
672     TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
673     return STATUS_SUCCESS;
674 
675 error:
676     ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
677            ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
678     ExitThreadCallback(Thread);
679     return Status;
680 }
681 
682 VOID
683 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
684 
685 NTSTATUS
686 NTAPI
687 ExitThreadCallback(PETHREAD Thread)
688 {
689     PTHREADINFO *ppti;
690     PSINGLE_LIST_ENTRY psle;
691     PPROCESSINFO ppiCurrent;
692     PEPROCESS Process;
693     PTHREADINFO ptiCurrent;
694 
695     Process = Thread->ThreadsProcess;
696 
697     /* Get the Win32 Thread */
698     ptiCurrent = PsGetThreadWin32Thread(Thread);
699     ASSERT(ptiCurrent);
700 
701     TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
702 
703     ptiCurrent->TIF_flags |= TIF_INCLEANUP;
704     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
705 
706     ppiCurrent = ptiCurrent->ppi;
707     ASSERT(ppiCurrent);
708 
709     IsRemoveAttachThread(ptiCurrent);
710 
711     ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
712     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
713 
714     UserCloseClipboard();
715 
716     /* Decrement thread count and check if its 0 */
717     ppiCurrent->cThreads--;
718 
719     if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
720     {
721         /* Do now some process cleanup that requires a valid win32 thread */
722         if (ptiCurrent->ppi->cThreads == 0)
723         {
724             /* Check if we have registered the user api hook */
725             if (ptiCurrent->ppi == ppiUahServer)
726             {
727                 /* Unregister the api hook */
728                 UserUnregisterUserApiHook();
729             }
730 
731             /* Notify logon application to restart shell if needed */
732             if (ptiCurrent->pDeskInfo)
733             {
734                 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
735                 {
736                     DWORD ExitCode = PsGetProcessExitStatus(Process);
737 
738                    TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
739 
740                     UserPostMessage(hwndSAS,
741                                     WM_LOGONNOTIFY,
742                                     LN_SHELL_EXITED,
743                                     ExitCode);
744 
745                     ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
746                 }
747             }
748         }
749 
750         DceFreeThreadDCE(ptiCurrent);
751         DestroyTimersForThread(ptiCurrent);
752         KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
753         UnregisterThreadHotKeys(ptiCurrent);
754 
755         if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
756         {
757             DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
758             ASSERT(FALSE);
759             return STATUS_UNSUCCESSFUL;
760         }
761 
762         if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
763             ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
764         {
765             TRACE_CH(UserThread, "DestroyProcessClasses\n");
766             /* no process windows should exist at this point, or the function will assert! */
767             DestroyProcessClasses(ppiCurrent);
768             ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
769         }
770 
771         IntBlockInput(ptiCurrent, FALSE);
772         IntCleanupThreadCallbacks(ptiCurrent);
773 
774         /* cleanup user object references stack */
775         psle = PopEntryList(&ptiCurrent->ReferencesList);
776         while (psle)
777         {
778             PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
779             TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
780             UserDereferenceObject(ref->obj);
781 
782             psle = PopEntryList(&ptiCurrent->ReferencesList);
783         }
784     }
785 
786     if (ptiCurrent->cEnterCount)
787     {
788        KeSetKernelStackSwapEnable(TRUE);
789        ptiCurrent->cEnterCount = 0;
790     }
791 
792     /* Find the THREADINFO in the PROCESSINFO's list */
793     ppti = &ppiCurrent->ptiList;
794     while (*ppti != NULL && *ppti != ptiCurrent)
795     {
796         ppti = &((*ppti)->ptiSibling);
797     }
798 
799     /* we must have found it */
800     ASSERT(*ppti == ptiCurrent);
801 
802     /* Remove it from the list */
803     *ppti = ptiCurrent->ptiSibling;
804 
805     if (ptiCurrent->KeyboardLayout)
806         UserDereferenceObject(ptiCurrent->KeyboardLayout);
807 
808     if (gptiForeground == ptiCurrent)
809     {
810 //       IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
811 //       IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
812 
813        gptiForeground = NULL;
814     }
815 
816     /* Restore display mode when we are the last thread, and we changed the display mode */
817     if (ppiCurrent->cThreads == 0)
818         UserDisplayNotifyShutdown(ppiCurrent);
819 
820 
821     // Fixes CORE-6384 & CORE-7030.
822 /*    if (ptiLastInput == ptiCurrent)
823     {
824        if (!ppiCurrent->ptiList)
825           ptiLastInput = gptiForeground;
826        else
827           ptiLastInput = ppiCurrent->ptiList;
828        ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
829     }
830 */
831     TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
832 
833     IntSetThreadDesktop(NULL, TRUE);
834 
835     if (ptiCurrent->hEventQueueClient != NULL)
836     {
837        ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
838        ObDereferenceObject(ptiCurrent->pEventQueueServer);
839     }
840     ptiCurrent->hEventQueueClient = NULL;
841 
842     /* The thread is dying */
843     PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
844 
845     /* Dereference the THREADINFO */
846     IntDereferenceThreadInfo(ptiCurrent);
847 
848     return STATUS_SUCCESS;
849 }
850 
851 NTSTATUS
852 APIENTRY
853 Win32kThreadCallback(PETHREAD Thread,
854                      PSW32THREADCALLOUTTYPE Type)
855 {
856     NTSTATUS Status;
857 
858     ASSERT(NtCurrentTeb());
859 
860     UserEnterExclusive();
861 
862     if (Type == PsW32ThreadCalloutInitialize)
863     {
864         ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
865         Status = InitThreadCallback(Thread);
866     }
867     else // if (Type == PsW32ThreadCalloutExit)
868     {
869         ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
870         Status = ExitThreadCallback(Thread);
871     }
872 
873     UserLeave();
874 
875     return Status;
876 }
877 
878 _Function_class_(DRIVER_UNLOAD)
879 VOID NTAPI
880 DriverUnload(IN PDRIVER_OBJECT DriverObject)
881 {
882     // TODO: Do more cleanup!
883 
884     ResetCsrApiPort();
885     ResetCsrProcess();
886 }
887 
888 // Return on failure
889 #define NT_ROF(x) \
890 { \
891     Status = (x); \
892     if (!NT_SUCCESS(Status)) \
893     { \
894         DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
895         return Status; \
896     } \
897 }
898 
899 /*
900  * This definition doesn't work
901  */
902 INIT_FUNCTION
903 NTSTATUS
904 APIENTRY
905 DriverEntry(
906     IN PDRIVER_OBJECT  DriverObject,
907     IN PUNICODE_STRING RegistryPath)
908 {
909     NTSTATUS Status;
910     BOOLEAN Result;
911     WIN32_CALLOUTS_FPNS CalloutData = {0};
912     PVOID GlobalUserHeapBase = NULL;
913 
914     /*
915      * Register user mode call interface
916      * (system service table index = 1)
917      */
918     Result = KeAddSystemServiceTable(Win32kSSDT,
919                                      NULL,
920                                      Win32kNumberOfSysCalls,
921                                      Win32kSSPT,
922                                      1);
923     if (Result == FALSE)
924     {
925         DPRINT1("Adding system services failed!\n");
926         return STATUS_UNSUCCESSFUL;
927     }
928 
929     hModuleWin = MmPageEntireDriver(DriverEntry);
930     DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
931 
932     DriverObject->DriverUnload = DriverUnload;
933 
934     /* Register Object Manager Callbacks */
935     CalloutData.ProcessCallout = Win32kProcessCallback;
936     CalloutData.ThreadCallout = Win32kThreadCallback;
937     // CalloutData.GlobalAtomTableCallout = NULL;
938     // CalloutData.PowerEventCallout = NULL;
939     // CalloutData.PowerStateCallout = NULL;
940     // CalloutData.JobCallout = NULL;
941     CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
942     CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
943     CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
944     CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
945     CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
946     CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose;
947     // CalloutData.WindowStationCloseProcedure = NULL;
948     CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
949     CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
950     // CalloutData.WindowStationOpenProcedure = NULL;
951 
952     /* Register our per-process and per-thread structures. */
953     PsEstablishWin32Callouts(&CalloutData);
954 
955     /* Register service hook callbacks */
956 #if DBG && defined(KDBG)
957     KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
958     KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
959 #endif
960 
961     /* Create the global USER heap */
962     GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
963                                     &GlobalUserHeapBase,
964                                     1 * 1024 * 1024); /* FIXME: 1 MB for now... */
965     if (GlobalUserHeap == NULL)
966     {
967         DPRINT1("Failed to initialize the global heap!\n");
968         return STATUS_UNSUCCESSFUL;
969     }
970 
971     /* Allocate global server info structure */
972     gpsi = UserHeapAlloc(sizeof(*gpsi));
973     if (!gpsi)
974     {
975         DPRINT1("Failed allocate server info structure!\n");
976         return STATUS_UNSUCCESSFUL;
977     }
978 
979     RtlZeroMemory(gpsi, sizeof(*gpsi));
980     DPRINT("Global Server Data -> %p\n", gpsi);
981 
982     NT_ROF(InitGdiHandleTable());
983     NT_ROF(InitPaletteImpl());
984 
985     /* Create stock objects, ie. precreated objects commonly
986        used by win32 applications */
987     CreateStockObjects();
988     CreateSysColorObjects();
989 
990     NT_ROF(InitBrushImpl());
991     NT_ROF(InitPDEVImpl());
992     NT_ROF(InitLDEVImpl());
993     NT_ROF(InitDeviceImpl());
994     NT_ROF(InitDcImpl());
995     NT_ROF(InitUserImpl());
996     NT_ROF(InitWindowStationImpl());
997     NT_ROF(InitDesktopImpl());
998     NT_ROF(InitInputImpl());
999     NT_ROF(InitKeyboardImpl());
1000     NT_ROF(MsqInitializeImpl());
1001     NT_ROF(InitTimerImpl());
1002     NT_ROF(InitDCEImpl());
1003 
1004     gusLanguageID = UserGetLanguageID();
1005 
1006     /* Initialize FreeType library */
1007     if (!InitFontSupport())
1008     {
1009         DPRINT1("Unable to initialize font support\n");
1010         return Status;
1011     }
1012 
1013     return STATUS_SUCCESS;
1014 }
1015 
1016 /* EOF */
1017