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 PPROCESSINFO ppiScrnSaver;
30 PPROCESSINFO gppiList = NULL;
31
32 extern ULONG_PTR Win32kSSDT[];
33 extern UCHAR Win32kSSPT[];
34 extern ULONG Win32kNumberOfSysCalls;
35
36 #if DBG
37 void
38 NTAPI
DbgPreServiceHook(ULONG ulSyscallId,PULONG_PTR pulArguments)39 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
40 {
41 GdiDbgPreServiceHook(ulSyscallId, pulArguments);
42 UserDbgPreServiceHook(ulSyscallId, pulArguments);
43 }
44
45 ULONG_PTR
46 NTAPI
DbgPostServiceHook(ULONG ulSyscallId,ULONG_PTR ulResult)47 DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
48 {
49 ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
50 ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
51 return ulResult;
52 }
53 #endif
54
55
56 NTSTATUS
AllocW32Process(IN PEPROCESS Process,OUT PPROCESSINFO * W32Process)57 AllocW32Process(IN PEPROCESS Process,
58 OUT PPROCESSINFO* W32Process)
59 {
60 PPROCESSINFO ppiCurrent;
61
62 TRACE_CH(UserProcess, "In AllocW32Process(0x%p)\n", Process);
63
64 /* Check that we were not called with an already existing Win32 process info */
65 ppiCurrent = PsGetProcessWin32Process(Process);
66 if (ppiCurrent) return STATUS_SUCCESS;
67
68 /* Allocate a new Win32 process info */
69 ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
70 sizeof(*ppiCurrent),
71 USERTAG_PROCESSINFO);
72 if (ppiCurrent == NULL)
73 {
74 ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
75 HandleToUlong(Process->UniqueProcessId));
76 return STATUS_NO_MEMORY;
77 }
78
79 TRACE_CH(UserProcess, "Allocated ppi 0x%p for PID:0x%lx\n",
80 ppiCurrent, HandleToUlong(Process->UniqueProcessId));
81
82 RtlZeroMemory(ppiCurrent, sizeof(*ppiCurrent));
83
84 PsSetProcessWin32Process(Process, ppiCurrent, NULL);
85 IntReferenceProcessInfo(ppiCurrent);
86
87 *W32Process = ppiCurrent;
88 return STATUS_SUCCESS;
89 }
90
91 /*
92 * Called from IntDereferenceProcessInfo
93 */
94 VOID
UserDeleteW32Process(_Pre_notnull_ __drv_freesMem (Mem)PPROCESSINFO ppiCurrent)95 UserDeleteW32Process(
96 _Pre_notnull_ __drv_freesMem(Mem) PPROCESSINFO ppiCurrent)
97 {
98 if (ppiCurrent->InputIdleEvent)
99 {
100 /* Free the allocated memory */
101 ExFreePoolWithTag(ppiCurrent->InputIdleEvent, USERTAG_EVENT);
102 }
103
104 /* Close the startup desktop */
105 if (ppiCurrent->rpdeskStartup)
106 ObDereferenceObject(ppiCurrent->rpdeskStartup);
107
108 #if DBG
109 if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
110 {
111 TRACE_PPI(ppiCurrent, UserObj, "Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
112 DbgUserDumpHandleTable();
113 }
114 #endif
115
116 /* Free the PROCESSINFO */
117 ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
118 }
119
120 NTSTATUS
UserProcessCreate(PEPROCESS Process)121 UserProcessCreate(PEPROCESS Process)
122 {
123 PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
124 ASSERT(ppiCurrent);
125
126 InitializeListHead(&ppiCurrent->DriverObjListHead);
127 ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
128
129 {
130 PKEVENT Event;
131
132 /* Allocate memory for the event structure */
133 Event = ExAllocatePoolWithTag(NonPagedPool,
134 sizeof(*Event),
135 USERTAG_EVENT);
136 if (Event)
137 {
138 /* Initialize the kernel event */
139 KeInitializeEvent(Event,
140 SynchronizationEvent,
141 FALSE);
142 }
143 else
144 {
145 /* Out of memory */
146 DPRINT("CreateEvent() failed\n");
147 KeBugCheck(0);
148 }
149
150 /* Set the event */
151 ppiCurrent->InputIdleEvent = Event;
152 KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
153 }
154
155 ppiCurrent->peProcess = Process;
156 ppiCurrent->W32Pid = HandleToUlong(PsGetProcessId(Process));
157
158 /* Setup process flags */
159 ppiCurrent->W32PF_flags |= W32PF_PROCESSCONNECTED;
160 if (Process->Peb->ProcessParameters &&
161 (Process->Peb->ProcessParameters->WindowFlags & STARTF_SCREENSAVER))
162 {
163 ppiScrnSaver = ppiCurrent;
164 ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
165 }
166
167 // FIXME: check if this process is allowed.
168 ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application will get it toggled off.
169
170 return STATUS_SUCCESS;
171 }
172
173 NTSTATUS
UserProcessDestroy(PEPROCESS Process)174 UserProcessDestroy(PEPROCESS Process)
175 {
176 PPROCESSINFO ppiCurrent = PsGetProcessWin32Process(Process);
177 ASSERT(ppiCurrent);
178
179 if (ppiScrnSaver == ppiCurrent)
180 ppiScrnSaver = NULL;
181
182 IntFreeImeHotKeys();
183
184 if (gpwlCache)
185 {
186 ExFreePoolWithTag(gpwlCache, USERTAG_WINDOWLIST);
187 gpwlCache = NULL;
188 }
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
InitProcessCallback(PEPROCESS Process)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
ExitProcessCallback(PEPROCESS Process)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 IntDereferenceProcessInfo(ppiCurrent);
336
337 return STATUS_SUCCESS;
338 }
339
340 NTSTATUS
341 APIENTRY
Win32kProcessCallback(PEPROCESS Process,BOOLEAN Initialize)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
AllocW32Thread(IN PETHREAD Thread,OUT PTHREADINFO * W32Thread)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 ObReferenceObject(Thread);
401 IntReferenceThreadInfo(ptiCurrent);
402
403 *W32Thread = ptiCurrent;
404 return STATUS_SUCCESS;
405 }
406
407 /*
408 * Called from IntDereferenceThreadInfo
409 */
410 VOID
UserDeleteW32Thread(PTHREADINFO pti)411 UserDeleteW32Thread(PTHREADINFO pti)
412 {
413 PPROCESSINFO ppi = pti->ppi;
414
415 TRACE_CH(UserThread, "UserDeleteW32Thread pti 0x%p\n",pti);
416
417 /* Free the message queue */
418 if (pti->MessageQueue)
419 {
420 MsqDestroyMessageQueue(pti);
421 }
422
423 MsqCleanupThreadMsgs(pti);
424
425 ObDereferenceObject(pti->pEThread);
426
427 ExFreePoolWithTag(pti, USERTAG_THREADINFO);
428
429 IntDereferenceProcessInfo(ppi);
430
431 {
432 // Find another queue for mouse cursor.
433 MSG msg;
434 msg.message = WM_MOUSEMOVE;
435 msg.wParam = UserGetMouseButtonsState();
436 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
437 msg.pt = gpsi->ptCursor;
438 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
439 }
440 }
441
442 NTSTATUS
UserThreadCreate(PETHREAD Thread)443 UserThreadCreate(PETHREAD Thread)
444 {
445 return STATUS_SUCCESS;
446 }
447
448 NTSTATUS
UserThreadDestroy(PETHREAD Thread)449 UserThreadDestroy(PETHREAD Thread)
450 {
451 return STATUS_SUCCESS;
452 }
453
454 NTSTATUS NTAPI
InitThreadCallback(PETHREAD Thread)455 InitThreadCallback(PETHREAD Thread)
456 {
457 PEPROCESS Process;
458 PCLIENTINFO pci;
459 PTHREADINFO ptiCurrent;
460 int i;
461 NTSTATUS Status = STATUS_SUCCESS;
462 PTEB pTeb;
463 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
464 PKL pDefKL;
465
466 Process = Thread->ThreadsProcess;
467
468 pTeb = NtCurrentTeb();
469 ASSERT(pTeb);
470
471 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
472
473 /* Allocate a new Win32 thread info */
474 Status = AllocW32Thread(Thread, &ptiCurrent);
475 if (!NT_SUCCESS(Status))
476 {
477 ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n",
478 HandleToUlong(Thread->Cid.UniqueThread));
479 return Status;
480 }
481
482 /* Initialize the THREADINFO */
483 ptiCurrent->pEThread = Thread;
484 ptiCurrent->ppi = PsGetProcessWin32Process(Process);
485 IntReferenceProcessInfo(ptiCurrent->ppi);
486 pTeb->Win32ThreadInfo = ptiCurrent;
487 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
488 ptiCurrent->pcti = &ptiCurrent->cti;
489
490 /* Mark the process as having threads */
491 ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
492
493 InitializeListHead(&ptiCurrent->WindowListHead);
494 InitializeListHead(&ptiCurrent->W32CallbackListHead);
495 InitializeListHead(&ptiCurrent->PostedMessagesListHead);
496 InitializeListHead(&ptiCurrent->SentMessagesListHead);
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, UserMode,
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 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
521 ptiCurrent->hEventQueueClient = NULL;
522 goto error;
523 }
524
525 ptiCurrent->pcti->timeLastRead = EngGetTickCount32();
526
527 ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
528 if (ptiCurrent->MessageQueue == NULL)
529 {
530 ERR_CH(UserThread, "Failed to allocate message loop\n");
531 Status = STATUS_NO_MEMORY;
532 goto error;
533 }
534
535 pDefKL = W32kGetDefaultKeyLayout();
536 UserAssignmentLock((PVOID*)&(ptiCurrent->KeyboardLayout), pDefKL);
537
538 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
539
540 // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !!
541
542 /* CSRSS threads have some special features */
543 if (Process == gpepCSRSS || !gpepCSRSS)
544 ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE;
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 (pDefKL)
553 {
554 pci->hKL = pDefKL->hkl;
555 pci->CodePage = pDefKL->CodePage;
556 }
557
558 /* Populate dwExpWinVer */
559 if (Process->Peb)
560 ptiCurrent->dwExpWinVer = RtlGetExpWinVer(Process->SectionBaseAddress);
561 else
562 ptiCurrent->dwExpWinVer = WINVER_WINNT4;
563 pci->dwExpWinVer = ptiCurrent->dwExpWinVer;
564
565 /* Need to pass the user Startup Information to the current process. */
566 if ( ProcessParams )
567 {
568 if ( ptiCurrent->ppi->usi.cb == 0 ) // Not initialized yet.
569 {
570 if ( ProcessParams->WindowFlags != 0 ) // Need window flags set.
571 {
572 ptiCurrent->ppi->usi.cb = sizeof(USERSTARTUPINFO);
573 ptiCurrent->ppi->usi.dwX = ProcessParams->StartingX;
574 ptiCurrent->ppi->usi.dwY = ProcessParams->StartingY;
575 ptiCurrent->ppi->usi.dwXSize = ProcessParams->CountX;
576 ptiCurrent->ppi->usi.dwYSize = ProcessParams->CountY;
577 ptiCurrent->ppi->usi.dwFlags = ProcessParams->WindowFlags;
578 ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
579 }
580 }
581 }
582
583 /*
584 * Assign a default window station and desktop to the process.
585 * Do not try to open a desktop or window station before the very first
586 * (interactive) window station has been created by Winlogon.
587 */
588 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
589 ptiCurrent->ppi->hdeskStartup == NULL &&
590 InputWindowStation != NULL)
591 {
592 HWINSTA hWinSta = NULL;
593 HDESK hDesk = NULL;
594 UNICODE_STRING DesktopPath;
595 PDESKTOP pdesk;
596
597 /*
598 * Inherit the thread desktop and process window station (if not yet inherited)
599 * from the process startup info structure. See documentation of CreateProcess().
600 */
601 Status = STATUS_UNSUCCESSFUL;
602 if (ProcessParams && ProcessParams->DesktopInfo.Length > 0)
603 {
604 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
605 }
606 if (!NT_SUCCESS(Status))
607 {
608 RtlInitUnicodeString(&DesktopPath, NULL);
609 }
610
611 Status = IntResolveDesktop(Process,
612 &DesktopPath,
613 !!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP),
614 &hWinSta,
615 &hDesk);
616
617 if (DesktopPath.Buffer)
618 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
619
620 if (!NT_SUCCESS(Status))
621 {
622 ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n");
623 goto error;
624 }
625
626 if (!UserSetProcessWindowStation(hWinSta))
627 {
628 Status = STATUS_UNSUCCESSFUL;
629 ERR_CH(UserThread, "Failed to set initial process winsta\n");
630 goto error;
631 }
632
633 /* Validate the new desktop */
634 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
635 if (!NT_SUCCESS(Status))
636 {
637 ERR_CH(UserThread, "Failed to validate initial desktop handle\n");
638 goto error;
639 }
640
641 /* Store the parsed desktop as the initial desktop */
642 ASSERT(ptiCurrent->ppi->hdeskStartup == NULL);
643 ASSERT(Process->UniqueProcessId != gpidLogon);
644 ptiCurrent->ppi->hdeskStartup = hDesk;
645 ptiCurrent->ppi->rpdeskStartup = pdesk;
646 }
647
648 if (ptiCurrent->ppi->hdeskStartup != NULL)
649 {
650 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
651 {
652 ERR_CH(UserThread, "Failed to set thread desktop\n");
653 Status = STATUS_UNSUCCESSFUL;
654 goto error;
655 }
656 }
657
658 /* Mark the thread as fully initialized */
659 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
660
661 if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) &&
662 (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi ))
663 {
664 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
665 }
666 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
667
668 /* Create the default input context */
669 if (IS_IMM_MODE())
670 {
671 (VOID)UserCreateInputContext(0);
672 }
673
674 /* Last things to do only if we are not a SYSTEM or CSRSS thread */
675 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)))
676 {
677 /* Callback to User32 Client Thread Setup */
678 TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n");
679 Status = co_IntClientThreadSetup();
680 if (!NT_SUCCESS(Status))
681 {
682 ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status);
683 goto error;
684 }
685 TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n");
686 }
687 else
688 {
689 TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n");
690 }
691
692 TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent);
693 return STATUS_SUCCESS;
694
695 error:
696 ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n",
697 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread));
698 ExitThreadCallback(Thread);
699 return Status;
700 }
701
702 VOID
703 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent);
704
705 // Win: xxxDestroyThreadInfo
706 NTSTATUS
707 NTAPI
ExitThreadCallback(PETHREAD Thread)708 ExitThreadCallback(PETHREAD Thread)
709 {
710 PTHREADINFO *ppti;
711 PSINGLE_LIST_ENTRY psle;
712 PPROCESSINFO ppiCurrent;
713 PEPROCESS Process;
714 PTHREADINFO ptiCurrent;
715 PWINDOWLIST pwl, pwlNext;
716
717 Process = Thread->ThreadsProcess;
718
719 /* Get the Win32 Thread */
720 ptiCurrent = PsGetThreadWin32Thread(Thread);
721 ASSERT(ptiCurrent);
722
723 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
724
725 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
726 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
727
728 ppiCurrent = ptiCurrent->ppi;
729 ASSERT(ppiCurrent);
730
731 IsRemoveAttachThread(ptiCurrent);
732
733 if (gpwlList)
734 {
735 for (pwl = gpwlList; pwl; pwl = pwlNext)
736 {
737 pwlNext = pwl->pNextList;
738 if (pwl->pti == ptiCurrent)
739 IntFreeHwndList(pwl);
740 }
741 }
742
743 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE;
744 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
745
746 UserCloseClipboard();
747
748 /* Decrement thread count and check if its 0 */
749 ppiCurrent->cThreads--;
750
751 if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
752 {
753 /* Do now some process cleanup that requires a valid win32 thread */
754 if (ptiCurrent->ppi->cThreads == 0)
755 {
756 /* Check if we have registered the user api hook */
757 if (ptiCurrent->ppi == ppiUahServer)
758 {
759 /* Unregister the api hook */
760 UserUnregisterUserApiHook();
761 }
762
763 /* Notify logon application to restart shell if needed */
764 if (ptiCurrent->pDeskInfo)
765 {
766 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
767 {
768 DWORD ExitCode = PsGetProcessExitStatus(Process);
769
770 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
771
772 UserPostMessage(hwndSAS,
773 WM_LOGONNOTIFY,
774 LN_SHELL_EXITED,
775 ExitCode);
776
777 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
778 }
779 }
780 }
781
782 DceFreeThreadDCE(ptiCurrent);
783 DestroyTimersForThread(ptiCurrent);
784 KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
785 UnregisterThreadHotKeys(ptiCurrent);
786
787 if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
788 {
789 DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
790 ASSERT(FALSE);
791 return STATUS_UNSUCCESSFUL;
792 }
793 UserAssignmentUnlock((PVOID*)&ptiCurrent->spDefaultImc);
794
795 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
796 ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
797 {
798 TRACE_CH(UserThread, "DestroyProcessClasses\n");
799 /* no process windows should exist at this point, or the function will assert! */
800 DestroyProcessClasses(ppiCurrent);
801 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
802 }
803
804 IntBlockInput(ptiCurrent, FALSE);
805 IntCleanupThreadCallbacks(ptiCurrent);
806
807 /* cleanup user object references stack */
808 psle = PopEntryList(&ptiCurrent->ReferencesList);
809 while (psle)
810 {
811 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
812 TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj);
813 UserDereferenceObject(ref->obj);
814
815 psle = PopEntryList(&ptiCurrent->ReferencesList);
816 #if DBG
817 ptiCurrent->cRefObjectCo--;
818 #endif
819 }
820 }
821
822 if (ptiCurrent->cEnterCount)
823 {
824 KeSetKernelStackSwapEnable(TRUE);
825 ptiCurrent->cEnterCount = 0;
826 }
827
828 /* Find the THREADINFO in the PROCESSINFO's list */
829 ppti = &ppiCurrent->ptiList;
830 while (*ppti != NULL && *ppti != ptiCurrent)
831 {
832 ppti = &((*ppti)->ptiSibling);
833 }
834
835 /* we must have found it */
836 ASSERT(*ppti == ptiCurrent);
837
838 /* Remove it from the list */
839 *ppti = ptiCurrent->ptiSibling;
840
841 if (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout)))
842 ptiCurrent->pClientInfo->hKL = NULL;
843
844 if (gptiForeground == ptiCurrent)
845 {
846 // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
847 // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0);
848
849 gptiForeground = NULL;
850 }
851
852 /* Restore display mode when we are the last thread, and we changed the display mode */
853 if (ppiCurrent->cThreads == 0)
854 UserDisplayNotifyShutdown(ppiCurrent);
855
856
857 // Fixes CORE-6384 & CORE-7030.
858 /* if (ptiLastInput == ptiCurrent)
859 {
860 if (!ppiCurrent->ptiList)
861 ptiLastInput = gptiForeground;
862 else
863 ptiLastInput = ppiCurrent->ptiList;
864 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n");
865 }
866 */
867 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent);
868
869 IntSetThreadDesktop(NULL, TRUE);
870
871 if (ptiCurrent->hEventQueueClient != NULL)
872 {
873 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode);
874 ObDereferenceObject(ptiCurrent->pEventQueueServer);
875 }
876 ptiCurrent->hEventQueueClient = NULL;
877
878 ASSERT(ptiCurrent->cRefObjectCo == 0);
879
880 /* The thread is dying */
881 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent);
882
883 /* Dereference the THREADINFO */
884 IntDereferenceThreadInfo(ptiCurrent);
885
886 return STATUS_SUCCESS;
887 }
888
889 NTSTATUS
890 APIENTRY
Win32kThreadCallback(PETHREAD Thread,PSW32THREADCALLOUTTYPE Type)891 Win32kThreadCallback(PETHREAD Thread,
892 PSW32THREADCALLOUTTYPE Type)
893 {
894 NTSTATUS Status;
895
896 ASSERT(NtCurrentTeb());
897
898 UserEnterExclusive();
899
900 if (Type == PsW32ThreadCalloutInitialize)
901 {
902 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
903 Status = InitThreadCallback(Thread);
904 }
905 else // if (Type == PsW32ThreadCalloutExit)
906 {
907 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
908 Status = ExitThreadCallback(Thread);
909 }
910
911 UserLeave();
912
913 return Status;
914 }
915
_Function_class_(DRIVER_UNLOAD)916 _Function_class_(DRIVER_UNLOAD)
917 VOID NTAPI
918 DriverUnload(IN PDRIVER_OBJECT DriverObject)
919 {
920 // TODO: Do more cleanup!
921
922 FreeFontSupport();
923 ResetCsrApiPort();
924 ResetCsrProcess();
925 IntWin32PowerManagementCleanup();
926 }
927
928 // Return on failure
929 #define NT_ROF(x) \
930 { \
931 Status = (x); \
932 if (!NT_SUCCESS(Status)) \
933 { \
934 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
935 return Status; \
936 } \
937 }
938
939 // Lock & return on failure
940 #define USERLOCK_AND_ROF(x) \
941 { \
942 UserEnterExclusive(); \
943 Status = (x); \
944 UserLeave(); \
945 if (!NT_SUCCESS(Status)) \
946 { \
947 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
948 return Status; \
949 } \
950 }
951
952
953
954 /*
955 * This definition doesn't work
956 */
957 CODE_SEG("INIT")
958 NTSTATUS
959 APIENTRY
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)960 DriverEntry(
961 IN PDRIVER_OBJECT DriverObject,
962 IN PUNICODE_STRING RegistryPath)
963 {
964 NTSTATUS Status;
965 BOOLEAN Result;
966 WIN32_CALLOUTS_FPNS CalloutData = {0};
967 PVOID GlobalUserHeapBase = NULL;
968
969 /*
970 * Register user mode call interface
971 * (system service table index = 1)
972 */
973 Result = KeAddSystemServiceTable(Win32kSSDT,
974 NULL,
975 Win32kNumberOfSysCalls,
976 Win32kSSPT,
977 1);
978 if (Result == FALSE)
979 {
980 DPRINT1("Adding system services failed!\n");
981 return STATUS_UNSUCCESSFUL;
982 }
983
984 hModuleWin = MmPageEntireDriver(DriverEntry);
985 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
986
987 DriverObject->DriverUnload = DriverUnload;
988
989 /* Register Object Manager Callbacks */
990 CalloutData.ProcessCallout = Win32kProcessCallback;
991 CalloutData.ThreadCallout = Win32kThreadCallback;
992 // CalloutData.GlobalAtomTableCallout = NULL;
993 CalloutData.PowerEventCallout = IntHandlePowerEvent;
994 CalloutData.PowerStateCallout = IntHandlePowerState;
995 // CalloutData.JobCallout = NULL;
996 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
997 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen;
998 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
999 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose;
1000 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
1001 CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose;
1002 // CalloutData.WindowStationCloseProcedure = NULL;
1003 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
1004 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
1005 // CalloutData.WindowStationOpenProcedure = NULL;
1006
1007 /* Register our per-process and per-thread structures. */
1008 PsEstablishWin32Callouts(&CalloutData);
1009
1010 /* Register service hook callbacks */
1011 #if DBG && defined(KDBG)
1012 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
1013 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
1014 #endif
1015
1016 /* Create the global USER heap */
1017 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
1018 &GlobalUserHeapBase,
1019 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
1020 if (GlobalUserHeap == NULL)
1021 {
1022 DPRINT1("Failed to initialize the global heap!\n");
1023 return STATUS_UNSUCCESSFUL;
1024 }
1025
1026 /* Init the global user lock */
1027 ExInitializeResourceLite(&UserLock);
1028
1029 /* Lock while we use the heap (UserHeapAlloc asserts on this) */
1030 UserEnterExclusive();
1031
1032 /* Allocate global server info structure */
1033 gpsi = UserHeapAlloc(sizeof(*gpsi));
1034 UserLeave();
1035 if (!gpsi)
1036 {
1037 DPRINT1("Failed allocate server info structure!\n");
1038 return STATUS_UNSUCCESSFUL;
1039 }
1040
1041 RtlZeroMemory(gpsi, sizeof(*gpsi));
1042 DPRINT("Global Server Data -> %p\n", gpsi);
1043
1044 NT_ROF(InitGdiHandleTable());
1045 NT_ROF(InitPaletteImpl());
1046
1047 /* Create stock objects, ie. precreated objects commonly
1048 used by win32 applications */
1049 CreateStockObjects();
1050 CreateSysColorObjects();
1051
1052 NT_ROF(InitBrushImpl());
1053 NT_ROF(InitPDEVImpl());
1054 NT_ROF(InitLDEVImpl());
1055 NT_ROF(InitDeviceImpl());
1056 NT_ROF(InitDcImpl());
1057 USERLOCK_AND_ROF(InitUserImpl());
1058 NT_ROF(InitWindowStationImpl());
1059 NT_ROF(InitDesktopImpl());
1060 NT_ROF(InitInputImpl());
1061 NT_ROF(InitKeyboardImpl());
1062 NT_ROF(MsqInitializeImpl());
1063 NT_ROF(InitTimerImpl());
1064 NT_ROF(InitDCEImpl());
1065
1066 return STATUS_SUCCESS;
1067 }
1068
1069 /* EOF */
1070