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