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