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