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