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