xref: /reactos/win32ss/user/ntuser/main.c (revision ccef43f3)
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 /* Win: xxxCreateThreadInfo */
456 NTSTATUS NTAPI
457 InitThreadCallback(PETHREAD Thread)
458 {
459     PEPROCESS Process;
460     PCLIENTINFO pci;
461     PTHREADINFO ptiCurrent;
462     int i;
463     NTSTATUS Status = STATUS_SUCCESS;
464     PTEB pTeb;
465     PRTL_USER_PROCESS_PARAMETERS ProcessParams;
466     PKL pDefKL;
467 
468     Process = Thread->ThreadsProcess;
469 
470     pTeb = NtCurrentTeb();
471     ASSERT(pTeb);
472 
473     ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
474 
475     /* Allocate a new Win32 thread info */
476     Status = AllocW32Thread(Thread, &ptiCurrent);
477     if (!NT_SUCCESS(Status))
478     {
479         ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
480                HandleToUlong(Thread->Cid.UniqueThread));
481         return Status;
482     }
483 
484     /* Initialize the THREADINFO */
485     ptiCurrent->pEThread = Thread;
486     ptiCurrent->ppi = PsGetProcessWin32Process(Process);
487     IntReferenceProcessInfo(ptiCurrent->ppi);
488     pTeb->Win32ThreadInfo = ptiCurrent;
489     ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
490     ptiCurrent->pcti = &ptiCurrent->cti;
491 
492     /* Mark the process as having threads */
493     ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
494 
495     InitializeListHead(&ptiCurrent->WindowListHead);
496     InitializeListHead(&ptiCurrent->W32CallbackListHead);
497     InitializeListHead(&ptiCurrent->PostedMessagesListHead);
498     InitializeListHead(&ptiCurrent->SentMessagesListHead);
499     InitializeListHead(&ptiCurrent->PtiLink);
500     for (i = 0; i < NB_HOOKS; i++)
501     {
502         InitializeListHead(&ptiCurrent->aphkStart[i]);
503     }
504     ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
505     ptiCurrent->ppi->ptiList = ptiCurrent;
506     ptiCurrent->ppi->cThreads++;
507 
508     ptiCurrent->hEventQueueClient = NULL;
509     Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
510                             NULL, SynchronizationEvent, FALSE);
511     if (!NT_SUCCESS(Status))
512     {
513         ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
514         goto error;
515     }
516     Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
517                                        *ExEventObjectType, UserMode,
518                                        (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
519     if (!NT_SUCCESS(Status))
520     {
521         ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
522         ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
523         ptiCurrent->hEventQueueClient = NULL;
524         goto error;
525     }
526 
527     ptiCurrent->pcti->timeLastRead = EngGetTickCount32();
528 
529     ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
530     if (ptiCurrent->MessageQueue == NULL)
531     {
532         ERR_CH(UserThread, "Failed to allocate message loop\n");
533         Status = STATUS_NO_MEMORY;
534         goto error;
535     }
536 
537     pDefKL = W32kGetDefaultKeyLayout();
538     UserAssignmentLock((PVOID*)&(ptiCurrent->KeyboardLayout), pDefKL);
539 
540     ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
541 
542     // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
543 
544     /* CSRSS threads have some special features */
545     if (Process == gpepCSRSS || !gpepCSRSS)
546         ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
547 
548     /* Initialize the CLIENTINFO */
549     pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
550     RtlZeroMemory(pci, sizeof(*pci));
551     pci->ppi = ptiCurrent->ppi;
552     pci->fsHooks = ptiCurrent->fsHooks;
553     pci->dwTIFlags = ptiCurrent->TIF_flags;
554     if (pDefKL)
555     {
556         pci->hKL = pDefKL->hkl;
557         pci->CodePage = pDefKL->CodePage;
558     }
559 
560     /* Need to pass the user Startup Information to the current process. */
561     if ( ProcessParams )
562     {
563        if ( ptiCurrent->ppi->usi.cb == 0 )      // Not initialized yet.
564        {
565           if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
566           {
567              ptiCurrent->ppi->usi.cb          = sizeof(USERSTARTUPINFO);
568              ptiCurrent->ppi->usi.dwX         = ProcessParams->StartingX;
569              ptiCurrent->ppi->usi.dwY         = ProcessParams->StartingY;
570              ptiCurrent->ppi->usi.dwXSize     = ProcessParams->CountX;
571              ptiCurrent->ppi->usi.dwYSize     = ProcessParams->CountY;
572              ptiCurrent->ppi->usi.dwFlags     = ProcessParams->WindowFlags;
573              ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
574           }
575        }
576     }
577 
578     /*
579      * Assign a default window station and desktop to the process.
580      * Do not try to open a desktop or window station before the very first
581      * (interactive) window station has been created by Winlogon.
582      */
583     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
584         ptiCurrent->ppi->hdeskStartup == NULL &&
585         InputWindowStation != NULL)
586     {
587         HWINSTA hWinSta = NULL;
588         HDESK hDesk = NULL;
589         UNICODE_STRING DesktopPath;
590         PDESKTOP pdesk;
591 
592         /*
593          * Inherit the thread desktop and process window station (if not yet inherited)
594          * from the process startup info structure. See documentation of CreateProcess().
595          */
596         Status = STATUS_UNSUCCESSFUL;
597         if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
598         {
599             Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
600         }
601         if (!NT_SUCCESS(Status))
602         {
603             RtlInitUnicodeString(&DesktopPath, NULL);
604         }
605 
606         Status = IntResolveDesktop(Process,
607                                    &DesktopPath,
608                                    !!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP),
609                                    &hWinSta,
610                                    &hDesk);
611 
612         if (DesktopPath.Buffer)
613             ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
614 
615         if (!NT_SUCCESS(Status))
616         {
617             ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n");
618             goto error;
619         }
620 
621         if (!UserSetProcessWindowStation(hWinSta))
622         {
623             Status = STATUS_UNSUCCESSFUL;
624             ERR_CH(UserThread, "Failed to set initial process winsta\n");
625             goto error;
626         }
627 
628         /* Validate the new desktop */
629         Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
630         if (!NT_SUCCESS(Status))
631         {
632             ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
633             goto error;
634         }
635 
636         /* Store the parsed desktop as the initial desktop */
637         ASSERT(ptiCurrent->ppi->hdeskStartup == NULL);
638         ASSERT(Process->UniqueProcessId != gpidLogon);
639         ptiCurrent->ppi->hdeskStartup = hDesk;
640         ptiCurrent->ppi->rpdeskStartup = pdesk;
641     }
642 
643     if (ptiCurrent->ppi->hdeskStartup != NULL)
644     {
645         if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
646         {
647             ERR_CH(UserThread, "Failed to set thread desktop\n");
648             Status = STATUS_UNSUCCESSFUL;
649             goto error;
650         }
651     }
652 
653     /* Mark the thread as fully initialized */
654     ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
655 
656     if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
657          (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
658     {
659         ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
660     }
661     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
662 
663     /* Create the default input context */
664     if (IS_IMM_MODE())
665     {
666         (VOID)UserCreateInputContext(0);
667     }
668 
669     /* Last things to do only if we are not a SYSTEM or CSRSS thread */
670     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
671     {
672         /* Callback to User32 Client Thread Setup */
673         TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
674         Status = co_IntClientThreadSetup();
675         if (!NT_SUCCESS(Status))
676         {
677             ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
678             goto error;
679         }
680         TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
681     }
682     else
683     {
684         TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
685     }
686 
687     TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
688     return STATUS_SUCCESS;
689 
690 error:
691     ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
692            ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
693     ExitThreadCallback(Thread);
694     return Status;
695 }
696 
697 VOID
698 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
699 
700 // Win: xxxDestroyThreadInfo
701 NTSTATUS
702 NTAPI
703 ExitThreadCallback(PETHREAD Thread)
704 {
705     PTHREADINFO *ppti;
706     PSINGLE_LIST_ENTRY psle;
707     PPROCESSINFO ppiCurrent;
708     PEPROCESS Process;
709     PTHREADINFO ptiCurrent;
710     PWINDOWLIST pwl, pwlNext;
711 
712     Process = Thread->ThreadsProcess;
713 
714     /* Get the Win32 Thread */
715     ptiCurrent = PsGetThreadWin32Thread(Thread);
716     ASSERT(ptiCurrent);
717 
718     TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
719 
720     ptiCurrent->TIF_flags |= TIF_INCLEANUP;
721     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
722 
723     ppiCurrent = ptiCurrent->ppi;
724     ASSERT(ppiCurrent);
725 
726     IsRemoveAttachThread(ptiCurrent);
727 
728     if (gpwlList)
729     {
730         for (pwl = gpwlList; pwl; pwl = pwlNext)
731         {
732             pwlNext = pwl->pNextList;
733             if (pwl->pti == ptiCurrent)
734                 IntFreeHwndList(pwl);
735         }
736     }
737 
738     ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
739     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
740 
741     UserCloseClipboard();
742 
743     /* Decrement thread count and check if its 0 */
744     ppiCurrent->cThreads--;
745 
746     if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
747     {
748         /* Do now some process cleanup that requires a valid win32 thread */
749         if (ptiCurrent->ppi->cThreads == 0)
750         {
751             /* Check if we have registered the user api hook */
752             if (ptiCurrent->ppi == ppiUahServer)
753             {
754                 /* Unregister the api hook */
755                 UserUnregisterUserApiHook();
756             }
757 
758             /* Notify logon application to restart shell if needed */
759             if (ptiCurrent->pDeskInfo)
760             {
761                 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
762                 {
763                     DWORD ExitCode = PsGetProcessExitStatus(Process);
764 
765                    TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
766 
767                     UserPostMessage(hwndSAS,
768                                     WM_LOGONNOTIFY,
769                                     LN_SHELL_EXITED,
770                                     ExitCode);
771 
772                     ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
773                 }
774             }
775         }
776 
777         DceFreeThreadDCE(ptiCurrent);
778         DestroyTimersForThread(ptiCurrent);
779         KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
780         UnregisterThreadHotKeys(ptiCurrent);
781 
782         if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
783         {
784             DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
785             ASSERT(FALSE);
786             return STATUS_UNSUCCESSFUL;
787         }
788         UserAssignmentUnlock((PVOID*)&ptiCurrent->spDefaultImc);
789 
790         if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
791             ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
792         {
793             TRACE_CH(UserThread, "DestroyProcessClasses\n");
794             /* no process windows should exist at this point, or the function will assert! */
795             DestroyProcessClasses(ppiCurrent);
796             ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
797         }
798 
799         IntBlockInput(ptiCurrent, FALSE);
800         IntCleanupThreadCallbacks(ptiCurrent);
801 
802         /* cleanup user object references stack */
803         psle = PopEntryList(&ptiCurrent->ReferencesList);
804         while (psle)
805         {
806             PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
807             TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
808             UserDereferenceObject(ref->obj);
809 
810             psle = PopEntryList(&ptiCurrent->ReferencesList);
811         }
812     }
813 
814     if (ptiCurrent->cEnterCount)
815     {
816        KeSetKernelStackSwapEnable(TRUE);
817        ptiCurrent->cEnterCount = 0;
818     }
819 
820     /* Find the THREADINFO in the PROCESSINFO's list */
821     ppti = &ppiCurrent->ptiList;
822     while (*ppti != NULL && *ppti != ptiCurrent)
823     {
824         ppti = &((*ppti)->ptiSibling);
825     }
826 
827     /* we must have found it */
828     ASSERT(*ppti == ptiCurrent);
829 
830     /* Remove it from the list */
831     *ppti = ptiCurrent->ptiSibling;
832 
833     if (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout)))
834         ptiCurrent->pClientInfo->hKL = NULL;
835 
836     if (gptiForeground == ptiCurrent)
837     {
838 //       IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
839 //       IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
840 
841        gptiForeground = NULL;
842     }
843 
844     /* Restore display mode when we are the last thread, and we changed the display mode */
845     if (ppiCurrent->cThreads == 0)
846         UserDisplayNotifyShutdown(ppiCurrent);
847 
848 
849     // Fixes CORE-6384 & CORE-7030.
850 /*    if (ptiLastInput == ptiCurrent)
851     {
852        if (!ppiCurrent->ptiList)
853           ptiLastInput = gptiForeground;
854        else
855           ptiLastInput = ppiCurrent->ptiList;
856        ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
857     }
858 */
859     TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
860 
861     IntSetThreadDesktop(NULL, TRUE);
862 
863     if (ptiCurrent->hEventQueueClient != NULL)
864     {
865        ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
866        ObDereferenceObject(ptiCurrent->pEventQueueServer);
867     }
868     ptiCurrent->hEventQueueClient = NULL;
869 
870     /* The thread is dying */
871     PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
872 
873     /* Dereference the THREADINFO */
874     IntDereferenceThreadInfo(ptiCurrent);
875 
876     return STATUS_SUCCESS;
877 }
878 
879 NTSTATUS
880 APIENTRY
881 Win32kThreadCallback(PETHREAD Thread,
882                      PSW32THREADCALLOUTTYPE Type)
883 {
884     NTSTATUS Status;
885 
886     ASSERT(NtCurrentTeb());
887 
888     UserEnterExclusive();
889 
890     if (Type == PsW32ThreadCalloutInitialize)
891     {
892         ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
893         Status = InitThreadCallback(Thread);
894     }
895     else // if (Type == PsW32ThreadCalloutExit)
896     {
897         ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
898         Status = ExitThreadCallback(Thread);
899     }
900 
901     UserLeave();
902 
903     return Status;
904 }
905 
906 _Function_class_(DRIVER_UNLOAD)
907 VOID NTAPI
908 DriverUnload(IN PDRIVER_OBJECT DriverObject)
909 {
910     // TODO: Do more cleanup!
911 
912     ResetCsrApiPort();
913     ResetCsrProcess();
914 }
915 
916 // Return on failure
917 #define NT_ROF(x) \
918 { \
919     Status = (x); \
920     if (!NT_SUCCESS(Status)) \
921     { \
922         DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
923         return Status; \
924     } \
925 }
926 
927 // Lock & return on failure
928 #define USERLOCK_AND_ROF(x)         \
929 {                                   \
930     UserEnterExclusive();           \
931     Status = (x);                   \
932     UserLeave();                    \
933     if (!NT_SUCCESS(Status))        \
934     { \
935         DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
936         return Status; \
937     } \
938 }
939 
940 
941 
942 /*
943  * This definition doesn't work
944  */
945 CODE_SEG("INIT")
946 NTSTATUS
947 APIENTRY
948 DriverEntry(
949     IN PDRIVER_OBJECT  DriverObject,
950     IN PUNICODE_STRING RegistryPath)
951 {
952     NTSTATUS Status;
953     BOOLEAN Result;
954     WIN32_CALLOUTS_FPNS CalloutData = {0};
955     PVOID GlobalUserHeapBase = NULL;
956 
957     /*
958      * Register user mode call interface
959      * (system service table index = 1)
960      */
961     Result = KeAddSystemServiceTable(Win32kSSDT,
962                                      NULL,
963                                      Win32kNumberOfSysCalls,
964                                      Win32kSSPT,
965                                      1);
966     if (Result == FALSE)
967     {
968         DPRINT1("Adding system services failed!\n");
969         return STATUS_UNSUCCESSFUL;
970     }
971 
972     hModuleWin = MmPageEntireDriver(DriverEntry);
973     DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
974 
975     DriverObject->DriverUnload = DriverUnload;
976 
977     /* Register Object Manager Callbacks */
978     CalloutData.ProcessCallout = Win32kProcessCallback;
979     CalloutData.ThreadCallout = Win32kThreadCallback;
980     // CalloutData.GlobalAtomTableCallout = NULL;
981     // CalloutData.PowerEventCallout = NULL;
982     // CalloutData.PowerStateCallout = NULL;
983     // CalloutData.JobCallout = NULL;
984     CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
985     CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
986     CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
987     CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
988     CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
989     CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose;
990     // CalloutData.WindowStationCloseProcedure = NULL;
991     CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
992     CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
993     // CalloutData.WindowStationOpenProcedure = NULL;
994 
995     /* Register our per-process and per-thread structures. */
996     PsEstablishWin32Callouts(&CalloutData);
997 
998     /* Register service hook callbacks */
999 #if DBG && defined(KDBG)
1000     KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
1001     KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
1002 #endif
1003 
1004     /* Create the global USER heap */
1005     GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
1006                                     &GlobalUserHeapBase,
1007                                     1 * 1024 * 1024); /* FIXME: 1 MB for now... */
1008     if (GlobalUserHeap == NULL)
1009     {
1010         DPRINT1("Failed to initialize the global heap!\n");
1011         return STATUS_UNSUCCESSFUL;
1012     }
1013 
1014     /* Init the global user lock */
1015     ExInitializeResourceLite(&UserLock);
1016 
1017     /* Lock while we use the heap (UserHeapAlloc asserts on this) */
1018     UserEnterExclusive();
1019 
1020     /* Allocate global server info structure */
1021     gpsi = UserHeapAlloc(sizeof(*gpsi));
1022     UserLeave();
1023     if (!gpsi)
1024     {
1025         DPRINT1("Failed allocate server info structure!\n");
1026         return STATUS_UNSUCCESSFUL;
1027     }
1028 
1029     RtlZeroMemory(gpsi, sizeof(*gpsi));
1030     DPRINT("Global Server Data -> %p\n", gpsi);
1031 
1032     NT_ROF(InitGdiHandleTable());
1033     NT_ROF(InitPaletteImpl());
1034 
1035     /* Create stock objects, ie. precreated objects commonly
1036        used by win32 applications */
1037     CreateStockObjects();
1038     CreateSysColorObjects();
1039 
1040     NT_ROF(InitBrushImpl());
1041     NT_ROF(InitPDEVImpl());
1042     NT_ROF(InitLDEVImpl());
1043     NT_ROF(InitDeviceImpl());
1044     NT_ROF(InitDcImpl());
1045     USERLOCK_AND_ROF(InitUserImpl());
1046     NT_ROF(InitWindowStationImpl());
1047     NT_ROF(InitDesktopImpl());
1048     NT_ROF(InitInputImpl());
1049     NT_ROF(InitKeyboardImpl());
1050     NT_ROF(MsqInitializeImpl());
1051     NT_ROF(InitTimerImpl());
1052     NT_ROF(InitDCEImpl());
1053 
1054     gusLanguageID = UserGetLanguageID();
1055 
1056     /* Initialize FreeType library */
1057     if (!InitFontSupport())
1058     {
1059         DPRINT1("Unable to initialize font support\n");
1060         return Status;
1061     }
1062 
1063     return STATUS_SUCCESS;
1064 }
1065 
1066 /* EOF */
1067