f2742736125c1937406b7628aee70f1b1f5aee55
[reactos.git] / reactos / win32ss / user / ntuser / main.c
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 ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
138 {
139 PKEVENT Event;
140
141 /* Allocate memory for the event structure */
142 Event = ExAllocatePoolWithTag(NonPagedPool,
143 sizeof(*Event),
144 USERTAG_EVENT);
145 if (Event)
146 {
147 /* Initialize the kernel event */
148 KeInitializeEvent(Event,
149 SynchronizationEvent,
150 FALSE);
151 }
152 else
153 {
154 /* Out of memory */
155 DPRINT("CreateEvent() failed\n");
156 KeBugCheck(0);
157 }
158
159 /* Set the event */
160 ppiCurrent->InputIdleEvent = Event;
161 KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
162 }
163
164 ppiCurrent->peProcess = Process;
165 ppiCurrent->W32Pid = HandleToUlong(PsGetProcessId(Process));
166
167 /* Setup process flags */
168 ppiCurrent->W32PF_flags |= W32PF_PROCESSCONNECTED;
169 if ( Process->Peb->ProcessParameters &&
170 Process->Peb->ProcessParameters->WindowFlags & STARTF_SCRNSAVER )
171 {
172 ppiScrnSaver = ppiCurrent;
173 ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
174 }
175
176 // FIXME: check if this process is allowed.
177 ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application will get it toggled off.
178
179 return STATUS_SUCCESS;
180 }
181
182 NTSTATUS
183 UserProcessDestroy(PEPROCESS Process)
184 {
185 PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
186 ASSERT(ppiCurrent);
187
188 if (ppiScrnSaver == ppiCurrent)
189 ppiScrnSaver = NULL;
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 FreeW32Process(/*Process*/ ppiCurrent); // 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 IntReferenceThreadInfo(ptiCurrent);
402
403 *W32Thread = ptiCurrent;
404 return STATUS_SUCCESS;
405 }
406
407 #define FreeW32Thread(/*Thread*/ W32Thread) \
408 do { \
409 /*PTHREADINFO W32Thread = PsGetThreadWin32Thread(Thread);*/ \
410 /*ASSERT(W32Thread);*/ \
411 IntDereferenceThreadInfo(W32Thread); \
412 } while(0)
413
414 /*
415 * Called from IntDereferenceThreadInfo
416 */
417 VOID
418 UserDeleteW32Thread(PTHREADINFO pti)
419 {
420 PPROCESSINFO ppi = pti->ppi;
421
422 TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
423
424 /* Free the message queue */
425 if (pti->MessageQueue)
426 {
427 MsqDestroyMessageQueue(pti);
428 }
429
430 MsqCleanupThreadMsgs(pti);
431
432 ExFreePoolWithTag(pti, USERTAG_THREADINFO);
433
434 IntDereferenceProcessInfo(ppi);
435 }
436
437 NTSTATUS
438 UserThreadCreate(PETHREAD Thread)
439 {
440 return STATUS_SUCCESS;
441 }
442
443 NTSTATUS
444 UserThreadDestroy(PETHREAD Thread)
445 {
446 return STATUS_SUCCESS;
447 }
448
449 NTSTATUS NTAPI
450 InitThreadCallback(PETHREAD Thread)
451 {
452 PEPROCESS Process;
453 PCLIENTINFO pci;
454 PTHREADINFO ptiCurrent;
455 int i;
456 NTSTATUS Status = STATUS_SUCCESS;
457 PTEB pTeb;
458 LARGE_INTEGER LargeTickCount;
459 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
460
461 Process = Thread->ThreadsProcess;
462
463 pTeb = NtCurrentTeb();
464 ASSERT(pTeb);
465
466 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
467
468 /* Allocate a new Win32 thread info */
469 Status = AllocW32Thread(Thread, &ptiCurrent);
470 if (!NT_SUCCESS(Status))
471 {
472 ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
473 HandleToUlong(Thread->Cid.UniqueThread));
474 return Status;
475 }
476
477 /* Initialize the THREADINFO */
478 ptiCurrent->pEThread = Thread;
479 ptiCurrent->ppi = PsGetProcessWin32Process(Process);
480 IntReferenceProcessInfo(ptiCurrent->ppi);
481 pTeb->Win32ThreadInfo = ptiCurrent;
482 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
483
484 /* Mark the process as having threads */
485 ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
486
487 InitializeListHead(&ptiCurrent->WindowListHead);
488 InitializeListHead(&ptiCurrent->W32CallbackListHead);
489 InitializeListHead(&ptiCurrent->PostedMessagesListHead);
490 InitializeListHead(&ptiCurrent->SentMessagesListHead);
491 InitializeListHead(&ptiCurrent->PtiLink);
492 for (i = 0; i < NB_HOOKS; i++)
493 {
494 InitializeListHead(&ptiCurrent->aphkStart[i]);
495 }
496 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
497 ptiCurrent->ppi->ptiList = ptiCurrent;
498 ptiCurrent->ppi->cThreads++;
499
500 ptiCurrent->hEventQueueClient = NULL;
501 Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
502 NULL, SynchronizationEvent, FALSE);
503 if (!NT_SUCCESS(Status))
504 {
505 ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
506 goto error;
507 }
508 Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
509 *ExEventObjectType, UserMode,
510 (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
511 if (!NT_SUCCESS(Status))
512 {
513 ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
514 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
515 ptiCurrent->hEventQueueClient = NULL;
516 goto error;
517 }
518
519 KeQueryTickCount(&LargeTickCount);
520 ptiCurrent->timeLast = LargeTickCount.u.LowPart;
521
522 ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
523 if (ptiCurrent->MessageQueue == NULL)
524 {
525 ERR_CH(UserThread, "Failed to allocate message loop\n");
526 Status = STATUS_NO_MEMORY;
527 goto error;
528 }
529
530 ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
531 if (ptiCurrent->KeyboardLayout)
532 UserReferenceObject(ptiCurrent->KeyboardLayout);
533
534 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
535
536 /* CSRSS threads have some special features */
537 if (Process == gpepCSRSS)
538 ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
539
540 // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
541
542 ptiCurrent->pcti = &ptiCurrent->cti;
543
544 /* Initialize the CLIENTINFO */
545 pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
546 RtlZeroMemory(pci, sizeof(*pci));
547 pci->ppi = ptiCurrent->ppi;
548 pci->fsHooks = ptiCurrent->fsHooks;
549 pci->dwTIFlags = ptiCurrent->TIF_flags;
550 if (ptiCurrent->KeyboardLayout)
551 {
552 pci->hKL = ptiCurrent->KeyboardLayout->hkl;
553 pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
554 }
555
556 /* Need to pass the user Startup Information to the current process. */
557 if ( ProcessParams )
558 {
559 if ( ptiCurrent->ppi->usi.cb == 0 ) // Not initialized yet.
560 {
561 if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
562 {
563 ptiCurrent->ppi->usi.cb = sizeof(USERSTARTUPINFO);
564 ptiCurrent->ppi->usi.dwX = ProcessParams->StartingX;
565 ptiCurrent->ppi->usi.dwY = ProcessParams->StartingY;
566 ptiCurrent->ppi->usi.dwXSize = ProcessParams->CountX;
567 ptiCurrent->ppi->usi.dwYSize = ProcessParams->CountY;
568 ptiCurrent->ppi->usi.dwFlags = ProcessParams->WindowFlags;
569 ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
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 winlogon initializes */
576 if (ptiCurrent->ppi->hdeskStartup == NULL && gpidLogon != 0)
577 {
578 HWINSTA hWinSta = NULL;
579 HDESK hDesk = NULL;
580 UNICODE_STRING DesktopPath;
581 PDESKTOP pdesk;
582
583 /*
584 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
585 * info structure. See documentation of CreateProcess()
586 */
587
588 Status = STATUS_UNSUCCESSFUL;
589 if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
590 {
591 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
592 }
593 if (!NT_SUCCESS(Status))
594 {
595 RtlInitUnicodeString(&DesktopPath, NULL);
596 }
597
598 Status = IntParseDesktopPath(Process,
599 &DesktopPath,
600 &hWinSta,
601 &hDesk);
602
603 if (DesktopPath.Buffer)
604 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
605
606 if (!NT_SUCCESS(Status))
607 {
608 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
609 goto error;
610 }
611
612 if (!UserSetProcessWindowStation(hWinSta))
613 {
614 Status = STATUS_UNSUCCESSFUL;
615 ERR_CH(UserThread, "Failed to set initial process winsta\n");
616 goto error;
617 }
618
619 /* Validate the new desktop. */
620 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
621 if (!NT_SUCCESS(Status))
622 {
623 ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
624 goto error;
625 }
626
627 /* Store the parsed desktop as the initial desktop */
628 ptiCurrent->ppi->hdeskStartup = hDesk;
629 ptiCurrent->ppi->rpdeskStartup = pdesk;
630 }
631
632 if (ptiCurrent->ppi->hdeskStartup != NULL)
633 {
634 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
635 {
636 ERR_CH(UserThread, "Failed to set thread desktop\n");
637 Status = STATUS_UNSUCCESSFUL;
638 goto error;
639 }
640 }
641
642 /* Mark the thread as fully initialized */
643 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
644
645 if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
646 (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
647 {
648 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
649 }
650 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
651
652 /* Last things to do only if we are not a SYSTEM or CSRSS thread */
653 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
654 {
655 /* Callback to User32 Client Thread Setup */
656 TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
657 Status = co_IntClientThreadSetup();
658 if (!NT_SUCCESS(Status))
659 {
660 ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
661 goto error;
662 }
663 TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
664 }
665 else
666 {
667 TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
668 }
669
670 TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
671 return STATUS_SUCCESS;
672
673 error:
674 ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
675 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
676 ExitThreadCallback(Thread);
677 return Status;
678 }
679
680 VOID
681 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
682
683 NTSTATUS
684 NTAPI
685 ExitThreadCallback(PETHREAD Thread)
686 {
687 PTHREADINFO *ppti;
688 PSINGLE_LIST_ENTRY psle;
689 PPROCESSINFO ppiCurrent;
690 PEPROCESS Process;
691 PTHREADINFO ptiCurrent;
692
693 Process = Thread->ThreadsProcess;
694
695 /* Get the Win32 Thread */
696 ptiCurrent = PsGetThreadWin32Thread(Thread);
697 ASSERT(ptiCurrent);
698
699 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
700
701 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
702 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
703
704 ppiCurrent = ptiCurrent->ppi;
705 ASSERT(ppiCurrent);
706
707 IsRemoveAttachThread(ptiCurrent);
708
709 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
710 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
711
712 /* Decrement thread count and check if its 0 */
713 ppiCurrent->cThreads--;
714
715 if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
716 {
717 /* Do now some process cleanup that requires a valid win32 thread */
718 if (ptiCurrent->ppi->cThreads == 0)
719 {
720 /* Check if we have registered the user api hook */
721 if (ptiCurrent->ppi == ppiUahServer)
722 {
723 /* Unregister the api hook */
724 UserUnregisterUserApiHook();
725 }
726
727 /* Notify logon application to restart shell if needed */
728 if (ptiCurrent->pDeskInfo)
729 {
730 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
731 {
732 DWORD ExitCode = PsGetProcessExitStatus(Process);
733
734 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
735
736 UserPostMessage(hwndSAS,
737 WM_LOGONNOTIFY,
738 LN_SHELL_EXITED,
739 ExitCode);
740
741 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
742 }
743 }
744 }
745
746 DceFreeThreadDCE(ptiCurrent);
747 DestroyTimersForThread(ptiCurrent);
748 KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
749 UnregisterThreadHotKeys(ptiCurrent);
750
751 if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
752 {
753 DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
754 ASSERT(FALSE);
755 return STATUS_UNSUCCESSFUL;
756 }
757
758 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
759 ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
760 {
761 TRACE_CH(UserThread, "DestroyProcessClasses\n");
762 /* no process windows should exist at this point, or the function will assert! */
763 DestroyProcessClasses(ppiCurrent);
764 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
765 }
766
767 IntBlockInput(ptiCurrent, FALSE);
768 IntCleanupThreadCallbacks(ptiCurrent);
769
770 /* cleanup user object references stack */
771 psle = PopEntryList(&ptiCurrent->ReferencesList);
772 while (psle)
773 {
774 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
775 TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
776 UserDereferenceObject(ref->obj);
777
778 psle = PopEntryList(&ptiCurrent->ReferencesList);
779 }
780 }
781
782 if (ptiCurrent->cEnterCount)
783 {
784 KeSetKernelStackSwapEnable(TRUE);
785 ptiCurrent->cEnterCount = 0;
786 }
787
788 /* Find the THREADINFO in the PROCESSINFO's list */
789 ppti = &ppiCurrent->ptiList;
790 while (*ppti != NULL && *ppti != ptiCurrent)
791 {
792 ppti = &((*ppti)->ptiSibling);
793 }
794
795 /* we must have found it */
796 ASSERT(*ppti == ptiCurrent);
797
798 /* Remove it from the list */
799 *ppti = ptiCurrent->ptiSibling;
800
801 if (ptiCurrent->KeyboardLayout)
802 UserDereferenceObject(ptiCurrent->KeyboardLayout);
803
804 if (gptiForeground == ptiCurrent)
805 {
806 // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
807 // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
808
809 gptiForeground = NULL;
810 }
811
812 /* Restore display mode when we are the last thread, and we changed the display mode */
813 if (ppiCurrent->cThreads == 0)
814 UserDisplayNotifyShutdown(ppiCurrent);
815
816
817 // Fixes CORE-6384 & CORE-7030.
818 /* if (ptiLastInput == ptiCurrent)
819 {
820 if (!ppiCurrent->ptiList)
821 ptiLastInput = gptiForeground;
822 else
823 ptiLastInput = ppiCurrent->ptiList;
824 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
825 }
826 */
827 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
828
829 IntSetThreadDesktop(NULL, TRUE);
830
831 if (ptiCurrent->hEventQueueClient != NULL)
832 {
833 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
834 ObDereferenceObject(ptiCurrent->pEventQueueServer);
835 }
836 ptiCurrent->hEventQueueClient = NULL;
837
838 /* The thread is dying */
839 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
840 ptiCurrent->pEThread = NULL;
841
842 /* Free the THREADINFO */
843 FreeW32Thread(/*Thread*/ ptiCurrent); // IntDereferenceThreadInfo(ptiCurrent);
844
845 return STATUS_SUCCESS;
846 }
847
848 NTSTATUS
849 APIENTRY
850 Win32kThreadCallback(PETHREAD Thread,
851 PSW32THREADCALLOUTTYPE Type)
852 {
853 NTSTATUS Status;
854
855 ASSERT(NtCurrentTeb());
856
857 UserEnterExclusive();
858
859 if (Type == PsW32ThreadCalloutInitialize)
860 {
861 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
862 Status = InitThreadCallback(Thread);
863 }
864 else // if (Type == PsW32ThreadCalloutExit)
865 {
866 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
867 Status = ExitThreadCallback(Thread);
868 }
869
870 UserLeave();
871
872 return Status;
873 }
874
875 _Function_class_(DRIVER_UNLOAD)
876 VOID NTAPI
877 DriverUnload(IN PDRIVER_OBJECT DriverObject)
878 {
879 // TODO: Do more cleanup!
880
881 ResetCsrApiPort();
882 ResetCsrProcess();
883 }
884
885 // Return on failure
886 #define NT_ROF(x) \
887 { \
888 Status = (x); \
889 if (!NT_SUCCESS(Status)) \
890 { \
891 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
892 return Status; \
893 } \
894 }
895
896 /*
897 * This definition doesn't work
898 */
899 INIT_SECTION
900 NTSTATUS
901 APIENTRY
902 DriverEntry(
903 IN PDRIVER_OBJECT DriverObject,
904 IN PUNICODE_STRING RegistryPath)
905 {
906 NTSTATUS Status;
907 BOOLEAN Result;
908 WIN32_CALLOUTS_FPNS CalloutData = {0};
909 PVOID GlobalUserHeapBase = NULL;
910
911 /*
912 * Register user mode call interface
913 * (system service table index = 1)
914 */
915 Result = KeAddSystemServiceTable(Win32kSSDT,
916 NULL,
917 Win32kNumberOfSysCalls,
918 Win32kSSPT,
919 1);
920 if (Result == FALSE)
921 {
922 DPRINT1("Adding system services failed!\n");
923 return STATUS_UNSUCCESSFUL;
924 }
925
926 hModuleWin = MmPageEntireDriver(DriverEntry);
927 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
928
929 DriverObject->DriverUnload = DriverUnload;
930
931 /* Register Object Manager Callbacks */
932 CalloutData.ProcessCallout = Win32kProcessCallback;
933 CalloutData.ThreadCallout = Win32kThreadCallback;
934 // CalloutData.GlobalAtomTableCallout = NULL;
935 // CalloutData.PowerEventCallout = NULL;
936 // CalloutData.PowerStateCallout = NULL;
937 // CalloutData.JobCallout = NULL;
938 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
939 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
940 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
941 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
942 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
943 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
944 // CalloutData.WindowStationCloseProcedure = NULL;
945 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
946 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
947 // CalloutData.WindowStationOpenProcedure = NULL;
948
949 /* Register our per-process and per-thread structures. */
950 PsEstablishWin32Callouts(&CalloutData);
951
952 /* Register service hook callbacks */
953 #if DBG && defined(KDBG)
954 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
955 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
956 #endif
957
958 /* Create the global USER heap */
959 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
960 &GlobalUserHeapBase,
961 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
962 if (GlobalUserHeap == NULL)
963 {
964 DPRINT1("Failed to initialize the global heap!\n");
965 return STATUS_UNSUCCESSFUL;
966 }
967
968 /* Allocate global server info structure */
969 gpsi = UserHeapAlloc(sizeof(*gpsi));
970 if (!gpsi)
971 {
972 DPRINT1("Failed allocate server info structure!\n");
973 return STATUS_UNSUCCESSFUL;
974 }
975
976 RtlZeroMemory(gpsi, sizeof(*gpsi));
977 DPRINT("Global Server Data -> %p\n", gpsi);
978
979 NT_ROF(InitGdiHandleTable());
980 NT_ROF(InitPaletteImpl());
981
982 /* Create stock objects, ie. precreated objects commonly
983 used by win32 applications */
984 CreateStockObjects();
985 CreateSysColorObjects();
986
987 NT_ROF(InitBrushImpl());
988 NT_ROF(InitPDEVImpl());
989 NT_ROF(InitLDEVImpl());
990 NT_ROF(InitDeviceImpl());
991 NT_ROF(InitDcImpl());
992 NT_ROF(InitUserImpl());
993 NT_ROF(InitWindowStationImpl());
994 NT_ROF(InitDesktopImpl());
995 NT_ROF(InitInputImpl());
996 NT_ROF(InitKeyboardImpl());
997 NT_ROF(MsqInitializeImpl());
998 NT_ROF(InitTimerImpl());
999 NT_ROF(InitDCEImpl());
1000
1001 /* Initialize FreeType library */
1002 if (!InitFontSupport())
1003 {
1004 DPRINT1("Unable to initialize font support\n");
1005 return Status;
1006 }
1007
1008 gusLanguageID = UserGetLanguageID();
1009
1010 return STATUS_SUCCESS;
1011 }
1012
1013 /* EOF */