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