9dd8cfe2f5400ea1fede8a657a07026b04f81e79
[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 if (ptiCurrent)
383 {
384 ERR_CH(UserThread, "PsGetThreadWin32Thread returned non-NULL thread info!!\n");
385 // return STATUS_SUCCESS;
386 }
387
388 /* Allocate a new Win32 thread info */
389 ptiCurrent = ExAllocatePoolWithTag(NonPagedPool,
390 sizeof(*ptiCurrent),
391 USERTAG_THREADINFO);
392 if (ptiCurrent == NULL)
393 {
394 ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
395 HandleToUlong(Thread->Cid.UniqueThread));
396 return STATUS_NO_MEMORY;
397 }
398
399 TRACE_CH(UserThread, "Allocated pti 0x%p for TID:0x%lx\n",
400 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
401
402 RtlZeroMemory(ptiCurrent, sizeof(*ptiCurrent));
403
404 PsSetThreadWin32Thread(Thread, ptiCurrent, NULL);
405 IntReferenceThreadInfo(ptiCurrent);
406
407 *W32Thread = ptiCurrent;
408 return STATUS_SUCCESS;
409 }
410
411 #define FreeW32Thread(/*Thread*/ W32Thread) \
412 do { \
413 /*PTHREADINFO W32Thread = PsGetThreadWin32Thread(Thread);*/ \
414 /*ASSERT(W32Thread);*/ \
415 IntDereferenceThreadInfo(W32Thread); \
416 } while(0)
417
418 /*
419 * Called from IntDereferenceThreadInfo
420 */
421 VOID
422 UserDeleteW32Thread(PTHREADINFO pti)
423 {
424 PPROCESSINFO ppi = pti->ppi;
425
426 TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
427
428 /* Free the message queue */
429 if (pti->MessageQueue)
430 {
431 MsqDestroyMessageQueue(pti);
432 }
433
434 MsqCleanupThreadMsgs(pti);
435
436 ExFreePoolWithTag(pti, USERTAG_THREADINFO);
437
438 IntDereferenceProcessInfo(ppi);
439 }
440
441 NTSTATUS
442 UserThreadCreate(PETHREAD Thread)
443 {
444 return STATUS_SUCCESS;
445 }
446
447 NTSTATUS
448 UserThreadDestroy(PETHREAD Thread)
449 {
450 return STATUS_SUCCESS;
451 }
452
453 NTSTATUS NTAPI
454 InitThreadCallback(PETHREAD Thread)
455 {
456 PEPROCESS Process;
457 PCLIENTINFO pci;
458 PTHREADINFO ptiCurrent;
459 int i;
460 NTSTATUS Status = STATUS_SUCCESS;
461 PTEB pTeb;
462 LARGE_INTEGER LargeTickCount;
463 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
464
465 Process = Thread->ThreadsProcess;
466
467 pTeb = NtCurrentTeb();
468 ASSERT(pTeb);
469
470 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
471
472 /* Allocate a new Win32 thread info */
473 Status = AllocW32Thread(Thread, &ptiCurrent);
474 if (!NT_SUCCESS(Status))
475 {
476 ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
477 HandleToUlong(Thread->Cid.UniqueThread));
478 return Status;
479 }
480
481 /* Initialize the THREADINFO */
482 ptiCurrent->pEThread = Thread;
483 ptiCurrent->ppi = PsGetProcessWin32Process(Process);
484 IntReferenceProcessInfo(ptiCurrent->ppi);
485 pTeb->Win32ThreadInfo = ptiCurrent;
486 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
487
488 /* Mark the process as having threads */
489 ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
490
491 InitializeListHead(&ptiCurrent->WindowListHead);
492 InitializeListHead(&ptiCurrent->W32CallbackListHead);
493 InitializeListHead(&ptiCurrent->PostedMessagesListHead);
494 InitializeListHead(&ptiCurrent->SentMessagesListHead);
495 InitializeListHead(&ptiCurrent->DispatchingMessagesHead);
496 InitializeListHead(&ptiCurrent->LocalDispatchingMessagesHead);
497 InitializeListHead(&ptiCurrent->PtiLink);
498 for (i = 0; i < NB_HOOKS; i++)
499 {
500 InitializeListHead(&ptiCurrent->aphkStart[i]);
501 }
502 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
503 ptiCurrent->ppi->ptiList = ptiCurrent;
504 ptiCurrent->ppi->cThreads++;
505
506 ptiCurrent->hEventQueueClient = NULL;
507 Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS,
508 NULL, SynchronizationEvent, FALSE);
509 if (!NT_SUCCESS(Status))
510 {
511 ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
512 goto error;
513 }
514 Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
515 *ExEventObjectType, KernelMode,
516 (PVOID*)&ptiCurrent->pEventQueueServer, NULL);
517 if (!NT_SUCCESS(Status))
518 {
519 ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
520 ZwClose(ptiCurrent->hEventQueueClient);
521 ptiCurrent->hEventQueueClient = NULL;
522 goto error;
523 }
524
525 KeQueryTickCount(&LargeTickCount);
526 ptiCurrent->timeLast = LargeTickCount.u.LowPart;
527
528 ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
529 if (ptiCurrent->MessageQueue == NULL)
530 {
531 ERR_CH(UserThread, "Failed to allocate message loop\n");
532 Status = STATUS_NO_MEMORY;
533 goto error;
534 }
535
536 ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
537 if (ptiCurrent->KeyboardLayout)
538 UserReferenceObject(ptiCurrent->KeyboardLayout);
539
540 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
541
542 /* CSRSS threads have some special features */
543 if (Process == gpepCSRSS)
544 ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
545
546 // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
547
548 ptiCurrent->pcti = &ptiCurrent->cti;
549
550 /* Initialize the CLIENTINFO */
551 pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
552 RtlZeroMemory(pci, sizeof(*pci));
553 pci->ppi = ptiCurrent->ppi;
554 pci->fsHooks = ptiCurrent->fsHooks;
555 pci->dwTIFlags = ptiCurrent->TIF_flags;
556 if (ptiCurrent->KeyboardLayout)
557 {
558 pci->hKL = ptiCurrent->KeyboardLayout->hkl;
559 pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
560 }
561
562 /* Need to pass the user Startup Information to the current process. */
563 if ( ProcessParams )
564 {
565 if ( ptiCurrent->ppi->usi.cb == 0 ) // Not initialized yet.
566 {
567 if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
568 {
569 ptiCurrent->ppi->usi.cb = sizeof(USERSTARTUPINFO);
570 ptiCurrent->ppi->usi.dwX = ProcessParams->StartingX;
571 ptiCurrent->ppi->usi.dwY = ProcessParams->StartingY;
572 ptiCurrent->ppi->usi.dwXSize = ProcessParams->CountX;
573 ptiCurrent->ppi->usi.dwYSize = ProcessParams->CountY;
574 ptiCurrent->ppi->usi.dwFlags = ProcessParams->WindowFlags;
575 ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
576 }
577 }
578 }
579
580 /* Assign a default window station and desktop to the process */
581 /* Do not try to open a desktop or window station before winlogon initializes */
582 if (ptiCurrent->ppi->hdeskStartup == NULL && gpidLogon != 0)
583 {
584 HWINSTA hWinSta = NULL;
585 HDESK hDesk = NULL;
586 UNICODE_STRING DesktopPath;
587 PDESKTOP pdesk;
588
589 /*
590 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
591 * info structure. See documentation of CreateProcess()
592 */
593
594 Status = STATUS_UNSUCCESSFUL;
595 if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
596 {
597 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
598 }
599 if (!NT_SUCCESS(Status))
600 {
601 RtlInitUnicodeString(&DesktopPath, NULL);
602 }
603
604 Status = IntParseDesktopPath(Process,
605 &DesktopPath,
606 &hWinSta,
607 &hDesk);
608
609 if (DesktopPath.Buffer)
610 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
611
612 if (!NT_SUCCESS(Status))
613 {
614 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
615 goto error;
616 }
617
618 if (!UserSetProcessWindowStation(hWinSta))
619 {
620 Status = STATUS_UNSUCCESSFUL;
621 ERR_CH(UserThread, "Failed to set initial process winsta\n");
622 goto error;
623 }
624
625 /* Validate the new desktop. */
626 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
627 if (!NT_SUCCESS(Status))
628 {
629 ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
630 goto error;
631 }
632
633 /* Store the parsed desktop as the initial desktop */
634 ptiCurrent->ppi->hdeskStartup = hDesk;
635 ptiCurrent->ppi->rpdeskStartup = pdesk;
636 }
637
638 if (ptiCurrent->ppi->hdeskStartup != NULL)
639 {
640 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
641 {
642 ERR_CH(UserThread, "Failed to set thread desktop\n");
643 Status = STATUS_UNSUCCESSFUL;
644 goto error;
645 }
646 }
647
648 /* Mark the thread as fully initialized */
649 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
650
651 if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
652 (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
653 {
654 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
655 }
656 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
657
658 /* Last things to do only if we are not a SYSTEM or CSRSS thread */
659 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
660 {
661 /* Callback to User32 Client Thread Setup */
662 TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
663 Status = co_IntClientThreadSetup();
664 if (!NT_SUCCESS(Status))
665 {
666 ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
667 goto error;
668 }
669 TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
670 }
671 else
672 {
673 TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
674 }
675
676 TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
677 return STATUS_SUCCESS;
678
679 error:
680 ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
681 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
682 ExitThreadCallback(Thread);
683 return Status;
684 }
685
686 NTSTATUS
687 NTAPI
688 ExitThreadCallback(PETHREAD Thread)
689 {
690 PTHREADINFO *ppti;
691 PSINGLE_LIST_ENTRY psle;
692 PPROCESSINFO ppiCurrent;
693 PEPROCESS Process;
694 PTHREADINFO ptiCurrent;
695
696 Process = Thread->ThreadsProcess;
697
698 /* Get the Win32 Thread */
699 ptiCurrent = PsGetThreadWin32Thread(Thread);
700 ASSERT(ptiCurrent);
701
702 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
703
704 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
705 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
706
707 ppiCurrent = ptiCurrent->ppi;
708 ASSERT(ppiCurrent);
709
710 IsRemoveAttachThread(ptiCurrent);
711
712 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
713 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
714
715 /* Decrement thread count and check if its 0 */
716 ppiCurrent->cThreads--;
717
718 if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
719 {
720 /* Do now some process cleanup that requires a valid win32 thread */
721 if (ptiCurrent->ppi->cThreads == 0)
722 {
723 /* Check if we have registered the user api hook */
724 if (ptiCurrent->ppi == ppiUahServer)
725 {
726 /* Unregister the api hook */
727 UserUnregisterUserApiHook();
728 }
729
730 /* Notify logon application to restart shell if needed */
731 if (ptiCurrent->pDeskInfo)
732 {
733 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
734 {
735 DWORD ExitCode = PsGetProcessExitStatus(Process);
736
737 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
738
739 UserPostMessage(hwndSAS,
740 WM_LOGONNOTIFY,
741 LN_SHELL_EXITED,
742 ExitCode);
743
744 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
745 }
746 }
747 }
748
749 DceFreeThreadDCE(ptiCurrent);
750 DestroyTimersForThread(ptiCurrent);
751 KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
752 UnregisterThreadHotKeys(ptiCurrent);
753
754 if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
755 {
756 DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
757 ASSERT(FALSE);
758 return STATUS_UNSUCCESSFUL;
759 }
760
761 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
762 ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
763 {
764 TRACE_CH(UserThread, "DestroyProcessClasses\n");
765 /* no process windows should exist at this point, or the function will assert! */
766 DestroyProcessClasses(ppiCurrent);
767 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
768 }
769
770 IntBlockInput(ptiCurrent, FALSE);
771 IntCleanupThreadCallbacks(ptiCurrent);
772
773 /* cleanup user object references stack */
774 psle = PopEntryList(&ptiCurrent->ReferencesList);
775 while (psle)
776 {
777 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
778 TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
779 UserDereferenceObject(ref->obj);
780
781 psle = PopEntryList(&ptiCurrent->ReferencesList);
782 }
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 ZwClose(ptiCurrent->hEventQueueClient);
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 */