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