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 39 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments) 40 { 41 GdiDbgPreServiceHook(ulSyscallId, pulArguments); 42 UserDbgPreServiceHook(ulSyscallId, pulArguments); 43 } 44 45 ULONG_PTR 46 NTAPI 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 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 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 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 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 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 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 ObReferenceObject(Thread); 401 IntReferenceThreadInfo(ptiCurrent); 402 403 *W32Thread = ptiCurrent; 404 return STATUS_SUCCESS; 405 } 406 407 /* 408 * Called from IntDereferenceThreadInfo 409 */ 410 VOID 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 443 UserThreadCreate(PETHREAD Thread) 444 { 445 return STATUS_SUCCESS; 446 } 447 448 NTSTATUS 449 UserThreadDestroy(PETHREAD Thread) 450 { 451 return STATUS_SUCCESS; 452 } 453 454 NTSTATUS NTAPI 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 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 } 817 } 818 819 if (ptiCurrent->cEnterCount) 820 { 821 KeSetKernelStackSwapEnable(TRUE); 822 ptiCurrent->cEnterCount = 0; 823 } 824 825 /* Find the THREADINFO in the PROCESSINFO's list */ 826 ppti = &ppiCurrent->ptiList; 827 while (*ppti != NULL && *ppti != ptiCurrent) 828 { 829 ppti = &((*ppti)->ptiSibling); 830 } 831 832 /* we must have found it */ 833 ASSERT(*ppti == ptiCurrent); 834 835 /* Remove it from the list */ 836 *ppti = ptiCurrent->ptiSibling; 837 838 if (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout))) 839 ptiCurrent->pClientInfo->hKL = NULL; 840 841 if (gptiForeground == ptiCurrent) 842 { 843 // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0); 844 // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0); 845 846 gptiForeground = NULL; 847 } 848 849 /* Restore display mode when we are the last thread, and we changed the display mode */ 850 if (ppiCurrent->cThreads == 0) 851 UserDisplayNotifyShutdown(ppiCurrent); 852 853 854 // Fixes CORE-6384 & CORE-7030. 855 /* if (ptiLastInput == ptiCurrent) 856 { 857 if (!ppiCurrent->ptiList) 858 ptiLastInput = gptiForeground; 859 else 860 ptiLastInput = ppiCurrent->ptiList; 861 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n"); 862 } 863 */ 864 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent); 865 866 IntSetThreadDesktop(NULL, TRUE); 867 868 if (ptiCurrent->hEventQueueClient != NULL) 869 { 870 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode); 871 ObDereferenceObject(ptiCurrent->pEventQueueServer); 872 } 873 ptiCurrent->hEventQueueClient = NULL; 874 875 /* The thread is dying */ 876 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent); 877 878 /* Dereference the THREADINFO */ 879 IntDereferenceThreadInfo(ptiCurrent); 880 881 return STATUS_SUCCESS; 882 } 883 884 NTSTATUS 885 APIENTRY 886 Win32kThreadCallback(PETHREAD Thread, 887 PSW32THREADCALLOUTTYPE Type) 888 { 889 NTSTATUS Status; 890 891 ASSERT(NtCurrentTeb()); 892 893 UserEnterExclusive(); 894 895 if (Type == PsW32ThreadCalloutInitialize) 896 { 897 ASSERT(PsGetThreadWin32Thread(Thread) == NULL); 898 Status = InitThreadCallback(Thread); 899 } 900 else // if (Type == PsW32ThreadCalloutExit) 901 { 902 ASSERT(PsGetThreadWin32Thread(Thread) != NULL); 903 Status = ExitThreadCallback(Thread); 904 } 905 906 UserLeave(); 907 908 return Status; 909 } 910 911 _Function_class_(DRIVER_UNLOAD) 912 VOID NTAPI 913 DriverUnload(IN PDRIVER_OBJECT DriverObject) 914 { 915 // TODO: Do more cleanup! 916 917 FreeFontSupport(); 918 ResetCsrApiPort(); 919 ResetCsrProcess(); 920 IntWin32PowerManagementCleanup(); 921 } 922 923 // Return on failure 924 #define NT_ROF(x) \ 925 { \ 926 Status = (x); \ 927 if (!NT_SUCCESS(Status)) \ 928 { \ 929 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 930 return Status; \ 931 } \ 932 } 933 934 // Lock & return on failure 935 #define USERLOCK_AND_ROF(x) \ 936 { \ 937 UserEnterExclusive(); \ 938 Status = (x); \ 939 UserLeave(); \ 940 if (!NT_SUCCESS(Status)) \ 941 { \ 942 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 943 return Status; \ 944 } \ 945 } 946 947 948 949 /* 950 * This definition doesn't work 951 */ 952 CODE_SEG("INIT") 953 NTSTATUS 954 APIENTRY 955 DriverEntry( 956 IN PDRIVER_OBJECT DriverObject, 957 IN PUNICODE_STRING RegistryPath) 958 { 959 NTSTATUS Status; 960 BOOLEAN Result; 961 WIN32_CALLOUTS_FPNS CalloutData = {0}; 962 PVOID GlobalUserHeapBase = NULL; 963 964 /* 965 * Register user mode call interface 966 * (system service table index = 1) 967 */ 968 Result = KeAddSystemServiceTable(Win32kSSDT, 969 NULL, 970 Win32kNumberOfSysCalls, 971 Win32kSSPT, 972 1); 973 if (Result == FALSE) 974 { 975 DPRINT1("Adding system services failed!\n"); 976 return STATUS_UNSUCCESSFUL; 977 } 978 979 hModuleWin = MmPageEntireDriver(DriverEntry); 980 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin); 981 982 DriverObject->DriverUnload = DriverUnload; 983 984 /* Register Object Manager Callbacks */ 985 CalloutData.ProcessCallout = Win32kProcessCallback; 986 CalloutData.ThreadCallout = Win32kThreadCallback; 987 // CalloutData.GlobalAtomTableCallout = NULL; 988 CalloutData.PowerEventCallout = IntHandlePowerEvent; 989 CalloutData.PowerStateCallout = IntHandlePowerState; 990 // CalloutData.JobCallout = NULL; 991 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch; 992 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen; 993 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose; 994 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose; 995 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete; 996 CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose; 997 // CalloutData.WindowStationCloseProcedure = NULL; 998 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete; 999 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse; 1000 // CalloutData.WindowStationOpenProcedure = NULL; 1001 1002 /* Register our per-process and per-thread structures. */ 1003 PsEstablishWin32Callouts(&CalloutData); 1004 1005 /* Register service hook callbacks */ 1006 #if DBG && defined(KDBG) 1007 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0); 1008 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0); 1009 #endif 1010 1011 /* Create the global USER heap */ 1012 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection, 1013 &GlobalUserHeapBase, 1014 1 * 1024 * 1024); /* FIXME: 1 MB for now... */ 1015 if (GlobalUserHeap == NULL) 1016 { 1017 DPRINT1("Failed to initialize the global heap!\n"); 1018 return STATUS_UNSUCCESSFUL; 1019 } 1020 1021 /* Init the global user lock */ 1022 ExInitializeResourceLite(&UserLock); 1023 1024 /* Lock while we use the heap (UserHeapAlloc asserts on this) */ 1025 UserEnterExclusive(); 1026 1027 /* Allocate global server info structure */ 1028 gpsi = UserHeapAlloc(sizeof(*gpsi)); 1029 UserLeave(); 1030 if (!gpsi) 1031 { 1032 DPRINT1("Failed allocate server info structure!\n"); 1033 return STATUS_UNSUCCESSFUL; 1034 } 1035 1036 RtlZeroMemory(gpsi, sizeof(*gpsi)); 1037 DPRINT("Global Server Data -> %p\n", gpsi); 1038 1039 NT_ROF(InitGdiHandleTable()); 1040 NT_ROF(InitPaletteImpl()); 1041 1042 /* Create stock objects, ie. precreated objects commonly 1043 used by win32 applications */ 1044 CreateStockObjects(); 1045 CreateSysColorObjects(); 1046 1047 NT_ROF(InitBrushImpl()); 1048 NT_ROF(InitPDEVImpl()); 1049 NT_ROF(InitLDEVImpl()); 1050 NT_ROF(InitDeviceImpl()); 1051 NT_ROF(InitDcImpl()); 1052 USERLOCK_AND_ROF(InitUserImpl()); 1053 NT_ROF(InitWindowStationImpl()); 1054 NT_ROF(InitDesktopImpl()); 1055 NT_ROF(InitInputImpl()); 1056 NT_ROF(InitKeyboardImpl()); 1057 NT_ROF(MsqInitializeImpl()); 1058 NT_ROF(InitTimerImpl()); 1059 NT_ROF(InitDCEImpl()); 1060 1061 return STATUS_SUCCESS; 1062 } 1063 1064 /* EOF */ 1065