0da71f8c4867fd38068f34b2dc9b92c6bdb0a16f
[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 NTSTATUS
681 NTAPI
682 ExitThreadCallback(PETHREAD Thread)
683 {
684 PTHREADINFO *ppti;
685 PSINGLE_LIST_ENTRY psle;
686 PPROCESSINFO ppiCurrent;
687 PEPROCESS Process;
688 PTHREADINFO ptiCurrent;
689
690 Process = Thread->ThreadsProcess;
691
692 /* Get the Win32 Thread */
693 ptiCurrent = PsGetThreadWin32Thread(Thread);
694 ASSERT(ptiCurrent);
695
696 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
697
698 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
699 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
700
701 ppiCurrent = ptiCurrent->ppi;
702 ASSERT(ppiCurrent);
703
704 IsRemoveAttachThread(ptiCurrent);
705
706 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
707 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
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 // Fixes CORE-6384 & CORE-7030.
810 /* if (ptiLastInput == ptiCurrent)
811 {
812 if (!ppiCurrent->ptiList)
813 ptiLastInput = gptiForeground;
814 else
815 ptiLastInput = ppiCurrent->ptiList;
816 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
817 }
818 */
819 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
820
821 IntSetThreadDesktop(NULL, TRUE);
822
823 if (ptiCurrent->hEventQueueClient != NULL)
824 {
825 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
826 ObDereferenceObject(ptiCurrent->pEventQueueServer);
827 }
828 ptiCurrent->hEventQueueClient = NULL;
829
830 /* The thread is dying */
831 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
832 ptiCurrent->pEThread = NULL;
833
834 /* Free the THREADINFO */
835 FreeW32Thread(/*Thread*/ ptiCurrent); // IntDereferenceThreadInfo(ptiCurrent);
836
837 return STATUS_SUCCESS;
838 }
839
840 NTSTATUS
841 APIENTRY
842 Win32kThreadCallback(PETHREAD Thread,
843 PSW32THREADCALLOUTTYPE Type)
844 {
845 NTSTATUS Status;
846
847 ASSERT(NtCurrentTeb());
848
849 UserEnterExclusive();
850
851 if (Type == PsW32ThreadCalloutInitialize)
852 {
853 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
854 Status = InitThreadCallback(Thread);
855 }
856 else // if (Type == PsW32ThreadCalloutExit)
857 {
858 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
859 Status = ExitThreadCallback(Thread);
860 }
861
862 UserLeave();
863
864 return Status;
865 }
866
867 _Function_class_(DRIVER_UNLOAD)
868 VOID NTAPI
869 DriverUnload(IN PDRIVER_OBJECT DriverObject)
870 {
871 // TODO: Do more cleanup!
872
873 ResetCsrApiPort();
874 ResetCsrProcess();
875 }
876
877 // Return on failure
878 #define NT_ROF(x) \
879 { \
880 Status = (x); \
881 if (!NT_SUCCESS(Status)) \
882 { \
883 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
884 return Status; \
885 } \
886 }
887
888 /*
889 * This definition doesn't work
890 */
891 INIT_SECTION
892 NTSTATUS
893 APIENTRY
894 DriverEntry(
895 IN PDRIVER_OBJECT DriverObject,
896 IN PUNICODE_STRING RegistryPath)
897 {
898 NTSTATUS Status;
899 BOOLEAN Result;
900 WIN32_CALLOUTS_FPNS CalloutData = {0};
901 PVOID GlobalUserHeapBase = NULL;
902
903 /*
904 * Register user mode call interface
905 * (system service table index = 1)
906 */
907 Result = KeAddSystemServiceTable(Win32kSSDT,
908 NULL,
909 Win32kNumberOfSysCalls,
910 Win32kSSPT,
911 1);
912 if (Result == FALSE)
913 {
914 DPRINT1("Adding system services failed!\n");
915 return STATUS_UNSUCCESSFUL;
916 }
917
918 hModuleWin = MmPageEntireDriver(DriverEntry);
919 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
920
921 DriverObject->DriverUnload = DriverUnload;
922
923 /* Register Object Manager Callbacks */
924 CalloutData.ProcessCallout = Win32kProcessCallback;
925 CalloutData.ThreadCallout = Win32kThreadCallback;
926 // CalloutData.GlobalAtomTableCallout = NULL;
927 // CalloutData.PowerEventCallout = NULL;
928 // CalloutData.PowerStateCallout = NULL;
929 // CalloutData.JobCallout = NULL;
930 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
931 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
932 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
933 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
934 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
935 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
936 // CalloutData.WindowStationCloseProcedure = NULL;
937 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
938 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
939 // CalloutData.WindowStationOpenProcedure = NULL;
940
941 /* Register our per-process and per-thread structures. */
942 PsEstablishWin32Callouts(&CalloutData);
943
944 /* Register service hook callbacks */
945 #if DBG && defined(KDBG)
946 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
947 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
948 #endif
949
950 /* Create the global USER heap */
951 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
952 &GlobalUserHeapBase,
953 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
954 if (GlobalUserHeap == NULL)
955 {
956 DPRINT1("Failed to initialize the global heap!\n");
957 return STATUS_UNSUCCESSFUL;
958 }
959
960 /* Allocate global server info structure */
961 gpsi = UserHeapAlloc(sizeof(*gpsi));
962 if (!gpsi)
963 {
964 DPRINT1("Failed allocate server info structure!\n");
965 return STATUS_UNSUCCESSFUL;
966 }
967
968 RtlZeroMemory(gpsi, sizeof(*gpsi));
969 DPRINT("Global Server Data -> %p\n", gpsi);
970
971 NT_ROF(InitGdiHandleTable());
972 NT_ROF(InitPaletteImpl());
973
974 /* Create stock objects, ie. precreated objects commonly
975 used by win32 applications */
976 CreateStockObjects();
977 CreateSysColorObjects();
978
979 NT_ROF(InitBrushImpl());
980 NT_ROF(InitPDEVImpl());
981 NT_ROF(InitLDEVImpl());
982 NT_ROF(InitDeviceImpl());
983 NT_ROF(InitDcImpl());
984 NT_ROF(InitUserImpl());
985 NT_ROF(InitWindowStationImpl());
986 NT_ROF(InitDesktopImpl());
987 NT_ROF(InitInputImpl());
988 NT_ROF(InitKeyboardImpl());
989 NT_ROF(MsqInitializeImpl());
990 NT_ROF(InitTimerImpl());
991 NT_ROF(InitDCEImpl());
992
993 /* Initialize FreeType library */
994 if (!InitFontSupport())
995 {
996 DPRINT1("Unable to initialize font support\n");
997 return Status;
998 }
999
1000 gusLanguageID = UserGetLanguageID();
1001
1002 return STATUS_SUCCESS;
1003 }
1004
1005 /* EOF */