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