xref: /reactos/win32ss/user/ntuser/main.c (revision 9eca7c52)
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 PPROCESSINFO ppiScrnSaver;
30 PPROCESSINFO gppiList = NULL;
31 
32 extern ULONG_PTR Win32kSSDT[];
33 extern UCHAR Win32kSSPT[];
34 extern ULONG Win32kNumberOfSysCalls;
35 
36 #if DBG
37 void
38 NTAPI
DbgPreServiceHook(ULONG ulSyscallId,PULONG_PTR pulArguments)39 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
40 {
41     GdiDbgPreServiceHook(ulSyscallId, pulArguments);
42     UserDbgPreServiceHook(ulSyscallId, pulArguments);
43 }
44 
45 ULONG_PTR
46 NTAPI
DbgPostServiceHook(ULONG ulSyscallId,ULONG_PTR ulResult)47 DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
48 {
49     ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
50     ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
51     return ulResult;
52 }
53 #endif
54 
55 
56 NTSTATUS
AllocW32Process(IN PEPROCESS Process,OUT PPROCESSINFO * W32Process)57 AllocW32Process(IN  PEPROCESS Process,
58                 OUT PPROCESSINFO* W32Process)
59 {
60     PPROCESSINFO ppiCurrent;
61 
62     TRACE_CH(UserProcess, "In AllocW32Process(0x%p)\n", Process);
63 
64     /* Check that we were not called with an already existing Win32 process info */
65     ppiCurrent = PsGetProcessWin32Process(Process);
66     if (ppiCurrent) return STATUS_SUCCESS;
67 
68     /* Allocate a new Win32 process info */
69     ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
70                                        sizeof(*ppiCurrent),
71                                        USERTAG_PROCESSINFO);
72     if (ppiCurrent == NULL)
73     {
74         ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
75                HandleToUlong(Process->UniqueProcessId));
76         return STATUS_NO_MEMORY;
77     }
78 
79     TRACE_CH(UserProcess, "Allocated ppi 0x%p for PID:0x%lx\n",
80              ppiCurrent, HandleToUlong(Process->UniqueProcessId));
81 
82     RtlZeroMemory(ppiCurrent, sizeof(*ppiCurrent));
83 
84     PsSetProcessWin32Process(Process, ppiCurrent, NULL);
85     IntReferenceProcessInfo(ppiCurrent);
86 
87     *W32Process = ppiCurrent;
88     return STATUS_SUCCESS;
89 }
90 
91 /*
92  * Called from IntDereferenceProcessInfo
93  */
94 VOID
UserDeleteW32Process(_Pre_notnull_ __drv_freesMem (Mem)PPROCESSINFO ppiCurrent)95 UserDeleteW32Process(
96     _Pre_notnull_ __drv_freesMem(Mem) PPROCESSINFO ppiCurrent)
97 {
98     if (ppiCurrent->InputIdleEvent)
99     {
100         /* Free the allocated memory */
101         ExFreePoolWithTag(ppiCurrent->InputIdleEvent, USERTAG_EVENT);
102     }
103 
104     /* Close the startup desktop */
105     if (ppiCurrent->rpdeskStartup)
106         ObDereferenceObject(ppiCurrent->rpdeskStartup);
107 
108 #if DBG
109     if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
110     {
111         TRACE_PPI(ppiCurrent, UserObj, "Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
112         DbgUserDumpHandleTable();
113     }
114 #endif
115 
116     /* Free the PROCESSINFO */
117     ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
118 }
119 
120 NTSTATUS
UserProcessCreate(PEPROCESS Process)121 UserProcessCreate(PEPROCESS Process)
122 {
123     PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
124     ASSERT(ppiCurrent);
125 
126     InitializeListHead(&ppiCurrent->DriverObjListHead);
127     ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
128 
129     {
130         PKEVENT Event;
131 
132         /* Allocate memory for the event structure */
133         Event = ExAllocatePoolWithTag(NonPagedPool,
134                                       sizeof(*Event),
135                                       USERTAG_EVENT);
136         if (Event)
137         {
138             /* Initialize the kernel event */
139             KeInitializeEvent(Event,
140                               SynchronizationEvent,
141                               FALSE);
142         }
143         else
144         {
145             /* Out of memory */
146             DPRINT("CreateEvent() failed\n");
147             KeBugCheck(0);
148         }
149 
150         /* Set the event */
151         ppiCurrent->InputIdleEvent = Event;
152         KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
153     }
154 
155     ppiCurrent->peProcess = Process;
156     ppiCurrent->W32Pid = HandleToUlong(PsGetProcessId(Process));
157 
158     /* Setup process flags */
159     ppiCurrent->W32PF_flags |= W32PF_PROCESSCONNECTED;
160     if (Process->Peb->ProcessParameters &&
161         (Process->Peb->ProcessParameters->WindowFlags & STARTF_SCREENSAVER))
162     {
163         ppiScrnSaver = ppiCurrent;
164         ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
165     }
166 
167     // FIXME: check if this process is allowed.
168     ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application will get it toggled off.
169 
170     return STATUS_SUCCESS;
171 }
172 
173 NTSTATUS
UserProcessDestroy(PEPROCESS Process)174 UserProcessDestroy(PEPROCESS Process)
175 {
176     PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
177     ASSERT(ppiCurrent);
178 
179     if (ppiScrnSaver == ppiCurrent)
180         ppiScrnSaver = NULL;
181 
182     IntFreeImeHotKeys();
183 
184     if (gpwlCache)
185     {
186         ExFreePoolWithTag(gpwlCache, USERTAG_WINDOWLIST);
187         gpwlCache = NULL;
188     }
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
InitProcessCallback(PEPROCESS Process)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
ExitProcessCallback(PEPROCESS Process)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     IntDereferenceProcessInfo(ppiCurrent);
336 
337     return STATUS_SUCCESS;
338 }
339 
340 NTSTATUS
341 APIENTRY
Win32kProcessCallback(PEPROCESS Process,BOOLEAN Initialize)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
AllocW32Thread(IN PETHREAD Thread,OUT PTHREADINFO * W32Thread)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     ObReferenceObject(Thread);
401     IntReferenceThreadInfo(ptiCurrent);
402 
403     *W32Thread = ptiCurrent;
404     return STATUS_SUCCESS;
405 }
406 
407 /*
408  * Called from IntDereferenceThreadInfo
409  */
410 VOID
UserDeleteW32Thread(PTHREADINFO pti)411 UserDeleteW32Thread(PTHREADINFO pti)
412 {
413    PPROCESSINFO ppi = pti->ppi;
414 
415    TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
416 
417    /* Free the message queue */
418    if (pti->MessageQueue)
419    {
420       MsqDestroyMessageQueue(pti);
421    }
422 
423    MsqCleanupThreadMsgs(pti);
424 
425    ObDereferenceObject(pti->pEThread);
426 
427    ExFreePoolWithTag(pti, USERTAG_THREADINFO);
428 
429    IntDereferenceProcessInfo(ppi);
430 
431    {
432       // Find another queue for mouse cursor.
433       MSG msg;
434       msg.message = WM_MOUSEMOVE;
435       msg.wParam = UserGetMouseButtonsState();
436       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
437       msg.pt = gpsi->ptCursor;
438       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
439    }
440 }
441 
442 NTSTATUS
UserThreadCreate(PETHREAD Thread)443 UserThreadCreate(PETHREAD Thread)
444 {
445     return STATUS_SUCCESS;
446 }
447 
448 NTSTATUS
UserThreadDestroy(PETHREAD Thread)449 UserThreadDestroy(PETHREAD Thread)
450 {
451     return STATUS_SUCCESS;
452 }
453 
454 NTSTATUS NTAPI
InitThreadCallback(PETHREAD Thread)455 InitThreadCallback(PETHREAD Thread)
456 {
457     PEPROCESS Process;
458     PCLIENTINFO pci;
459     PTHREADINFO ptiCurrent;
460     int i;
461     NTSTATUS Status = STATUS_SUCCESS;
462     PTEB pTeb;
463     PRTL_USER_PROCESS_PARAMETERS ProcessParams;
464     PKL pDefKL;
465 
466     Process = Thread->ThreadsProcess;
467 
468     pTeb = NtCurrentTeb();
469     ASSERT(pTeb);
470 
471     ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
472 
473     /* Allocate a new Win32 thread info */
474     Status = AllocW32Thread(Thread, &ptiCurrent);
475     if (!NT_SUCCESS(Status))
476     {
477         ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
478                HandleToUlong(Thread->Cid.UniqueThread));
479         return Status;
480     }
481 
482     /* Initialize the THREADINFO */
483     ptiCurrent->pEThread = Thread;
484     ptiCurrent->ppi = PsGetProcessWin32Process(Process);
485     IntReferenceProcessInfo(ptiCurrent->ppi);
486     pTeb->Win32ThreadInfo = ptiCurrent;
487     ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
488     ptiCurrent->pcti = &ptiCurrent->cti;
489 
490     /* Mark the process as having threads */
491     ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
492 
493     InitializeListHead(&ptiCurrent->WindowListHead);
494     InitializeListHead(&ptiCurrent->W32CallbackListHead);
495     InitializeListHead(&ptiCurrent->PostedMessagesListHead);
496     InitializeListHead(&ptiCurrent->SentMessagesListHead);
497     InitializeListHead(&ptiCurrent->PtiLink);
498     for (i = 0; i < NB_HOOKS; i++)
499     {
500         InitializeListHead(&ptiCurrent->aphkStart[i]);
501     }
502     ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
503     ptiCurrent->ppi->ptiList = ptiCurrent;
504     ptiCurrent->ppi->cThreads++;
505 
506     ptiCurrent->hEventQueueClient = NULL;
507     Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
508                             NULL, SynchronizationEvent, FALSE);
509     if (!NT_SUCCESS(Status))
510     {
511         ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
512         goto error;
513     }
514     Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
515                                        *ExEventObjectType, UserMode,
516                                        (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
517     if (!NT_SUCCESS(Status))
518     {
519         ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
520         ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
521         ptiCurrent->hEventQueueClient = NULL;
522         goto error;
523     }
524 
525     ptiCurrent->pcti->timeLastRead = EngGetTickCount32();
526 
527     ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
528     if (ptiCurrent->MessageQueue == NULL)
529     {
530         ERR_CH(UserThread, "Failed to allocate message loop\n");
531         Status = STATUS_NO_MEMORY;
532         goto error;
533     }
534 
535     pDefKL = W32kGetDefaultKeyLayout();
536     UserAssignmentLock((PVOID*)&(ptiCurrent->KeyboardLayout), pDefKL);
537 
538     ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
539 
540     // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
541 
542     /* CSRSS threads have some special features */
543     if (Process == gpepCSRSS || !gpepCSRSS)
544         ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
545 
546     /* Initialize the CLIENTINFO */
547     pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
548     RtlZeroMemory(pci, sizeof(*pci));
549     pci->ppi = ptiCurrent->ppi;
550     pci->fsHooks = ptiCurrent->fsHooks;
551     pci->dwTIFlags = ptiCurrent->TIF_flags;
552     if (pDefKL)
553     {
554         pci->hKL = pDefKL->hkl;
555         pci->CodePage = pDefKL->CodePage;
556     }
557 
558     /* Populate dwExpWinVer */
559     if (Process->Peb)
560         ptiCurrent->dwExpWinVer = RtlGetExpWinVer(Process->SectionBaseAddress);
561     else
562         ptiCurrent->dwExpWinVer = WINVER_WINNT4;
563     pci->dwExpWinVer = ptiCurrent->dwExpWinVer;
564 
565     /* Need to pass the user Startup Information to the current process. */
566     if ( ProcessParams )
567     {
568        if ( ptiCurrent->ppi->usi.cb == 0 )      // Not initialized yet.
569        {
570           if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
571           {
572              ptiCurrent->ppi->usi.cb          = sizeof(USERSTARTUPINFO);
573              ptiCurrent->ppi->usi.dwX         = ProcessParams->StartingX;
574              ptiCurrent->ppi->usi.dwY         = ProcessParams->StartingY;
575              ptiCurrent->ppi->usi.dwXSize     = ProcessParams->CountX;
576              ptiCurrent->ppi->usi.dwYSize     = ProcessParams->CountY;
577              ptiCurrent->ppi->usi.dwFlags     = ProcessParams->WindowFlags;
578              ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
579           }
580        }
581     }
582 
583     /*
584      * Assign a default window station and desktop to the process.
585      * Do not try to open a desktop or window station before the very first
586      * (interactive) window station has been created by Winlogon.
587      */
588     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
589         ptiCurrent->ppi->hdeskStartup == NULL &&
590         InputWindowStation != NULL)
591     {
592         HWINSTA hWinSta = NULL;
593         HDESK hDesk = NULL;
594         UNICODE_STRING DesktopPath;
595         PDESKTOP pdesk;
596 
597         /*
598          * Inherit the thread desktop and process window station (if not yet inherited)
599          * from the process startup info structure. See documentation of CreateProcess().
600          */
601         Status = STATUS_UNSUCCESSFUL;
602         if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
603         {
604             Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
605         }
606         if (!NT_SUCCESS(Status))
607         {
608             RtlInitUnicodeString(&DesktopPath, NULL);
609         }
610 
611         Status = IntResolveDesktop(Process,
612                                    &DesktopPath,
613                                    !!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP),
614                                    &hWinSta,
615                                    &hDesk);
616 
617         if (DesktopPath.Buffer)
618             ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
619 
620         if (!NT_SUCCESS(Status))
621         {
622             ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n");
623             goto error;
624         }
625 
626         if (!UserSetProcessWindowStation(hWinSta))
627         {
628             Status = STATUS_UNSUCCESSFUL;
629             ERR_CH(UserThread, "Failed to set initial process winsta\n");
630             goto error;
631         }
632 
633         /* Validate the new desktop */
634         Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
635         if (!NT_SUCCESS(Status))
636         {
637             ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
638             goto error;
639         }
640 
641         /* Store the parsed desktop as the initial desktop */
642         ASSERT(ptiCurrent->ppi->hdeskStartup == NULL);
643         ASSERT(Process->UniqueProcessId != gpidLogon);
644         ptiCurrent->ppi->hdeskStartup = hDesk;
645         ptiCurrent->ppi->rpdeskStartup = pdesk;
646     }
647 
648     if (ptiCurrent->ppi->hdeskStartup != NULL)
649     {
650         if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
651         {
652             ERR_CH(UserThread, "Failed to set thread desktop\n");
653             Status = STATUS_UNSUCCESSFUL;
654             goto error;
655         }
656     }
657 
658     /* Mark the thread as fully initialized */
659     ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
660 
661     if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
662          (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
663     {
664         ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
665     }
666     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
667 
668     /* Create the default input context */
669     if (IS_IMM_MODE())
670     {
671         (VOID)UserCreateInputContext(0);
672     }
673 
674     /* Last things to do only if we are not a SYSTEM or CSRSS thread */
675     if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
676     {
677         /* Callback to User32 Client Thread Setup */
678         TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
679         Status = co_IntClientThreadSetup();
680         if (!NT_SUCCESS(Status))
681         {
682             ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
683             goto error;
684         }
685         TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
686     }
687     else
688     {
689         TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
690     }
691 
692     TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
693     return STATUS_SUCCESS;
694 
695 error:
696     ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
697            ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
698     ExitThreadCallback(Thread);
699     return Status;
700 }
701 
702 VOID
703 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
704 
705 // Win: xxxDestroyThreadInfo
706 NTSTATUS
707 NTAPI
ExitThreadCallback(PETHREAD Thread)708 ExitThreadCallback(PETHREAD Thread)
709 {
710     PTHREADINFO *ppti;
711     PSINGLE_LIST_ENTRY psle;
712     PPROCESSINFO ppiCurrent;
713     PEPROCESS Process;
714     PTHREADINFO ptiCurrent;
715     PWINDOWLIST pwl, pwlNext;
716 
717     Process = Thread->ThreadsProcess;
718 
719     /* Get the Win32 Thread */
720     ptiCurrent = PsGetThreadWin32Thread(Thread);
721     ASSERT(ptiCurrent);
722 
723     TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
724 
725     ptiCurrent->TIF_flags |= TIF_INCLEANUP;
726     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
727 
728     ppiCurrent = ptiCurrent->ppi;
729     ASSERT(ppiCurrent);
730 
731     IsRemoveAttachThread(ptiCurrent);
732 
733     if (gpwlList)
734     {
735         for (pwl = gpwlList; pwl; pwl = pwlNext)
736         {
737             pwlNext = pwl->pNextList;
738             if (pwl->pti == ptiCurrent)
739                 IntFreeHwndList(pwl);
740         }
741     }
742 
743     ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
744     ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
745 
746     UserCloseClipboard();
747 
748     /* Decrement thread count and check if its 0 */
749     ppiCurrent->cThreads--;
750 
751     if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
752     {
753         /* Do now some process cleanup that requires a valid win32 thread */
754         if (ptiCurrent->ppi->cThreads == 0)
755         {
756             /* Check if we have registered the user api hook */
757             if (ptiCurrent->ppi == ppiUahServer)
758             {
759                 /* Unregister the api hook */
760                 UserUnregisterUserApiHook();
761             }
762 
763             /* Notify logon application to restart shell if needed */
764             if (ptiCurrent->pDeskInfo)
765             {
766                 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
767                 {
768                     DWORD ExitCode = PsGetProcessExitStatus(Process);
769 
770                    TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
771 
772                     UserPostMessage(hwndSAS,
773                                     WM_LOGONNOTIFY,
774                                     LN_SHELL_EXITED,
775                                     ExitCode);
776 
777                     ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
778                 }
779             }
780         }
781 
782         DceFreeThreadDCE(ptiCurrent);
783         DestroyTimersForThread(ptiCurrent);
784         KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
785         UnregisterThreadHotKeys(ptiCurrent);
786 
787         if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
788         {
789             DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
790             ASSERT(FALSE);
791             return STATUS_UNSUCCESSFUL;
792         }
793         UserAssignmentUnlock((PVOID*)&ptiCurrent->spDefaultImc);
794 
795         if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
796             ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
797         {
798             TRACE_CH(UserThread, "DestroyProcessClasses\n");
799             /* no process windows should exist at this point, or the function will assert! */
800             DestroyProcessClasses(ppiCurrent);
801             ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
802         }
803 
804         IntBlockInput(ptiCurrent, FALSE);
805         IntCleanupThreadCallbacks(ptiCurrent);
806 
807         /* cleanup user object references stack */
808         psle = PopEntryList(&ptiCurrent->ReferencesList);
809         while (psle)
810         {
811             PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
812             TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
813             UserDereferenceObject(ref->obj);
814 
815             psle = PopEntryList(&ptiCurrent->ReferencesList);
816 #if DBG
817             ptiCurrent->cRefObjectCo--;
818 #endif
819         }
820     }
821 
822     if (ptiCurrent->cEnterCount)
823     {
824        KeSetKernelStackSwapEnable(TRUE);
825        ptiCurrent->cEnterCount = 0;
826     }
827 
828     /* Find the THREADINFO in the PROCESSINFO's list */
829     ppti = &ppiCurrent->ptiList;
830     while (*ppti != NULL && *ppti != ptiCurrent)
831     {
832         ppti = &((*ppti)->ptiSibling);
833     }
834 
835     /* we must have found it */
836     ASSERT(*ppti == ptiCurrent);
837 
838     /* Remove it from the list */
839     *ppti = ptiCurrent->ptiSibling;
840 
841     if (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout)))
842         ptiCurrent->pClientInfo->hKL = NULL;
843 
844     if (gptiForeground == ptiCurrent)
845     {
846 //       IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
847 //       IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
848 
849        gptiForeground = NULL;
850     }
851 
852     /* Restore display mode when we are the last thread, and we changed the display mode */
853     if (ppiCurrent->cThreads == 0)
854         UserDisplayNotifyShutdown(ppiCurrent);
855 
856 
857     // Fixes CORE-6384 & CORE-7030.
858 /*    if (ptiLastInput == ptiCurrent)
859     {
860        if (!ppiCurrent->ptiList)
861           ptiLastInput = gptiForeground;
862        else
863           ptiLastInput = ppiCurrent->ptiList;
864        ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
865     }
866 */
867     TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
868 
869     IntSetThreadDesktop(NULL, TRUE);
870 
871     if (ptiCurrent->hEventQueueClient != NULL)
872     {
873        ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
874        ObDereferenceObject(ptiCurrent->pEventQueueServer);
875     }
876     ptiCurrent->hEventQueueClient = NULL;
877 
878     ASSERT(ptiCurrent->cRefObjectCo == 0);
879 
880     /* The thread is dying */
881     PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
882 
883     /* Dereference the THREADINFO */
884     IntDereferenceThreadInfo(ptiCurrent);
885 
886     return STATUS_SUCCESS;
887 }
888 
889 NTSTATUS
890 APIENTRY
Win32kThreadCallback(PETHREAD Thread,PSW32THREADCALLOUTTYPE Type)891 Win32kThreadCallback(PETHREAD Thread,
892                      PSW32THREADCALLOUTTYPE Type)
893 {
894     NTSTATUS Status;
895 
896     ASSERT(NtCurrentTeb());
897 
898     UserEnterExclusive();
899 
900     if (Type == PsW32ThreadCalloutInitialize)
901     {
902         ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
903         Status = InitThreadCallback(Thread);
904     }
905     else // if (Type == PsW32ThreadCalloutExit)
906     {
907         ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
908         Status = ExitThreadCallback(Thread);
909     }
910 
911     UserLeave();
912 
913     return Status;
914 }
915 
_Function_class_(DRIVER_UNLOAD)916 _Function_class_(DRIVER_UNLOAD)
917 VOID NTAPI
918 DriverUnload(IN PDRIVER_OBJECT DriverObject)
919 {
920     // TODO: Do more cleanup!
921 
922     FreeFontSupport();
923     ResetCsrApiPort();
924     ResetCsrProcess();
925     IntWin32PowerManagementCleanup();
926 }
927 
928 // Return on failure
929 #define NT_ROF(x) \
930 { \
931     Status = (x); \
932     if (!NT_SUCCESS(Status)) \
933     { \
934         DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
935         return Status; \
936     } \
937 }
938 
939 // Lock & return on failure
940 #define USERLOCK_AND_ROF(x)         \
941 {                                   \
942     UserEnterExclusive();           \
943     Status = (x);                   \
944     UserLeave();                    \
945     if (!NT_SUCCESS(Status))        \
946     { \
947         DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
948         return Status; \
949     } \
950 }
951 
952 
953 
954 /*
955  * This definition doesn't work
956  */
957 CODE_SEG("INIT")
958 NTSTATUS
959 APIENTRY
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)960 DriverEntry(
961     IN PDRIVER_OBJECT  DriverObject,
962     IN PUNICODE_STRING RegistryPath)
963 {
964     NTSTATUS Status;
965     BOOLEAN Result;
966     WIN32_CALLOUTS_FPNS CalloutData = {0};
967     PVOID GlobalUserHeapBase = NULL;
968 
969     /*
970      * Register user mode call interface
971      * (system service table index = 1)
972      */
973     Result = KeAddSystemServiceTable(Win32kSSDT,
974                                      NULL,
975                                      Win32kNumberOfSysCalls,
976                                      Win32kSSPT,
977                                      1);
978     if (Result == FALSE)
979     {
980         DPRINT1("Adding system services failed!\n");
981         return STATUS_UNSUCCESSFUL;
982     }
983 
984     hModuleWin = MmPageEntireDriver(DriverEntry);
985     DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
986 
987     DriverObject->DriverUnload = DriverUnload;
988 
989     /* Register Object Manager Callbacks */
990     CalloutData.ProcessCallout = Win32kProcessCallback;
991     CalloutData.ThreadCallout = Win32kThreadCallback;
992     // CalloutData.GlobalAtomTableCallout = NULL;
993     CalloutData.PowerEventCallout = IntHandlePowerEvent;
994     CalloutData.PowerStateCallout = IntHandlePowerState;
995     // CalloutData.JobCallout = NULL;
996     CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
997     CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
998     CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
999     CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
1000     CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
1001     CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose;
1002     // CalloutData.WindowStationCloseProcedure = NULL;
1003     CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
1004     CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
1005     // CalloutData.WindowStationOpenProcedure = NULL;
1006 
1007     /* Register our per-process and per-thread structures. */
1008     PsEstablishWin32Callouts(&CalloutData);
1009 
1010     /* Register service hook callbacks */
1011 #if DBG && defined(KDBG)
1012     KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
1013     KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
1014 #endif
1015 
1016     /* Create the global USER heap */
1017     GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
1018                                     &GlobalUserHeapBase,
1019                                     1 * 1024 * 1024); /* FIXME: 1 MB for now... */
1020     if (GlobalUserHeap == NULL)
1021     {
1022         DPRINT1("Failed to initialize the global heap!\n");
1023         return STATUS_UNSUCCESSFUL;
1024     }
1025 
1026     /* Init the global user lock */
1027     ExInitializeResourceLite(&UserLock);
1028 
1029     /* Lock while we use the heap (UserHeapAlloc asserts on this) */
1030     UserEnterExclusive();
1031 
1032     /* Allocate global server info structure */
1033     gpsi = UserHeapAlloc(sizeof(*gpsi));
1034     UserLeave();
1035     if (!gpsi)
1036     {
1037         DPRINT1("Failed allocate server info structure!\n");
1038         return STATUS_UNSUCCESSFUL;
1039     }
1040 
1041     RtlZeroMemory(gpsi, sizeof(*gpsi));
1042     DPRINT("Global Server Data -> %p\n", gpsi);
1043 
1044     NT_ROF(InitGdiHandleTable());
1045     NT_ROF(InitPaletteImpl());
1046 
1047     /* Create stock objects, ie. precreated objects commonly
1048        used by win32 applications */
1049     CreateStockObjects();
1050     CreateSysColorObjects();
1051 
1052     NT_ROF(InitBrushImpl());
1053     NT_ROF(InitPDEVImpl());
1054     NT_ROF(InitLDEVImpl());
1055     NT_ROF(InitDeviceImpl());
1056     NT_ROF(InitDcImpl());
1057     USERLOCK_AND_ROF(InitUserImpl());
1058     NT_ROF(InitWindowStationImpl());
1059     NT_ROF(InitDesktopImpl());
1060     NT_ROF(InitInputImpl());
1061     NT_ROF(InitKeyboardImpl());
1062     NT_ROF(MsqInitializeImpl());
1063     NT_ROF(InitTimerImpl());
1064     NT_ROF(InitDCEImpl());
1065 
1066     return STATUS_SUCCESS;
1067 }
1068 
1069 /* EOF */
1070