f9aed03b77e6ae30759f4b6c7e72cd938c8cd96a
[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_SCRNSAVER )
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 /* CSRSS threads have some special features */
536 if (Process == gpepCSRSS)
537 ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
538
539 // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
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 /* Assign a default window station and desktop to the process */
574 /* Do not try to open a desktop or window station before winlogon initializes */
575 if (ptiCurrent->ppi->hdeskStartup == NULL && gpidLogon != 0)
576 {
577 HWINSTA hWinSta = NULL;
578 HDESK hDesk = NULL;
579 UNICODE_STRING DesktopPath;
580 PDESKTOP pdesk;
581
582 /*
583 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
584 * info structure. See documentation of CreateProcess()
585 */
586
587 Status = STATUS_UNSUCCESSFUL;
588 if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
589 {
590 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
591 }
592 if (!NT_SUCCESS(Status))
593 {
594 RtlInitUnicodeString(&DesktopPath, NULL);
595 }
596
597 Status = IntParseDesktopPath(Process,
598 &DesktopPath,
599 &hWinSta,
600 &hDesk);
601
602 if (DesktopPath.Buffer)
603 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
604
605 if (!NT_SUCCESS(Status))
606 {
607 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
608 goto error;
609 }
610
611 if (!UserSetProcessWindowStation(hWinSta))
612 {
613 Status = STATUS_UNSUCCESSFUL;
614 ERR_CH(UserThread, "Failed to set initial process winsta\n");
615 goto error;
616 }
617
618 /* Validate the new desktop. */
619 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
620 if (!NT_SUCCESS(Status))
621 {
622 ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
623 goto error;
624 }
625
626 /* Store the parsed desktop as the initial desktop */
627 ptiCurrent->ppi->hdeskStartup = hDesk;
628 ptiCurrent->ppi->rpdeskStartup = pdesk;
629 }
630
631 if (ptiCurrent->ppi->hdeskStartup != NULL)
632 {
633 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
634 {
635 ERR_CH(UserThread, "Failed to set thread desktop\n");
636 Status = STATUS_UNSUCCESSFUL;
637 goto error;
638 }
639 }
640
641 /* Mark the thread as fully initialized */
642 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
643
644 if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
645 (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
646 {
647 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
648 }
649 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
650
651 /* Last things to do only if we are not a SYSTEM or CSRSS thread */
652 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
653 {
654 /* Callback to User32 Client Thread Setup */
655 TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
656 Status = co_IntClientThreadSetup();
657 if (!NT_SUCCESS(Status))
658 {
659 ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
660 goto error;
661 }
662 TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
663 }
664 else
665 {
666 TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
667 }
668
669 TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
670 return STATUS_SUCCESS;
671
672 error:
673 ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
674 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
675 ExitThreadCallback(Thread);
676 return Status;
677 }
678
679 VOID
680 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
681
682 NTSTATUS
683 NTAPI
684 ExitThreadCallback(PETHREAD Thread)
685 {
686 PTHREADINFO *ppti;
687 PSINGLE_LIST_ENTRY psle;
688 PPROCESSINFO ppiCurrent;
689 PEPROCESS Process;
690 PTHREADINFO ptiCurrent;
691
692 Process = Thread->ThreadsProcess;
693
694 /* Get the Win32 Thread */
695 ptiCurrent = PsGetThreadWin32Thread(Thread);
696 ASSERT(ptiCurrent);
697
698 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
699
700 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
701 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
702
703 ppiCurrent = ptiCurrent->ppi;
704 ASSERT(ppiCurrent);
705
706 IsRemoveAttachThread(ptiCurrent);
707
708 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
709 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
710
711 UserCloseClipboard();
712
713 /* Decrement thread count and check if its 0 */
714 ppiCurrent->cThreads--;
715
716 if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
717 {
718 /* Do now some process cleanup that requires a valid win32 thread */
719 if (ptiCurrent->ppi->cThreads == 0)
720 {
721 /* Check if we have registered the user api hook */
722 if (ptiCurrent->ppi == ppiUahServer)
723 {
724 /* Unregister the api hook */
725 UserUnregisterUserApiHook();
726 }
727
728 /* Notify logon application to restart shell if needed */
729 if (ptiCurrent->pDeskInfo)
730 {
731 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
732 {
733 DWORD ExitCode = PsGetProcessExitStatus(Process);
734
735 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
736
737 UserPostMessage(hwndSAS,
738 WM_LOGONNOTIFY,
739 LN_SHELL_EXITED,
740 ExitCode);
741
742 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
743 }
744 }
745 }
746
747 DceFreeThreadDCE(ptiCurrent);
748 DestroyTimersForThread(ptiCurrent);
749 KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
750 UnregisterThreadHotKeys(ptiCurrent);
751
752 if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
753 {
754 DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
755 ASSERT(FALSE);
756 return STATUS_UNSUCCESSFUL;
757 }
758
759 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
760 ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
761 {
762 TRACE_CH(UserThread, "DestroyProcessClasses\n");
763 /* no process windows should exist at this point, or the function will assert! */
764 DestroyProcessClasses(ppiCurrent);
765 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
766 }
767
768 IntBlockInput(ptiCurrent, FALSE);
769 IntCleanupThreadCallbacks(ptiCurrent);
770
771 /* cleanup user object references stack */
772 psle = PopEntryList(&ptiCurrent->ReferencesList);
773 while (psle)
774 {
775 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
776 TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
777 UserDereferenceObject(ref->obj);
778
779 psle = PopEntryList(&ptiCurrent->ReferencesList);
780 }
781 }
782
783 if (ptiCurrent->cEnterCount)
784 {
785 KeSetKernelStackSwapEnable(TRUE);
786 ptiCurrent->cEnterCount = 0;
787 }
788
789 /* Find the THREADINFO in the PROCESSINFO's list */
790 ppti = &ppiCurrent->ptiList;
791 while (*ppti != NULL && *ppti != ptiCurrent)
792 {
793 ppti = &((*ppti)->ptiSibling);
794 }
795
796 /* we must have found it */
797 ASSERT(*ppti == ptiCurrent);
798
799 /* Remove it from the list */
800 *ppti = ptiCurrent->ptiSibling;
801
802 if (ptiCurrent->KeyboardLayout)
803 UserDereferenceObject(ptiCurrent->KeyboardLayout);
804
805 if (gptiForeground == ptiCurrent)
806 {
807 // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
808 // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
809
810 gptiForeground = NULL;
811 }
812
813 /* Restore display mode when we are the last thread, and we changed the display mode */
814 if (ppiCurrent->cThreads == 0)
815 UserDisplayNotifyShutdown(ppiCurrent);
816
817
818 // Fixes CORE-6384 & CORE-7030.
819 /* if (ptiLastInput == ptiCurrent)
820 {
821 if (!ppiCurrent->ptiList)
822 ptiLastInput = gptiForeground;
823 else
824 ptiLastInput = ppiCurrent->ptiList;
825 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
826 }
827 */
828 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
829
830 IntSetThreadDesktop(NULL, TRUE);
831
832 if (ptiCurrent->hEventQueueClient != NULL)
833 {
834 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
835 ObDereferenceObject(ptiCurrent->pEventQueueServer);
836 }
837 ptiCurrent->hEventQueueClient = NULL;
838
839 /* The thread is dying */
840 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
841 ptiCurrent->pEThread = NULL;
842
843 /* Free the THREADINFO */
844 FreeW32Thread(/*Thread*/ ptiCurrent); // IntDereferenceThreadInfo(ptiCurrent);
845
846 return STATUS_SUCCESS;
847 }
848
849 NTSTATUS
850 APIENTRY
851 Win32kThreadCallback(PETHREAD Thread,
852 PSW32THREADCALLOUTTYPE Type)
853 {
854 NTSTATUS Status;
855
856 ASSERT(NtCurrentTeb());
857
858 UserEnterExclusive();
859
860 if (Type == PsW32ThreadCalloutInitialize)
861 {
862 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
863 Status = InitThreadCallback(Thread);
864 }
865 else // if (Type == PsW32ThreadCalloutExit)
866 {
867 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
868 Status = ExitThreadCallback(Thread);
869 }
870
871 UserLeave();
872
873 return Status;
874 }
875
876 _Function_class_(DRIVER_UNLOAD)
877 VOID NTAPI
878 DriverUnload(IN PDRIVER_OBJECT DriverObject)
879 {
880 // TODO: Do more cleanup!
881
882 ResetCsrApiPort();
883 ResetCsrProcess();
884 }
885
886 // Return on failure
887 #define NT_ROF(x) \
888 { \
889 Status = (x); \
890 if (!NT_SUCCESS(Status)) \
891 { \
892 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
893 return Status; \
894 } \
895 }
896
897 /*
898 * This definition doesn't work
899 */
900 INIT_SECTION
901 NTSTATUS
902 APIENTRY
903 DriverEntry(
904 IN PDRIVER_OBJECT DriverObject,
905 IN PUNICODE_STRING RegistryPath)
906 {
907 NTSTATUS Status;
908 BOOLEAN Result;
909 WIN32_CALLOUTS_FPNS CalloutData = {0};
910 PVOID GlobalUserHeapBase = NULL;
911
912 /*
913 * Register user mode call interface
914 * (system service table index = 1)
915 */
916 Result = KeAddSystemServiceTable(Win32kSSDT,
917 NULL,
918 Win32kNumberOfSysCalls,
919 Win32kSSPT,
920 1);
921 if (Result == FALSE)
922 {
923 DPRINT1("Adding system services failed!\n");
924 return STATUS_UNSUCCESSFUL;
925 }
926
927 hModuleWin = MmPageEntireDriver(DriverEntry);
928 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
929
930 DriverObject->DriverUnload = DriverUnload;
931
932 /* Register Object Manager Callbacks */
933 CalloutData.ProcessCallout = Win32kProcessCallback;
934 CalloutData.ThreadCallout = Win32kThreadCallback;
935 // CalloutData.GlobalAtomTableCallout = NULL;
936 // CalloutData.PowerEventCallout = NULL;
937 // CalloutData.PowerStateCallout = NULL;
938 // CalloutData.JobCallout = NULL;
939 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
940 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
941 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
942 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
943 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
944 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
945 // CalloutData.WindowStationCloseProcedure = NULL;
946 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
947 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
948 // CalloutData.WindowStationOpenProcedure = NULL;
949
950 /* Register our per-process and per-thread structures. */
951 PsEstablishWin32Callouts(&CalloutData);
952
953 /* Register service hook callbacks */
954 #if DBG && defined(KDBG)
955 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
956 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
957 #endif
958
959 /* Create the global USER heap */
960 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
961 &GlobalUserHeapBase,
962 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
963 if (GlobalUserHeap == NULL)
964 {
965 DPRINT1("Failed to initialize the global heap!\n");
966 return STATUS_UNSUCCESSFUL;
967 }
968
969 /* Allocate global server info structure */
970 gpsi = UserHeapAlloc(sizeof(*gpsi));
971 if (!gpsi)
972 {
973 DPRINT1("Failed allocate server info structure!\n");
974 return STATUS_UNSUCCESSFUL;
975 }
976
977 RtlZeroMemory(gpsi, sizeof(*gpsi));
978 DPRINT("Global Server Data -> %p\n", gpsi);
979
980 NT_ROF(InitGdiHandleTable());
981 NT_ROF(InitPaletteImpl());
982
983 /* Create stock objects, ie. precreated objects commonly
984 used by win32 applications */
985 CreateStockObjects();
986 CreateSysColorObjects();
987
988 NT_ROF(InitBrushImpl());
989 NT_ROF(InitPDEVImpl());
990 NT_ROF(InitLDEVImpl());
991 NT_ROF(InitDeviceImpl());
992 NT_ROF(InitDcImpl());
993 NT_ROF(InitUserImpl());
994 NT_ROF(InitWindowStationImpl());
995 NT_ROF(InitDesktopImpl());
996 NT_ROF(InitInputImpl());
997 NT_ROF(InitKeyboardImpl());
998 NT_ROF(MsqInitializeImpl());
999 NT_ROF(InitTimerImpl());
1000 NT_ROF(InitDCEImpl());
1001
1002 gusLanguageID = UserGetLanguageID();
1003
1004 /* Initialize FreeType library */
1005 if (!InitFontSupport())
1006 {
1007 DPRINT1("Unable to initialize font support\n");
1008 return Status;
1009 }
1010
1011 return STATUS_SUCCESS;
1012 }
1013
1014 /* EOF */