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 /* Win: xxxCreateThreadInfo */ 456 NTSTATUS NTAPI 457 InitThreadCallback(PETHREAD Thread) 458 { 459 PEPROCESS Process; 460 PCLIENTINFO pci; 461 PTHREADINFO ptiCurrent; 462 int i; 463 NTSTATUS Status = STATUS_SUCCESS; 464 PTEB pTeb; 465 PRTL_USER_PROCESS_PARAMETERS ProcessParams; 466 PKL pDefKL; 467 468 Process = Thread->ThreadsProcess; 469 470 pTeb = NtCurrentTeb(); 471 ASSERT(pTeb); 472 473 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters; 474 475 /* Allocate a new Win32 thread info */ 476 Status = AllocW32Thread(Thread, &ptiCurrent); 477 if (!NT_SUCCESS(Status)) 478 { 479 ERR_CH(UserThread, "Failed to allocate pti for TID:0x%lx\n", 480 HandleToUlong(Thread->Cid.UniqueThread)); 481 return Status; 482 } 483 484 /* Initialize the THREADINFO */ 485 ptiCurrent->pEThread = Thread; 486 ptiCurrent->ppi = PsGetProcessWin32Process(Process); 487 IntReferenceProcessInfo(ptiCurrent->ppi); 488 pTeb->Win32ThreadInfo = ptiCurrent; 489 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo; 490 ptiCurrent->pcti = &ptiCurrent->cti; 491 492 /* Mark the process as having threads */ 493 ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED; 494 495 InitializeListHead(&ptiCurrent->WindowListHead); 496 InitializeListHead(&ptiCurrent->W32CallbackListHead); 497 InitializeListHead(&ptiCurrent->PostedMessagesListHead); 498 InitializeListHead(&ptiCurrent->SentMessagesListHead); 499 InitializeListHead(&ptiCurrent->PtiLink); 500 for (i = 0; i < NB_HOOKS; i++) 501 { 502 InitializeListHead(&ptiCurrent->aphkStart[i]); 503 } 504 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList; 505 ptiCurrent->ppi->ptiList = ptiCurrent; 506 ptiCurrent->ppi->cThreads++; 507 508 ptiCurrent->hEventQueueClient = NULL; 509 Status = ZwCreateEvent(&ptiCurrent->hEventQueueClient, EVENT_ALL_ACCESS, 510 NULL, SynchronizationEvent, FALSE); 511 if (!NT_SUCCESS(Status)) 512 { 513 ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status); 514 goto error; 515 } 516 Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0, 517 *ExEventObjectType, UserMode, 518 (PVOID*)&ptiCurrent->pEventQueueServer, NULL); 519 if (!NT_SUCCESS(Status)) 520 { 521 ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status); 522 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode); 523 ptiCurrent->hEventQueueClient = NULL; 524 goto error; 525 } 526 527 ptiCurrent->pcti->timeLastRead = EngGetTickCount32(); 528 529 ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent); 530 if (ptiCurrent->MessageQueue == NULL) 531 { 532 ERR_CH(UserThread, "Failed to allocate message loop\n"); 533 Status = STATUS_NO_MEMORY; 534 goto error; 535 } 536 537 pDefKL = W32kGetDefaultKeyLayout(); 538 UserAssignmentLock((PVOID*)&(ptiCurrent->KeyboardLayout), pDefKL); 539 540 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP; 541 542 // FIXME: Flag SYSTEM threads with... TIF_SYSTEMTHREAD !! 543 544 /* CSRSS threads have some special features */ 545 if (Process == gpepCSRSS || !gpepCSRSS) 546 ptiCurrent->TIF_flags = TIF_CSRSSTHREAD | TIF_DONTATTACHQUEUE; 547 548 /* Initialize the CLIENTINFO */ 549 pci = (PCLIENTINFO)pTeb->Win32ClientInfo; 550 RtlZeroMemory(pci, sizeof(*pci)); 551 pci->ppi = ptiCurrent->ppi; 552 pci->fsHooks = ptiCurrent->fsHooks; 553 pci->dwTIFlags = ptiCurrent->TIF_flags; 554 if (pDefKL) 555 { 556 pci->hKL = pDefKL->hkl; 557 pci->CodePage = pDefKL->CodePage; 558 } 559 560 /* Need to pass the user Startup Information to the current process. */ 561 if ( ProcessParams ) 562 { 563 if ( ptiCurrent->ppi->usi.cb == 0 ) // Not initialized yet. 564 { 565 if ( ProcessParams->WindowFlags != 0 ) // Need window flags set. 566 { 567 ptiCurrent->ppi->usi.cb = sizeof(USERSTARTUPINFO); 568 ptiCurrent->ppi->usi.dwX = ProcessParams->StartingX; 569 ptiCurrent->ppi->usi.dwY = ProcessParams->StartingY; 570 ptiCurrent->ppi->usi.dwXSize = ProcessParams->CountX; 571 ptiCurrent->ppi->usi.dwYSize = ProcessParams->CountY; 572 ptiCurrent->ppi->usi.dwFlags = ProcessParams->WindowFlags; 573 ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags; 574 } 575 } 576 } 577 578 /* 579 * Assign a default window station and desktop to the process. 580 * Do not try to open a desktop or window station before the very first 581 * (interactive) window station has been created by Winlogon. 582 */ 583 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) && 584 ptiCurrent->ppi->hdeskStartup == NULL && 585 InputWindowStation != NULL) 586 { 587 HWINSTA hWinSta = NULL; 588 HDESK hDesk = NULL; 589 UNICODE_STRING DesktopPath; 590 PDESKTOP pdesk; 591 592 /* 593 * Inherit the thread desktop and process window station (if not yet inherited) 594 * from the process startup info structure. See documentation of CreateProcess(). 595 */ 596 Status = STATUS_UNSUCCESSFUL; 597 if (ProcessParams && ProcessParams->DesktopInfo.Length > 0) 598 { 599 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo); 600 } 601 if (!NT_SUCCESS(Status)) 602 { 603 RtlInitUnicodeString(&DesktopPath, NULL); 604 } 605 606 Status = IntResolveDesktop(Process, 607 &DesktopPath, 608 !!(ProcessParams->WindowFlags & STARTF_INHERITDESKTOP), 609 &hWinSta, 610 &hDesk); 611 612 if (DesktopPath.Buffer) 613 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING); 614 615 if (!NT_SUCCESS(Status)) 616 { 617 ERR_CH(UserThread, "Failed to assign default desktop and winsta to process\n"); 618 goto error; 619 } 620 621 if (!UserSetProcessWindowStation(hWinSta)) 622 { 623 Status = STATUS_UNSUCCESSFUL; 624 ERR_CH(UserThread, "Failed to set initial process winsta\n"); 625 goto error; 626 } 627 628 /* Validate the new desktop */ 629 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk); 630 if (!NT_SUCCESS(Status)) 631 { 632 ERR_CH(UserThread, "Failed to validate initial desktop handle\n"); 633 goto error; 634 } 635 636 /* Store the parsed desktop as the initial desktop */ 637 ASSERT(ptiCurrent->ppi->hdeskStartup == NULL); 638 ASSERT(Process->UniqueProcessId != gpidLogon); 639 ptiCurrent->ppi->hdeskStartup = hDesk; 640 ptiCurrent->ppi->rpdeskStartup = pdesk; 641 } 642 643 if (ptiCurrent->ppi->hdeskStartup != NULL) 644 { 645 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE)) 646 { 647 ERR_CH(UserThread, "Failed to set thread desktop\n"); 648 Status = STATUS_UNSUCCESSFUL; 649 goto error; 650 } 651 } 652 653 /* Mark the thread as fully initialized */ 654 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED; 655 656 if (!(ptiCurrent->ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_APPSTARTING)) && 657 (gptiForeground && gptiForeground->ppi == ptiCurrent->ppi )) 658 { 659 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 660 } 661 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 662 663 /* Create the default input context */ 664 if (IS_IMM_MODE()) 665 { 666 (VOID)UserCreateInputContext(0); 667 } 668 669 /* Last things to do only if we are not a SYSTEM or CSRSS thread */ 670 if (!(ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) 671 { 672 /* Callback to User32 Client Thread Setup */ 673 TRACE_CH(UserThread, "Call co_IntClientThreadSetup...\n"); 674 Status = co_IntClientThreadSetup(); 675 if (!NT_SUCCESS(Status)) 676 { 677 ERR_CH(UserThread, "ClientThreadSetup failed with Status 0x%08lx\n", Status); 678 goto error; 679 } 680 TRACE_CH(UserThread, "co_IntClientThreadSetup succeeded!\n"); 681 } 682 else 683 { 684 TRACE_CH(UserThread, "co_IntClientThreadSetup cannot be called...\n"); 685 } 686 687 TRACE_CH(UserThread, "UserCreateW32Thread pti 0x%p\n", ptiCurrent); 688 return STATUS_SUCCESS; 689 690 error: 691 ERR_CH(UserThread, "InitThreadCallback failed! Freeing pti 0x%p for TID:0x%lx\n", 692 ptiCurrent, HandleToUlong(Thread->Cid.UniqueThread)); 693 ExitThreadCallback(Thread); 694 return Status; 695 } 696 697 VOID 698 UserDisplayNotifyShutdown(PPROCESSINFO ppiCurrent); 699 700 // Win: xxxDestroyThreadInfo 701 NTSTATUS 702 NTAPI 703 ExitThreadCallback(PETHREAD Thread) 704 { 705 PTHREADINFO *ppti; 706 PSINGLE_LIST_ENTRY psle; 707 PPROCESSINFO ppiCurrent; 708 PEPROCESS Process; 709 PTHREADINFO ptiCurrent; 710 PWINDOWLIST pwl, pwlNext; 711 712 Process = Thread->ThreadsProcess; 713 714 /* Get the Win32 Thread */ 715 ptiCurrent = PsGetThreadWin32Thread(Thread); 716 ASSERT(ptiCurrent); 717 718 TRACE_CH(UserThread, "Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread); 719 720 ptiCurrent->TIF_flags |= TIF_INCLEANUP; 721 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 722 723 ppiCurrent = ptiCurrent->ppi; 724 ASSERT(ppiCurrent); 725 726 IsRemoveAttachThread(ptiCurrent); 727 728 if (gpwlList) 729 { 730 for (pwl = gpwlList; pwl; pwl = pwlNext) 731 { 732 pwlNext = pwl->pNextList; 733 if (pwl->pti == ptiCurrent) 734 IntFreeHwndList(pwl); 735 } 736 } 737 738 ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE; 739 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 740 741 UserCloseClipboard(); 742 743 /* Decrement thread count and check if its 0 */ 744 ppiCurrent->cThreads--; 745 746 if (ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED) 747 { 748 /* Do now some process cleanup that requires a valid win32 thread */ 749 if (ptiCurrent->ppi->cThreads == 0) 750 { 751 /* Check if we have registered the user api hook */ 752 if (ptiCurrent->ppi == ppiUahServer) 753 { 754 /* Unregister the api hook */ 755 UserUnregisterUserApiHook(); 756 } 757 758 /* Notify logon application to restart shell if needed */ 759 if (ptiCurrent->pDeskInfo) 760 { 761 if (ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent) 762 { 763 DWORD ExitCode = PsGetProcessExitStatus(Process); 764 765 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode); 766 767 UserPostMessage(hwndSAS, 768 WM_LOGONNOTIFY, 769 LN_SHELL_EXITED, 770 ExitCode); 771 772 ptiCurrent->pDeskInfo->ppiShellProcess = NULL; 773 } 774 } 775 } 776 777 DceFreeThreadDCE(ptiCurrent); 778 DestroyTimersForThread(ptiCurrent); 779 KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE); 780 UnregisterThreadHotKeys(ptiCurrent); 781 782 if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent)) 783 { 784 DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent); 785 ASSERT(FALSE); 786 return STATUS_UNSUCCESSFUL; 787 } 788 UserAssignmentUnlock((PVOID*)&ptiCurrent->spDefaultImc); 789 790 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling && 791 ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED) 792 { 793 TRACE_CH(UserThread, "DestroyProcessClasses\n"); 794 /* no process windows should exist at this point, or the function will assert! */ 795 DestroyProcessClasses(ppiCurrent); 796 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED; 797 } 798 799 IntBlockInput(ptiCurrent, FALSE); 800 IntCleanupThreadCallbacks(ptiCurrent); 801 802 /* cleanup user object references stack */ 803 psle = PopEntryList(&ptiCurrent->ReferencesList); 804 while (psle) 805 { 806 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry); 807 TRACE_CH(UserThread, "thread clean: remove reference obj 0x%p\n",ref->obj); 808 UserDereferenceObject(ref->obj); 809 810 psle = PopEntryList(&ptiCurrent->ReferencesList); 811 } 812 } 813 814 if (ptiCurrent->cEnterCount) 815 { 816 KeSetKernelStackSwapEnable(TRUE); 817 ptiCurrent->cEnterCount = 0; 818 } 819 820 /* Find the THREADINFO in the PROCESSINFO's list */ 821 ppti = &ppiCurrent->ptiList; 822 while (*ppti != NULL && *ppti != ptiCurrent) 823 { 824 ppti = &((*ppti)->ptiSibling); 825 } 826 827 /* we must have found it */ 828 ASSERT(*ppti == ptiCurrent); 829 830 /* Remove it from the list */ 831 *ppti = ptiCurrent->ptiSibling; 832 833 if (!UserAssignmentUnlock((PVOID*)&(ptiCurrent->KeyboardLayout))) 834 ptiCurrent->pClientInfo->hKL = NULL; 835 836 if (gptiForeground == ptiCurrent) 837 { 838 // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0); 839 // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0); 840 841 gptiForeground = NULL; 842 } 843 844 /* Restore display mode when we are the last thread, and we changed the display mode */ 845 if (ppiCurrent->cThreads == 0) 846 UserDisplayNotifyShutdown(ppiCurrent); 847 848 849 // Fixes CORE-6384 & CORE-7030. 850 /* if (ptiLastInput == ptiCurrent) 851 { 852 if (!ppiCurrent->ptiList) 853 ptiLastInput = gptiForeground; 854 else 855 ptiLastInput = ppiCurrent->ptiList; 856 ERR_CH(UserThread, "DTI: ptiLastInput is Cleared!!\n"); 857 } 858 */ 859 TRACE_CH(UserThread, "Freeing pti 0x%p\n", ptiCurrent); 860 861 IntSetThreadDesktop(NULL, TRUE); 862 863 if (ptiCurrent->hEventQueueClient != NULL) 864 { 865 ObCloseHandle(ptiCurrent->hEventQueueClient, UserMode); 866 ObDereferenceObject(ptiCurrent->pEventQueueServer); 867 } 868 ptiCurrent->hEventQueueClient = NULL; 869 870 /* The thread is dying */ 871 PsSetThreadWin32Thread(Thread /*ptiCurrent->pEThread*/, NULL, ptiCurrent); 872 873 /* Dereference the THREADINFO */ 874 IntDereferenceThreadInfo(ptiCurrent); 875 876 return STATUS_SUCCESS; 877 } 878 879 NTSTATUS 880 APIENTRY 881 Win32kThreadCallback(PETHREAD Thread, 882 PSW32THREADCALLOUTTYPE Type) 883 { 884 NTSTATUS Status; 885 886 ASSERT(NtCurrentTeb()); 887 888 UserEnterExclusive(); 889 890 if (Type == PsW32ThreadCalloutInitialize) 891 { 892 ASSERT(PsGetThreadWin32Thread(Thread) == NULL); 893 Status = InitThreadCallback(Thread); 894 } 895 else // if (Type == PsW32ThreadCalloutExit) 896 { 897 ASSERT(PsGetThreadWin32Thread(Thread) != NULL); 898 Status = ExitThreadCallback(Thread); 899 } 900 901 UserLeave(); 902 903 return Status; 904 } 905 906 _Function_class_(DRIVER_UNLOAD) 907 VOID NTAPI 908 DriverUnload(IN PDRIVER_OBJECT DriverObject) 909 { 910 // TODO: Do more cleanup! 911 912 ResetCsrApiPort(); 913 ResetCsrProcess(); 914 } 915 916 // Return on failure 917 #define NT_ROF(x) \ 918 { \ 919 Status = (x); \ 920 if (!NT_SUCCESS(Status)) \ 921 { \ 922 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 923 return Status; \ 924 } \ 925 } 926 927 // Lock & return on failure 928 #define USERLOCK_AND_ROF(x) \ 929 { \ 930 UserEnterExclusive(); \ 931 Status = (x); \ 932 UserLeave(); \ 933 if (!NT_SUCCESS(Status)) \ 934 { \ 935 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ 936 return Status; \ 937 } \ 938 } 939 940 941 942 /* 943 * This definition doesn't work 944 */ 945 CODE_SEG("INIT") 946 NTSTATUS 947 APIENTRY 948 DriverEntry( 949 IN PDRIVER_OBJECT DriverObject, 950 IN PUNICODE_STRING RegistryPath) 951 { 952 NTSTATUS Status; 953 BOOLEAN Result; 954 WIN32_CALLOUTS_FPNS CalloutData = {0}; 955 PVOID GlobalUserHeapBase = NULL; 956 957 /* 958 * Register user mode call interface 959 * (system service table index = 1) 960 */ 961 Result = KeAddSystemServiceTable(Win32kSSDT, 962 NULL, 963 Win32kNumberOfSysCalls, 964 Win32kSSPT, 965 1); 966 if (Result == FALSE) 967 { 968 DPRINT1("Adding system services failed!\n"); 969 return STATUS_UNSUCCESSFUL; 970 } 971 972 hModuleWin = MmPageEntireDriver(DriverEntry); 973 DPRINT("Win32k hInstance 0x%p!\n", hModuleWin); 974 975 DriverObject->DriverUnload = DriverUnload; 976 977 /* Register Object Manager Callbacks */ 978 CalloutData.ProcessCallout = Win32kProcessCallback; 979 CalloutData.ThreadCallout = Win32kThreadCallback; 980 // CalloutData.GlobalAtomTableCallout = NULL; 981 // CalloutData.PowerEventCallout = NULL; 982 // CalloutData.PowerStateCallout = NULL; 983 // CalloutData.JobCallout = NULL; 984 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch; 985 CalloutData.DesktopOpenProcedure = IntDesktopObjectOpen; 986 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose; 987 CalloutData.DesktopCloseProcedure = IntDesktopObjectClose; 988 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete; 989 CalloutData.WindowStationOkToCloseProcedure = IntWinStaOkToClose; 990 // CalloutData.WindowStationCloseProcedure = NULL; 991 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete; 992 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse; 993 // CalloutData.WindowStationOpenProcedure = NULL; 994 995 /* Register our per-process and per-thread structures. */ 996 PsEstablishWin32Callouts(&CalloutData); 997 998 /* Register service hook callbacks */ 999 #if DBG && defined(KDBG) 1000 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0); 1001 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0); 1002 #endif 1003 1004 /* Create the global USER heap */ 1005 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection, 1006 &GlobalUserHeapBase, 1007 1 * 1024 * 1024); /* FIXME: 1 MB for now... */ 1008 if (GlobalUserHeap == NULL) 1009 { 1010 DPRINT1("Failed to initialize the global heap!\n"); 1011 return STATUS_UNSUCCESSFUL; 1012 } 1013 1014 /* Init the global user lock */ 1015 ExInitializeResourceLite(&UserLock); 1016 1017 /* Lock while we use the heap (UserHeapAlloc asserts on this) */ 1018 UserEnterExclusive(); 1019 1020 /* Allocate global server info structure */ 1021 gpsi = UserHeapAlloc(sizeof(*gpsi)); 1022 UserLeave(); 1023 if (!gpsi) 1024 { 1025 DPRINT1("Failed allocate server info structure!\n"); 1026 return STATUS_UNSUCCESSFUL; 1027 } 1028 1029 RtlZeroMemory(gpsi, sizeof(*gpsi)); 1030 DPRINT("Global Server Data -> %p\n", gpsi); 1031 1032 NT_ROF(InitGdiHandleTable()); 1033 NT_ROF(InitPaletteImpl()); 1034 1035 /* Create stock objects, ie. precreated objects commonly 1036 used by win32 applications */ 1037 CreateStockObjects(); 1038 CreateSysColorObjects(); 1039 1040 NT_ROF(InitBrushImpl()); 1041 NT_ROF(InitPDEVImpl()); 1042 NT_ROF(InitLDEVImpl()); 1043 NT_ROF(InitDeviceImpl()); 1044 NT_ROF(InitDcImpl()); 1045 USERLOCK_AND_ROF(InitUserImpl()); 1046 NT_ROF(InitWindowStationImpl()); 1047 NT_ROF(InitDesktopImpl()); 1048 NT_ROF(InitInputImpl()); 1049 NT_ROF(InitKeyboardImpl()); 1050 NT_ROF(MsqInitializeImpl()); 1051 NT_ROF(InitTimerImpl()); 1052 NT_ROF(InitDCEImpl()); 1053 1054 gusLanguageID = UserGetLanguageID(); 1055 1056 /* Initialize FreeType library */ 1057 if (!InitFontSupport()) 1058 { 1059 DPRINT1("Unable to initialize font support\n"); 1060 return Status; 1061 } 1062 1063 return STATUS_SUCCESS; 1064 } 1065 1066 /* EOF */ 1067