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