1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Desktops 5 * FILE: subsystems/win32/win32k/ntuser/desktop.c 6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <win32k.h> 12 DBG_DEFAULT_CHANNEL(UserDesktop); 13 14 #include <reactos/buildno.h> 15 16 static NTSTATUS 17 UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta); 18 19 static NTSTATUS 20 IntMapDesktopView(IN PDESKTOP pdesk); 21 22 static NTSTATUS 23 IntUnmapDesktopView(IN PDESKTOP pdesk); 24 25 static VOID 26 IntFreeDesktopHeap(IN PDESKTOP pdesk); 27 28 /* GLOBALS *******************************************************************/ 29 30 /* These can be changed via CSRSS startup, these are defaults */ 31 DWORD gdwDesktopSectionSize = 512; 32 DWORD gdwNOIOSectionSize = 128; // A guess, for one or more of the first three system desktops. 33 34 /* Currently active desktop */ 35 PDESKTOP gpdeskInputDesktop = NULL; 36 HDC ScreenDeviceContext = NULL; 37 PTHREADINFO gptiDesktopThread = NULL; 38 HCURSOR gDesktopCursor = NULL; 39 PKEVENT gpDesktopThreadStartedEvent = NULL; 40 41 /* OBJECT CALLBACKS **********************************************************/ 42 43 NTSTATUS 44 APIENTRY 45 IntDesktopObjectParse(IN PVOID ParseObject, 46 IN PVOID ObjectType, 47 IN OUT PACCESS_STATE AccessState, 48 IN KPROCESSOR_MODE AccessMode, 49 IN ULONG Attributes, 50 IN OUT PUNICODE_STRING CompleteName, 51 IN OUT PUNICODE_STRING RemainingName, 52 IN OUT PVOID Context OPTIONAL, 53 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 54 OUT PVOID *Object) 55 { 56 NTSTATUS Status; 57 PDESKTOP Desktop; 58 OBJECT_ATTRIBUTES ObjectAttributes; 59 PLIST_ENTRY NextEntry, ListHead; 60 PWINSTATION_OBJECT WinStaObject = (PWINSTATION_OBJECT)ParseObject; 61 UNICODE_STRING DesktopName; 62 PBOOLEAN pContext = (PBOOLEAN) Context; 63 64 if (pContext) 65 *pContext = FALSE; 66 67 /* Set the list pointers and loop the window station */ 68 ListHead = &WinStaObject->DesktopListHead; 69 NextEntry = ListHead->Flink; 70 while (NextEntry != ListHead) 71 { 72 /* Get the current desktop */ 73 Desktop = CONTAINING_RECORD(NextEntry, DESKTOP, ListEntry); 74 75 /* Get the desktop name */ 76 ASSERT(Desktop->pDeskInfo != NULL); 77 RtlInitUnicodeString(&DesktopName, Desktop->pDeskInfo->szDesktopName); 78 79 /* Compare the name */ 80 if (RtlEqualUnicodeString(RemainingName, 81 &DesktopName, 82 (Attributes & OBJ_CASE_INSENSITIVE) != 0)) 83 { 84 /* We found a match. Did this come from a create? */ 85 if (Context) 86 { 87 /* Unless OPEN_IF was given, fail with an error */ 88 if (!(Attributes & OBJ_OPENIF)) 89 { 90 /* Name collision */ 91 return STATUS_OBJECT_NAME_COLLISION; 92 } 93 else 94 { 95 /* Otherwise, return with a warning only */ 96 Status = STATUS_OBJECT_NAME_EXISTS; 97 } 98 } 99 else 100 { 101 /* This was a real open, so this is OK */ 102 Status = STATUS_SUCCESS; 103 } 104 105 /* Reference the desktop and return it */ 106 ObReferenceObject(Desktop); 107 *Object = Desktop; 108 return Status; 109 } 110 111 /* Go to the next desktop */ 112 NextEntry = NextEntry->Flink; 113 } 114 115 /* If we got here but this isn't a create, just fail */ 116 if (!Context) return STATUS_OBJECT_NAME_NOT_FOUND; 117 118 /* Create the desktop object */ 119 InitializeObjectAttributes(&ObjectAttributes, RemainingName, 0, NULL, NULL); 120 Status = ObCreateObject(KernelMode, 121 ExDesktopObjectType, 122 &ObjectAttributes, 123 KernelMode, 124 NULL, 125 sizeof(DESKTOP), 126 0, 127 0, 128 (PVOID*)&Desktop); 129 if (!NT_SUCCESS(Status)) return Status; 130 131 /* Initialize the desktop */ 132 Status = UserInitializeDesktop(Desktop, RemainingName, WinStaObject); 133 if (!NT_SUCCESS(Status)) 134 { 135 ObDereferenceObject(Desktop); 136 return Status; 137 } 138 139 /* Set the desktop object and return success */ 140 *Object = Desktop; 141 *pContext = TRUE; 142 return STATUS_SUCCESS; 143 } 144 145 NTSTATUS 146 NTAPI 147 IntDesktopObjectDelete( 148 _In_ PVOID Parameters) 149 { 150 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters; 151 PDESKTOP pdesk = (PDESKTOP)DeleteParameters->Object; 152 153 TRACE("Deleting desktop object 0x%p\n", pdesk); 154 155 if (pdesk->pDeskInfo && 156 pdesk->pDeskInfo->spwnd) 157 { 158 ASSERT(pdesk->pDeskInfo->spwnd->spwndChild == NULL); 159 co_UserDestroyWindow(pdesk->pDeskInfo->spwnd); 160 } 161 162 if (pdesk->spwndMessage) 163 co_UserDestroyWindow(pdesk->spwndMessage); 164 165 /* Remove the desktop from the window station's list of associcated desktops */ 166 RemoveEntryList(&pdesk->ListEntry); 167 168 /* Free the heap */ 169 IntFreeDesktopHeap(pdesk); 170 171 ObDereferenceObject(pdesk->rpwinstaParent); 172 173 return STATUS_SUCCESS; 174 } 175 176 NTSTATUS 177 NTAPI 178 IntDesktopOkToClose( 179 _In_ PVOID Parameters) 180 { 181 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters; 182 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 183 184 if (pti == NULL) 185 { 186 /* This happens when we leak desktop handles */ 187 return STATUS_SUCCESS; 188 } 189 190 /* Do not allow the current desktop or the initial desktop to be closed */ 191 if (OkToCloseParameters->Handle == pti->ppi->hdeskStartup || 192 OkToCloseParameters->Handle == pti->hdesk) 193 { 194 return STATUS_ACCESS_DENIED; 195 } 196 197 return STATUS_SUCCESS; 198 } 199 200 NTSTATUS 201 NTAPI 202 IntDesktopObjectOpen( 203 _In_ PVOID Parameters) 204 { 205 NTSTATUS Ret; 206 PWIN32_OPENMETHOD_PARAMETERS OpenParameters = Parameters; 207 PPROCESSINFO ppi = PsGetProcessWin32Process(OpenParameters->Process); 208 if (ppi == NULL) 209 return STATUS_SUCCESS; 210 211 UserEnterExclusive(); 212 Ret = IntMapDesktopView((PDESKTOP)OpenParameters->Object); 213 UserLeave(); 214 return Ret; 215 } 216 217 NTSTATUS 218 NTAPI 219 IntDesktopObjectClose( 220 _In_ PVOID Parameters) 221 { 222 NTSTATUS Ret; 223 PWIN32_CLOSEMETHOD_PARAMETERS CloseParameters = Parameters; 224 PPROCESSINFO ppi = PsGetProcessWin32Process(CloseParameters->Process); 225 if (ppi == NULL) 226 { 227 /* This happens when the process leaks desktop handles. 228 * At this point the PPROCESSINFO is already destroyed */ 229 return STATUS_SUCCESS; 230 } 231 232 UserEnterExclusive(); 233 Ret = IntUnmapDesktopView((PDESKTOP)CloseParameters->Object); 234 UserLeave(); 235 return Ret; 236 } 237 238 239 /* PRIVATE FUNCTIONS **********************************************************/ 240 241 CODE_SEG("INIT") 242 NTSTATUS 243 NTAPI 244 InitDesktopImpl(VOID) 245 { 246 GENERIC_MAPPING IntDesktopMapping = { DESKTOP_READ, 247 DESKTOP_WRITE, 248 DESKTOP_EXECUTE, 249 DESKTOP_ALL_ACCESS}; 250 251 /* Set Desktop Object Attributes */ 252 ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP); 253 ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping; 254 ExDesktopObjectType->TypeInfo.ValidAccessMask = DESKTOP_ALL_ACCESS; 255 256 /* Allocate memory for the event structure */ 257 gpDesktopThreadStartedEvent = ExAllocatePoolWithTag(NonPagedPool, 258 sizeof(KEVENT), 259 USERTAG_EVENT); 260 if (!gpDesktopThreadStartedEvent) 261 { 262 ERR("Failed to allocate event!\n"); 263 return STATUS_NO_MEMORY; 264 } 265 266 /* Initialize the kernel event */ 267 KeInitializeEvent(gpDesktopThreadStartedEvent, 268 SynchronizationEvent, 269 FALSE); 270 271 return STATUS_SUCCESS; 272 } 273 274 static NTSTATUS 275 GetSystemVersionString(OUT PWSTR pwszzVersion, 276 IN SIZE_T cchDest, 277 IN BOOLEAN InSafeMode, 278 IN BOOLEAN AppendNtSystemRoot) 279 { 280 NTSTATUS Status; 281 282 RTL_OSVERSIONINFOEXW VerInfo; 283 UNICODE_STRING BuildLabString; 284 UNICODE_STRING CSDVersionString; 285 RTL_QUERY_REGISTRY_TABLE VersionConfigurationTable[] = 286 { 287 { 288 NULL, 289 RTL_QUERY_REGISTRY_DIRECT, 290 L"BuildLab", 291 &BuildLabString, 292 REG_NONE, NULL, 0 293 }, 294 { 295 NULL, 296 RTL_QUERY_REGISTRY_DIRECT, 297 L"CSDVersion", 298 &CSDVersionString, 299 REG_NONE, NULL, 0 300 }, 301 302 {0} 303 }; 304 305 WCHAR BuildLabBuffer[256]; 306 WCHAR VersionBuffer[256]; 307 PWCHAR EndBuffer; 308 309 VerInfo.dwOSVersionInfoSize = sizeof(VerInfo); 310 311 /* 312 * This call is uniquely used to retrieve the current CSD numbers. 313 * All the rest (major, minor, ...) is either retrieved from the 314 * SharedUserData structure, or from the registry. 315 */ 316 RtlGetVersion((PRTL_OSVERSIONINFOW)&VerInfo); 317 318 /* 319 * - Retrieve the BuildLab string from the registry (set by the kernel). 320 * - In kernel-mode, szCSDVersion is not initialized. Initialize it 321 * and query its value from the registry. 322 */ 323 RtlZeroMemory(BuildLabBuffer, sizeof(BuildLabBuffer)); 324 RtlInitEmptyUnicodeString(&BuildLabString, 325 BuildLabBuffer, 326 sizeof(BuildLabBuffer)); 327 RtlZeroMemory(VerInfo.szCSDVersion, sizeof(VerInfo.szCSDVersion)); 328 RtlInitEmptyUnicodeString(&CSDVersionString, 329 VerInfo.szCSDVersion, 330 sizeof(VerInfo.szCSDVersion)); 331 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, 332 L"", 333 VersionConfigurationTable, 334 NULL, 335 NULL); 336 if (!NT_SUCCESS(Status)) 337 { 338 /* Indicate nothing is there */ 339 BuildLabString.Length = 0; 340 CSDVersionString.Length = 0; 341 } 342 /* NULL-terminate the strings */ 343 BuildLabString.Buffer[BuildLabString.Length / sizeof(WCHAR)] = UNICODE_NULL; 344 CSDVersionString.Buffer[CSDVersionString.Length / sizeof(WCHAR)] = UNICODE_NULL; 345 346 EndBuffer = VersionBuffer; 347 if ( /* VerInfo.wServicePackMajor != 0 && */ CSDVersionString.Length) 348 { 349 /* Print the version string */ 350 Status = RtlStringCbPrintfExW(VersionBuffer, 351 sizeof(VersionBuffer), 352 &EndBuffer, 353 NULL, 354 0, 355 L": %wZ", 356 &CSDVersionString); 357 if (!NT_SUCCESS(Status)) 358 { 359 /* No version, NULL-terminate the string */ 360 *EndBuffer = UNICODE_NULL; 361 } 362 } 363 else 364 { 365 /* No version, NULL-terminate the string */ 366 *EndBuffer = UNICODE_NULL; 367 } 368 369 if (InSafeMode) 370 { 371 /* String for Safe Mode */ 372 Status = RtlStringCchPrintfW(pwszzVersion, 373 cchDest, 374 L"ReactOS Version %S %wZ (NT %u.%u Build %u%s)\n", 375 KERNEL_VERSION_STR, 376 &BuildLabString, 377 SharedUserData->NtMajorVersion, 378 SharedUserData->NtMinorVersion, 379 (VerInfo.dwBuildNumber & 0xFFFF), 380 VersionBuffer); 381 382 if (AppendNtSystemRoot && NT_SUCCESS(Status)) 383 { 384 Status = RtlStringCbPrintfW(VersionBuffer, 385 sizeof(VersionBuffer), 386 L" - %s\n", 387 SharedUserData->NtSystemRoot); 388 if (NT_SUCCESS(Status)) 389 { 390 /* Replace the last newline by a NULL, before concatenating */ 391 EndBuffer = wcsrchr(pwszzVersion, L'\n'); 392 if (EndBuffer) *EndBuffer = UNICODE_NULL; 393 394 /* The concatenated string has a terminating newline */ 395 Status = RtlStringCchCatW(pwszzVersion, 396 cchDest, 397 VersionBuffer); 398 if (!NT_SUCCESS(Status)) 399 { 400 /* Concatenation failed, put back the newline */ 401 if (EndBuffer) *EndBuffer = L'\n'; 402 } 403 } 404 405 /* Override any failures as the NtSystemRoot string is optional */ 406 Status = STATUS_SUCCESS; 407 } 408 } 409 else 410 { 411 /* Multi-string for Normal Mode */ 412 Status = RtlStringCchPrintfW(pwszzVersion, 413 cchDest, 414 L"ReactOS Version %S\n" 415 L"Build %wZ\n" 416 L"Reporting NT %u.%u (Build %u%s)\n", 417 KERNEL_VERSION_STR, 418 &BuildLabString, 419 SharedUserData->NtMajorVersion, 420 SharedUserData->NtMinorVersion, 421 (VerInfo.dwBuildNumber & 0xFFFF), 422 VersionBuffer); 423 424 if (AppendNtSystemRoot && NT_SUCCESS(Status)) 425 { 426 Status = RtlStringCbPrintfW(VersionBuffer, 427 sizeof(VersionBuffer), 428 L"%s\n", 429 SharedUserData->NtSystemRoot); 430 if (NT_SUCCESS(Status)) 431 { 432 Status = RtlStringCchCatW(pwszzVersion, 433 cchDest, 434 VersionBuffer); 435 } 436 437 /* Override any failures as the NtSystemRoot string is optional */ 438 Status = STATUS_SUCCESS; 439 } 440 } 441 442 if (!NT_SUCCESS(Status)) 443 { 444 /* Fall-back string */ 445 Status = RtlStringCchPrintfW(pwszzVersion, 446 cchDest, 447 L"ReactOS Version %S %wZ\n", 448 KERNEL_VERSION_STR, 449 &BuildLabString); 450 if (!NT_SUCCESS(Status)) 451 { 452 /* General failure, NULL-terminate the string */ 453 pwszzVersion[0] = UNICODE_NULL; 454 } 455 } 456 457 /* 458 * Convert the string separators (newlines) into NULLs 459 * and NULL-terminate the multi-string. 460 */ 461 while (*pwszzVersion) 462 { 463 EndBuffer = wcschr(pwszzVersion, L'\n'); 464 if (!EndBuffer) break; 465 pwszzVersion = EndBuffer; 466 467 *pwszzVersion++ = UNICODE_NULL; 468 } 469 *pwszzVersion = UNICODE_NULL; 470 471 return Status; 472 } 473 474 475 /* 476 * IntResolveDesktop 477 * 478 * The IntResolveDesktop function attempts to retrieve valid handles to 479 * a desktop and a window station suitable for the specified process. 480 * The specified desktop path string is used only as a hint for the resolution. 481 * 482 * - If the process is already assigned to a window station and a desktop, 483 * handles to these objects are returned directly regardless of the specified 484 * desktop path string. This is what happens when this function is called for 485 * a process that has been already started and connected to the Win32 USER. 486 * 487 * - If the process is being connected to the Win32 USER, or is in a state 488 * where a window station is assigned to it but no desktop yet, the desktop 489 * path string is used as a hint for the resolution. 490 * A specified window station (if any, otherwise "WinSta0" is used as default) 491 * is tested for existence and accessibility. If the checks are OK a handle 492 * to it is returned. Otherwise we either fail (the window station does not 493 * exist) or, in case a default window station was used, we attempt to open 494 * or create a non-interactive Service-0xXXXX-YYYY$ window station. This is 495 * typically what happens when a non-interactive process is started while 496 * the WinSta0 window station was used as the default one. 497 * A specified desktop (if any, otherwise "Default" is used as default) 498 * is then tested for existence on the opened window station. 499 * 500 * - Rules for the choice of the default window station, when none is specified 501 * in the desktop path: 502 * 503 * 1. By default, a SYSTEM process connects to a non-interactive window 504 * station, either the Service-0x0-3e7$ (from the SYSTEM LUID) station, 505 * or one that has been inherited and that is non-interactive. 506 * Only when the interactive window station WinSta0 is specified that 507 * the process can connect to it (e.g. the case of interactive services). 508 * 509 * 2. An interactive process, i.e. a process whose LUID is the same as the 510 * one assigned to WinSta0 by Winlogon on user logon, connects by default 511 * to the WinSta0 window station, unless it has inherited from another 512 * interactive window station (which must be... none other than WinSta0). 513 * 514 * 3. A non-interactive (but not SYSTEM) process connects by default to 515 * a non-interactive Service-0xXXXX-YYYY$ window station (whose name 516 * is derived from the process' LUID), or to another non-interactive 517 * window station that has been inherited. 518 * Otherwise it may be able connect to the interactive WinSta0 only if 519 * it has explicit access rights to it. 520 * 521 * Parameters 522 * Process 523 * The user process object. 524 * 525 * DesktopPath 526 * The desktop path string used as a hint for desktop resolution. 527 * 528 * bInherit 529 * Whether or not the returned handles are inheritable. 530 * 531 * phWinSta 532 * Pointer to a window station handle. 533 * 534 * phDesktop 535 * Pointer to a desktop handle. 536 * 537 * Return Value 538 * Status code. 539 */ 540 541 NTSTATUS 542 FASTCALL 543 IntResolveDesktop( 544 IN PEPROCESS Process, 545 IN PUNICODE_STRING DesktopPath, 546 IN BOOL bInherit, 547 OUT HWINSTA* phWinSta, 548 OUT HDESK* phDesktop) 549 { 550 NTSTATUS Status; 551 HWINSTA hWinSta = NULL, hWinStaDup = NULL; 552 HDESK hDesktop = NULL, hDesktopDup = NULL; 553 PPROCESSINFO ppi; 554 HANDLE hProcess = NULL; 555 LUID ProcessLuid; 556 USHORT StrSize; 557 SIZE_T MemSize; 558 POBJECT_ATTRIBUTES ObjectAttributes = NULL; 559 PUNICODE_STRING ObjectName; 560 UNICODE_STRING WinStaName, DesktopName; 561 const UNICODE_STRING WinSta0Name = RTL_CONSTANT_STRING(L"WinSta0"); 562 PWINSTATION_OBJECT WinStaObject; 563 HWINSTA hTempWinSta = NULL; 564 BOOLEAN bUseDefaultWinSta = FALSE; 565 BOOLEAN bInteractive = FALSE; 566 BOOLEAN bAccessAllowed = FALSE; 567 568 ASSERT(UserIsEnteredExclusive()); 569 570 ASSERT(phWinSta); 571 ASSERT(phDesktop); 572 ASSERT(DesktopPath); 573 574 *phWinSta = NULL; 575 *phDesktop = NULL; 576 577 ppi = PsGetProcessWin32Process(Process); 578 /* ppi is typically NULL for console applications that connect to Win32 USER */ 579 if (!ppi) TRACE("IntResolveDesktop: ppi is NULL!\n"); 580 581 if (ppi && ppi->hwinsta != NULL && ppi->hdeskStartup != NULL) 582 { 583 /* 584 * If this process is the current one, just return the cached handles. 585 * Otherwise, open the window station and desktop objects. 586 */ 587 if (Process == PsGetCurrentProcess()) 588 { 589 hWinSta = ppi->hwinsta; 590 hDesktop = ppi->hdeskStartup; 591 } 592 else 593 { 594 Status = ObOpenObjectByPointer(ppi->prpwinsta, 595 0, 596 NULL, 597 MAXIMUM_ALLOWED, 598 ExWindowStationObjectType, 599 UserMode, 600 (PHANDLE)&hWinSta); 601 if (!NT_SUCCESS(Status)) 602 { 603 ERR("IntResolveDesktop: Could not reference window station 0x%p\n", ppi->prpwinsta); 604 SetLastNtError(Status); 605 return Status; 606 } 607 608 Status = ObOpenObjectByPointer(ppi->rpdeskStartup, 609 0, 610 NULL, 611 MAXIMUM_ALLOWED, 612 ExDesktopObjectType, 613 UserMode, 614 (PHANDLE)&hDesktop); 615 if (!NT_SUCCESS(Status)) 616 { 617 ERR("IntResolveDesktop: Could not reference desktop 0x%p\n", ppi->rpdeskStartup); 618 ObCloseHandle(hWinSta, UserMode); 619 SetLastNtError(Status); 620 return Status; 621 } 622 } 623 624 *phWinSta = hWinSta; 625 *phDesktop = hDesktop; 626 return STATUS_SUCCESS; 627 } 628 629 /* We will by default use the default window station and desktop */ 630 RtlInitEmptyUnicodeString(&WinStaName, NULL, 0); 631 RtlInitEmptyUnicodeString(&DesktopName, NULL, 0); 632 633 /* 634 * Parse the desktop path string which can be of the form "WinSta\Desktop" 635 * or just "Desktop". In the latter case we use the default window station 636 * on which the process is attached to (or if none, "WinSta0"). 637 */ 638 if (DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR)) 639 { 640 DesktopName = *DesktopPath; 641 642 /* Find the separator */ 643 while (DesktopName.Length > 0 && *DesktopName.Buffer && 644 *DesktopName.Buffer != OBJ_NAME_PATH_SEPARATOR) 645 { 646 DesktopName.Buffer++; 647 DesktopName.Length -= sizeof(WCHAR); 648 DesktopName.MaximumLength -= sizeof(WCHAR); 649 } 650 if (DesktopName.Length > 0) 651 { 652 RtlInitEmptyUnicodeString(&WinStaName, DesktopPath->Buffer, 653 DesktopPath->Length - DesktopName.Length); 654 // (USHORT)((ULONG_PTR)DesktopName.Buffer - (ULONG_PTR)DesktopPath->Buffer); 655 WinStaName.Length = WinStaName.MaximumLength; 656 657 /* Skip the separator */ 658 DesktopName.Buffer++; 659 DesktopName.Length -= sizeof(WCHAR); 660 DesktopName.MaximumLength -= sizeof(WCHAR); 661 } 662 else 663 { 664 RtlInitEmptyUnicodeString(&WinStaName, NULL, 0); 665 DesktopName = *DesktopPath; 666 } 667 } 668 669 TRACE("IntResolveDesktop: WinStaName:'%wZ' ; DesktopName:'%wZ'\n", &WinStaName, &DesktopName); 670 671 /* Retrieve the process LUID */ 672 Status = GetProcessLuid(NULL, Process, &ProcessLuid); 673 if (!NT_SUCCESS(Status)) 674 { 675 ERR("IntResolveDesktop: Failed to retrieve the process LUID, Status 0x%08lx\n", Status); 676 SetLastNtError(Status); 677 return Status; 678 } 679 680 /* 681 * If this process is not the current one, obtain a temporary handle 682 * to it so that we can perform handles duplication later. 683 */ 684 if (Process != PsGetCurrentProcess()) 685 { 686 Status = ObOpenObjectByPointer(Process, 687 OBJ_KERNEL_HANDLE, 688 NULL, 689 0, 690 *PsProcessType, 691 KernelMode, 692 &hProcess); 693 if (!NT_SUCCESS(Status)) 694 { 695 ERR("IntResolveDesktop: Failed to obtain a handle to process 0x%p, Status 0x%08lx\n", Process, Status); 696 SetLastNtError(Status); 697 return Status; 698 } 699 ASSERT(hProcess); 700 } 701 702 /* 703 * If no window station has been specified, search the process handle table 704 * for inherited window station handles, otherwise use a default one. 705 */ 706 if (WinStaName.Buffer == NULL) 707 { 708 /* 709 * We want to find a suitable default window station. 710 * For applications that can be interactive, i.e. that have allowed 711 * access to the single interactive window station on the system, 712 * the default window station is 'WinSta0'. 713 * For applications that cannot be interactive, i.e. that do not have 714 * access to 'WinSta0' (e.g. non-interactive services), the default 715 * window station is 'Service-0xXXXX-YYYY$' (created if needed). 716 * Precedence will however be taken by any inherited window station 717 * that possesses the required interactivity property. 718 */ 719 bUseDefaultWinSta = TRUE; 720 721 /* 722 * Use the default 'WinSta0' window station. Whether we should 723 * use 'Service-0xXXXX-YYYY$' instead will be determined later. 724 */ 725 // RtlInitUnicodeString(&WinStaName, L"WinSta0"); 726 WinStaName = WinSta0Name; 727 728 if (ObFindHandleForObject(Process, 729 NULL, 730 ExWindowStationObjectType, 731 NULL, 732 (PHANDLE)&hWinSta)) 733 { 734 TRACE("IntResolveDesktop: Inherited window station is: 0x%p\n", hWinSta); 735 } 736 } 737 738 /* 739 * If no desktop has been specified, search the process handle table 740 * for inherited desktop handles, otherwise use the Default desktop. 741 * Note that the inherited desktop that we may use, may not belong 742 * to the window station we will connect to. 743 */ 744 if (DesktopName.Buffer == NULL) 745 { 746 /* Use a default desktop name */ 747 RtlInitUnicodeString(&DesktopName, L"Default"); 748 749 if (ObFindHandleForObject(Process, 750 NULL, 751 ExDesktopObjectType, 752 NULL, 753 (PHANDLE)&hDesktop)) 754 { 755 TRACE("IntResolveDesktop: Inherited desktop is: 0x%p\n", hDesktop); 756 } 757 } 758 759 760 /* 761 * We are going to open either a window station or a desktop. 762 * Even if this operation is done from kernel-mode, we should 763 * "emulate" an opening from user-mode (i.e. using an ObjectAttributes 764 * allocated in user-mode, with AccessMode == UserMode) for the 765 * Object Manager to perform proper access validation to the 766 * window station or desktop. 767 */ 768 769 /* 770 * Estimate the maximum size needed for the window station name 771 * and desktop name to be given to ObjectAttributes->ObjectName. 772 */ 773 StrSize = 0; 774 775 /* Window station name */ 776 MemSize = _scwprintf(L"Service-0x%x-%x$", MAXULONG, MAXULONG) * sizeof(WCHAR); 777 MemSize = gustrWindowStationsDir.Length + sizeof(OBJ_NAME_PATH_SEPARATOR) 778 + max(WinStaName.Length, MemSize) + sizeof(UNICODE_NULL); 779 if (MemSize > MAXUSHORT) 780 { 781 ERR("IntResolveDesktop: Window station name length is too long.\n"); 782 Status = STATUS_NAME_TOO_LONG; 783 goto Quit; 784 } 785 StrSize = max(StrSize, (USHORT)MemSize); 786 787 /* Desktop name */ 788 MemSize = max(DesktopName.Length + sizeof(UNICODE_NULL), sizeof(L"Default")); 789 StrSize = max(StrSize, (USHORT)MemSize); 790 791 /* Size for the OBJECT_ATTRIBUTES */ 792 MemSize = ALIGN_UP(sizeof(OBJECT_ATTRIBUTES), sizeof(PVOID)); 793 794 /* Add the string size */ 795 MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID)); 796 MemSize += StrSize; 797 798 /* Allocate the memory in user-mode */ 799 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), 800 (PVOID*)&ObjectAttributes, 801 0, 802 &MemSize, 803 MEM_COMMIT, 804 PAGE_READWRITE); 805 if (!NT_SUCCESS(Status)) 806 { 807 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status); 808 goto Quit; 809 } 810 811 ObjectName = (PUNICODE_STRING)((ULONG_PTR)ObjectAttributes + 812 ALIGN_UP(sizeof(OBJECT_ATTRIBUTES), sizeof(PVOID))); 813 814 RtlInitEmptyUnicodeString(ObjectName, 815 (PWCHAR)((ULONG_PTR)ObjectName + 816 ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))), 817 StrSize); 818 819 820 /* If we got an inherited window station handle, duplicate and use it */ 821 if (hWinSta) 822 { 823 ASSERT(bUseDefaultWinSta); 824 825 /* Duplicate the handle if it belongs to another process than the current one */ 826 if (Process != PsGetCurrentProcess()) 827 { 828 ASSERT(hProcess); 829 Status = ZwDuplicateObject(hProcess, 830 hWinSta, 831 ZwCurrentProcess(), 832 (PHANDLE)&hWinStaDup, 833 0, 834 0, 835 DUPLICATE_SAME_ACCESS); 836 if (!NT_SUCCESS(Status)) 837 { 838 ERR("IntResolveDesktop: Failed to duplicate the window station handle, Status 0x%08lx\n", Status); 839 /* We will use a default window station */ 840 hWinSta = NULL; 841 } 842 else 843 { 844 hWinSta = hWinStaDup; 845 } 846 } 847 } 848 849 /* 850 * If we have an inherited window station, check whether 851 * it is interactive and remember that for later. 852 */ 853 if (hWinSta) 854 { 855 ASSERT(bUseDefaultWinSta); 856 857 /* Reference the inherited window station */ 858 Status = ObReferenceObjectByHandle(hWinSta, 859 0, 860 ExWindowStationObjectType, 861 KernelMode, 862 (PVOID*)&WinStaObject, 863 NULL); 864 if (!NT_SUCCESS(Status)) 865 { 866 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status); 867 /* We will use a default window station */ 868 if (hWinStaDup) 869 { 870 ASSERT(hWinSta == hWinStaDup); 871 ObCloseHandle(hWinStaDup, UserMode); 872 hWinStaDup = NULL; 873 } 874 hWinSta = NULL; 875 } 876 else 877 { 878 ERR("Process LUID is: 0x%x-%x, inherited window station LUID is: 0x%x-%x\n", 879 ProcessLuid.HighPart, ProcessLuid.LowPart, 880 WinStaObject->luidUser.HighPart, WinStaObject->luidUser.LowPart); 881 882 /* Check whether this window station is interactive, and remember it for later */ 883 bInteractive = !(WinStaObject->Flags & WSS_NOIO); 884 885 /* Dereference the window station */ 886 ObDereferenceObject(WinStaObject); 887 } 888 } 889 890 /* Build a valid window station name */ 891 Status = RtlStringCbPrintfW(ObjectName->Buffer, 892 ObjectName->MaximumLength, 893 L"%wZ\\%wZ", 894 &gustrWindowStationsDir, 895 &WinStaName); 896 if (!NT_SUCCESS(Status)) 897 { 898 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status); 899 goto Quit; 900 } 901 ObjectName->Length = (USHORT)(wcslen(ObjectName->Buffer) * sizeof(WCHAR)); 902 903 TRACE("Parsed initial window station: '%wZ'\n", ObjectName); 904 905 /* Try to open the window station */ 906 InitializeObjectAttributes(ObjectAttributes, 907 ObjectName, 908 OBJ_CASE_INSENSITIVE, 909 NULL, 910 NULL); 911 if (bInherit) 912 ObjectAttributes->Attributes |= OBJ_INHERIT; 913 914 Status = ObOpenObjectByName(ObjectAttributes, 915 ExWindowStationObjectType, 916 UserMode, 917 NULL, 918 WINSTA_ACCESS_ALL, 919 NULL, 920 (PHANDLE)&hTempWinSta); 921 if (!NT_SUCCESS(Status)) 922 { 923 ERR("Failed to open the window station '%wZ', Status 0x%08lx\n", ObjectName, Status); 924 } 925 else 926 { 927 // 928 // FIXME TODO: Perform a window station access check!! 929 // If we fail AND bUseDefaultWinSta == FALSE we just quit. 930 // 931 932 /* 933 * Check whether we are opening the (single) interactive 934 * window station, and if so, perform an access check. 935 */ 936 /* Check whether we are allowed to perform interactions */ 937 if (RtlEqualUnicodeString(&WinStaName, &WinSta0Name, TRUE)) 938 { 939 LUID SystemLuid = SYSTEM_LUID; 940 941 /* Interactive window station: check for user LUID */ 942 WinStaObject = InputWindowStation; 943 944 Status = STATUS_ACCESS_DENIED; 945 946 // TODO: Check also that we compare wrt. window station WinSta0 947 // which is the only one that can be interactive on the system. 948 if (((!bUseDefaultWinSta || bInherit) && RtlEqualLuid(&ProcessLuid, &SystemLuid)) || 949 RtlEqualLuid(&ProcessLuid, &WinStaObject->luidUser)) 950 { 951 /* We are interactive on this window station */ 952 bAccessAllowed = TRUE; 953 Status = STATUS_SUCCESS; 954 } 955 } 956 else 957 { 958 /* Non-interactive window station: we have access since we were able to open it */ 959 bAccessAllowed = TRUE; 960 Status = STATUS_SUCCESS; 961 } 962 } 963 964 /* If we failed, bail out if we were not trying to open the default window station */ 965 if (!NT_SUCCESS(Status) && !bUseDefaultWinSta) // if (!bAccessAllowed) 966 goto Quit; 967 968 if (/* bAccessAllowed && */ bInteractive || !bAccessAllowed) 969 { 970 /* 971 * Close WinSta0 if the inherited window station is interactive so that 972 * we can use it, or we do not have access to the interactive WinSta0. 973 */ 974 ObCloseHandle(hTempWinSta, UserMode); 975 hTempWinSta = NULL; 976 } 977 if (bInteractive == bAccessAllowed) 978 { 979 /* Keep using the inherited window station */ 980 NOTHING; 981 } 982 else // if (bInteractive != bAccessAllowed) 983 { 984 /* 985 * Close the inherited window station, we will either keep using 986 * the interactive WinSta0, or use Service-0xXXXX-YYYY$. 987 */ 988 if (hWinStaDup) 989 { 990 ASSERT(hWinSta == hWinStaDup); 991 ObCloseHandle(hWinStaDup, UserMode); 992 hWinStaDup = NULL; 993 } 994 hWinSta = hTempWinSta; // hTempWinSta is NULL in case bAccessAllowed == FALSE 995 } 996 997 if (bUseDefaultWinSta) 998 { 999 if (hWinSta == NULL && !bInteractive) 1000 { 1001 /* Build a valid window station name from the LUID */ 1002 Status = RtlStringCbPrintfW(ObjectName->Buffer, 1003 ObjectName->MaximumLength, 1004 L"%wZ\\Service-0x%x-%x$", 1005 &gustrWindowStationsDir, 1006 ProcessLuid.HighPart, 1007 ProcessLuid.LowPart); 1008 if (!NT_SUCCESS(Status)) 1009 { 1010 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status); 1011 goto Quit; 1012 } 1013 ObjectName->Length = (USHORT)(wcslen(ObjectName->Buffer) * sizeof(WCHAR)); 1014 1015 /* 1016 * Create or open the non-interactive window station. 1017 * NOTE: The non-interactive window station handle is never inheritable. 1018 */ 1019 // FIXME: Set security! 1020 InitializeObjectAttributes(ObjectAttributes, 1021 ObjectName, 1022 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 1023 NULL, 1024 NULL); 1025 1026 Status = IntCreateWindowStation(&hWinSta, 1027 ObjectAttributes, 1028 UserMode, 1029 KernelMode, 1030 MAXIMUM_ALLOWED, 1031 0, 0, 0, 0, 0); 1032 if (!NT_SUCCESS(Status)) 1033 { 1034 ASSERT(hWinSta == NULL); 1035 ERR("Failed to create or open the non-interactive window station '%wZ', Status 0x%08lx\n", 1036 ObjectName, Status); 1037 goto Quit; 1038 } 1039 1040 // 1041 // FIXME: We might not need to always create or open the "Default" 1042 // desktop on the Service-0xXXXX-YYYY$ window station; we may need 1043 // to use another one.... 1044 // 1045 1046 /* Create or open the Default desktop on the window station */ 1047 Status = RtlStringCbCopyW(ObjectName->Buffer, 1048 ObjectName->MaximumLength, 1049 L"Default"); 1050 if (!NT_SUCCESS(Status)) 1051 { 1052 ERR("Impossible to build a valid desktop name, Status 0x%08lx\n", Status); 1053 goto Quit; 1054 } 1055 ObjectName->Length = (USHORT)(wcslen(ObjectName->Buffer) * sizeof(WCHAR)); 1056 1057 /* NOTE: The non-interactive desktop handle is never inheritable. */ 1058 // FIXME: Set security! 1059 InitializeObjectAttributes(ObjectAttributes, 1060 ObjectName, 1061 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 1062 hWinSta, 1063 NULL); 1064 1065 Status = IntCreateDesktop(&hDesktop, 1066 ObjectAttributes, 1067 UserMode, 1068 NULL, 1069 NULL, 1070 0, 1071 MAXIMUM_ALLOWED); 1072 if (!NT_SUCCESS(Status)) 1073 { 1074 ASSERT(hDesktop == NULL); 1075 ERR("Failed to create or open the desktop '%wZ' on window station 0x%p, Status 0x%08lx\n", 1076 ObjectName, hWinSta, Status); 1077 } 1078 1079 goto Quit; 1080 } 1081 /* 1082 if (hWinSta == NULL) 1083 { 1084 Status = STATUS_UNSUCCESSFUL; 1085 goto Quit; 1086 } 1087 */ 1088 } 1089 1090 /* 1091 * If we got an inherited desktop handle, duplicate and use it, 1092 * otherwise open a new desktop. 1093 */ 1094 if (hDesktop != NULL) 1095 { 1096 /* Duplicate the handle if it belongs to another process than the current one */ 1097 if (Process != PsGetCurrentProcess()) 1098 { 1099 ASSERT(hProcess); 1100 Status = ZwDuplicateObject(hProcess, 1101 hDesktop, 1102 ZwCurrentProcess(), 1103 (PHANDLE)&hDesktopDup, 1104 0, 1105 0, 1106 DUPLICATE_SAME_ACCESS); 1107 if (!NT_SUCCESS(Status)) 1108 { 1109 ERR("IntResolveDesktop: Failed to duplicate the desktop handle, Status 0x%08lx\n", Status); 1110 /* We will use a default desktop */ 1111 hDesktop = NULL; 1112 } 1113 else 1114 { 1115 hDesktop = hDesktopDup; 1116 } 1117 } 1118 } 1119 1120 if ((hWinSta != NULL) && (hDesktop == NULL)) 1121 { 1122 Status = RtlStringCbCopyNW(ObjectName->Buffer, 1123 ObjectName->MaximumLength, 1124 DesktopName.Buffer, 1125 DesktopName.Length); 1126 if (!NT_SUCCESS(Status)) 1127 { 1128 ERR("Impossible to build a valid desktop name, Status 0x%08lx\n", Status); 1129 goto Quit; 1130 } 1131 ObjectName->Length = (USHORT)(wcslen(ObjectName->Buffer) * sizeof(WCHAR)); 1132 1133 TRACE("Parsed initial desktop: '%wZ'\n", ObjectName); 1134 1135 /* Open the desktop object */ 1136 InitializeObjectAttributes(ObjectAttributes, 1137 ObjectName, 1138 OBJ_CASE_INSENSITIVE, 1139 hWinSta, 1140 NULL); 1141 if (bInherit) 1142 ObjectAttributes->Attributes |= OBJ_INHERIT; 1143 1144 Status = ObOpenObjectByName(ObjectAttributes, 1145 ExDesktopObjectType, 1146 UserMode, 1147 NULL, 1148 DESKTOP_ALL_ACCESS, 1149 NULL, 1150 (PHANDLE)&hDesktop); 1151 if (!NT_SUCCESS(Status)) 1152 { 1153 ERR("Failed to open the desktop '%wZ' on window station 0x%p, Status 0x%08lx\n", 1154 ObjectName, hWinSta, Status); 1155 goto Quit; 1156 } 1157 } 1158 1159 Quit: 1160 /* Release the object attributes */ 1161 if (ObjectAttributes) 1162 { 1163 MemSize = 0; 1164 ZwFreeVirtualMemory(ZwCurrentProcess(), 1165 (PVOID*)&ObjectAttributes, 1166 &MemSize, 1167 MEM_RELEASE); 1168 } 1169 1170 /* Close the temporary process handle */ 1171 if (hProcess) // if (Process != PsGetCurrentProcess()) 1172 ObCloseHandle(hProcess, KernelMode); 1173 1174 if (NT_SUCCESS(Status)) 1175 { 1176 *phWinSta = hWinSta; 1177 *phDesktop = hDesktop; 1178 return STATUS_SUCCESS; 1179 } 1180 else 1181 { 1182 ERR("IntResolveDesktop(%wZ) failed, Status 0x%08lx\n", DesktopPath, Status); 1183 1184 if (hDesktopDup) 1185 ObCloseHandle(hDesktopDup, UserMode); 1186 if (hWinStaDup) 1187 ObCloseHandle(hWinStaDup, UserMode); 1188 1189 if (hDesktop) 1190 ObCloseHandle(hDesktop, UserMode); 1191 if (hWinSta) 1192 ObCloseHandle(hWinSta, UserMode); 1193 1194 SetLastNtError(Status); 1195 return Status; 1196 } 1197 } 1198 1199 /* 1200 * IntValidateDesktopHandle 1201 * 1202 * Validates the desktop handle. 1203 * 1204 * Remarks 1205 * If the function succeeds, the handle remains referenced. If the 1206 * fucntion fails, last error is set. 1207 */ 1208 1209 NTSTATUS FASTCALL 1210 IntValidateDesktopHandle( 1211 HDESK Desktop, 1212 KPROCESSOR_MODE AccessMode, 1213 ACCESS_MASK DesiredAccess, 1214 PDESKTOP *Object) 1215 { 1216 NTSTATUS Status; 1217 1218 Status = ObReferenceObjectByHandle(Desktop, 1219 DesiredAccess, 1220 ExDesktopObjectType, 1221 AccessMode, 1222 (PVOID*)Object, 1223 NULL); 1224 1225 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n", 1226 Desktop, *Object, DesiredAccess, Status); 1227 1228 if (!NT_SUCCESS(Status)) 1229 SetLastNtError(Status); 1230 1231 return Status; 1232 } 1233 1234 PDESKTOP FASTCALL 1235 IntGetActiveDesktop(VOID) 1236 { 1237 return gpdeskInputDesktop; 1238 } 1239 1240 /* 1241 * Returns or creates a handle to the desktop object 1242 */ 1243 HDESK FASTCALL 1244 IntGetDesktopObjectHandle(PDESKTOP DesktopObject) 1245 { 1246 NTSTATUS Status; 1247 HDESK hDesk; 1248 1249 ASSERT(DesktopObject); 1250 1251 if (!ObFindHandleForObject(PsGetCurrentProcess(), 1252 DesktopObject, 1253 ExDesktopObjectType, 1254 NULL, 1255 (PHANDLE)&hDesk)) 1256 { 1257 Status = ObOpenObjectByPointer(DesktopObject, 1258 0, 1259 NULL, 1260 0, 1261 ExDesktopObjectType, 1262 UserMode, 1263 (PHANDLE)&hDesk); 1264 if (!NT_SUCCESS(Status)) 1265 { 1266 /* Unable to create a handle */ 1267 ERR("Unable to create a desktop handle\n"); 1268 return NULL; 1269 } 1270 } 1271 else 1272 { 1273 TRACE("Got handle: 0x%p\n", hDesk); 1274 } 1275 1276 return hDesk; 1277 } 1278 1279 PUSER_MESSAGE_QUEUE FASTCALL 1280 IntGetFocusMessageQueue(VOID) 1281 { 1282 PDESKTOP pdo = IntGetActiveDesktop(); 1283 if (!pdo) 1284 { 1285 TRACE("No active desktop\n"); 1286 return(NULL); 1287 } 1288 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue; 1289 } 1290 1291 VOID FASTCALL 1292 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue) 1293 { 1294 PUSER_MESSAGE_QUEUE Old; 1295 PDESKTOP pdo = IntGetActiveDesktop(); 1296 if (!pdo) 1297 { 1298 TRACE("No active desktop\n"); 1299 return; 1300 } 1301 if (NewQueue != NULL) 1302 { 1303 if (NewQueue->Desktop != NULL) 1304 { 1305 TRACE("Message Queue already attached to another desktop!\n"); 1306 return; 1307 } 1308 IntReferenceMessageQueue(NewQueue); 1309 (void)InterlockedExchangePointer((PVOID*)&NewQueue->Desktop, pdo); 1310 } 1311 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchangePointer((PVOID*)&pdo->ActiveMessageQueue, NewQueue); 1312 if (Old != NULL) 1313 { 1314 (void)InterlockedExchangePointer((PVOID*)&Old->Desktop, 0); 1315 gpqForegroundPrev = Old; 1316 IntDereferenceMessageQueue(Old); 1317 } 1318 // Only one Q can have active foreground even when there are more than one desktop. 1319 if (NewQueue) 1320 { 1321 gpqForeground = pdo->ActiveMessageQueue; 1322 } 1323 else 1324 { 1325 gpqForeground = NULL; 1326 ERR("ptiLastInput is CLEARED!!\n"); 1327 ptiLastInput = NULL; // ReactOS hacks... should check for process death. 1328 } 1329 } 1330 1331 PWND FASTCALL 1332 IntGetThreadDesktopWindow(PTHREADINFO pti) 1333 { 1334 if (!pti) pti = PsGetCurrentThreadWin32Thread(); 1335 if (pti->pDeskInfo) return pti->pDeskInfo->spwnd; 1336 return NULL; 1337 } 1338 1339 PWND FASTCALL co_GetDesktopWindow(PWND pWnd) 1340 { 1341 if (pWnd->head.rpdesk && 1342 pWnd->head.rpdesk->pDeskInfo) 1343 return pWnd->head.rpdesk->pDeskInfo->spwnd; 1344 return NULL; 1345 } 1346 1347 HWND FASTCALL IntGetDesktopWindow(VOID) 1348 { 1349 PDESKTOP pdo = IntGetActiveDesktop(); 1350 if (!pdo) 1351 { 1352 TRACE("No active desktop\n"); 1353 return NULL; 1354 } 1355 return pdo->DesktopWindow; 1356 } 1357 1358 PWND FASTCALL UserGetDesktopWindow(VOID) 1359 { 1360 PDESKTOP pdo = IntGetActiveDesktop(); 1361 1362 if (!pdo) 1363 { 1364 TRACE("No active desktop\n"); 1365 return NULL; 1366 } 1367 // return pdo->pDeskInfo->spwnd; 1368 return UserGetWindowObject(pdo->DesktopWindow); 1369 } 1370 1371 HWND FASTCALL IntGetMessageWindow(VOID) 1372 { 1373 PDESKTOP pdo = IntGetActiveDesktop(); 1374 1375 if (!pdo) 1376 { 1377 TRACE("No active desktop\n"); 1378 return NULL; 1379 } 1380 return pdo->spwndMessage->head.h; 1381 } 1382 1383 PWND FASTCALL UserGetMessageWindow(VOID) 1384 { 1385 PDESKTOP pdo = IntGetActiveDesktop(); 1386 1387 if (!pdo) 1388 { 1389 TRACE("No active desktop\n"); 1390 return NULL; 1391 } 1392 return pdo->spwndMessage; 1393 } 1394 1395 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID) 1396 { 1397 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1398 PDESKTOP pdo = pti->rpdesk; 1399 if (NULL == pdo) 1400 { 1401 ERR("Thread doesn't have a desktop\n"); 1402 return NULL; 1403 } 1404 return pdo->DesktopWindow; 1405 } 1406 1407 /* PUBLIC FUNCTIONS ***********************************************************/ 1408 1409 BOOL FASTCALL 1410 DesktopWindowProc(PWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) 1411 { 1412 PAINTSTRUCT Ps; 1413 ULONG Value; 1414 //ERR("DesktopWindowProc\n"); 1415 1416 *lResult = 0; 1417 1418 switch (Msg) 1419 { 1420 case WM_NCCREATE: 1421 if (!Wnd->fnid) 1422 { 1423 Wnd->fnid = FNID_DESKTOP; 1424 } 1425 *lResult = (LRESULT)TRUE; 1426 return TRUE; 1427 1428 case WM_CREATE: 1429 Value = HandleToULong(PsGetCurrentProcessId()); 1430 // Save Process ID 1431 co_UserSetWindowLong(UserHMGetHandle(Wnd), DT_GWL_PROCESSID, Value, FALSE); 1432 Value = HandleToULong(PsGetCurrentThreadId()); 1433 // Save Thread ID 1434 co_UserSetWindowLong(UserHMGetHandle(Wnd), DT_GWL_THREADID, Value, FALSE); 1435 case WM_CLOSE: 1436 return TRUE; 1437 1438 case WM_DISPLAYCHANGE: 1439 co_WinPosSetWindowPos(Wnd, 0, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE); 1440 return TRUE; 1441 1442 case WM_ERASEBKGND: 1443 IntPaintDesktop((HDC)wParam); 1444 *lResult = 1; 1445 return TRUE; 1446 1447 case WM_PAINT: 1448 { 1449 if (IntBeginPaint(Wnd, &Ps)) 1450 { 1451 IntEndPaint(Wnd, &Ps); 1452 } 1453 return TRUE; 1454 } 1455 case WM_SYSCOLORCHANGE: 1456 co_UserRedrawWindow(Wnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN); 1457 return TRUE; 1458 1459 case WM_SETCURSOR: 1460 { 1461 PCURICON_OBJECT pcurOld, pcurNew; 1462 pcurNew = UserGetCurIconObject(gDesktopCursor); 1463 if (!pcurNew) 1464 { 1465 return TRUE; 1466 } 1467 1468 pcurNew->CURSORF_flags |= CURSORF_CURRENT; 1469 pcurOld = UserSetCursor(pcurNew, FALSE); 1470 if (pcurOld) 1471 { 1472 pcurOld->CURSORF_flags &= ~CURSORF_CURRENT; 1473 UserDereferenceObject(pcurOld); 1474 } 1475 return TRUE; 1476 } 1477 1478 case WM_WINDOWPOSCHANGING: 1479 { 1480 PWINDOWPOS pWindowPos = (PWINDOWPOS)lParam; 1481 if ((pWindowPos->flags & SWP_SHOWWINDOW) != 0) 1482 { 1483 HDESK hdesk = UserOpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); 1484 IntSetThreadDesktop(hdesk, FALSE); 1485 } 1486 break; 1487 } 1488 default: 1489 TRACE("DWP calling IDWP Msg %d\n",Msg); 1490 //*lResult = IntDefWindowProc(Wnd, Msg, wParam, lParam, FALSE); 1491 } 1492 return TRUE; /* We are done. Do not do any callbacks to user mode */ 1493 } 1494 1495 BOOL FASTCALL 1496 UserMessageWindowProc(PWND pwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) 1497 { 1498 *lResult = 0; 1499 1500 switch(Msg) 1501 { 1502 case WM_NCCREATE: 1503 pwnd->fnid |= FNID_MESSAGEWND; 1504 *lResult = (LRESULT)TRUE; 1505 break; 1506 case WM_DESTROY: 1507 pwnd->fnid |= FNID_DESTROY; 1508 break; 1509 default: 1510 ERR("UMWP calling IDWP\n"); 1511 *lResult = IntDefWindowProc(pwnd, Msg, wParam, lParam, FALSE); 1512 } 1513 1514 return TRUE; /* We are done. Do not do any callbacks to user mode */ 1515 } 1516 1517 VOID NTAPI DesktopThreadMain(VOID) 1518 { 1519 BOOL Ret; 1520 MSG Msg; 1521 1522 gptiDesktopThread = PsGetCurrentThreadWin32Thread(); 1523 1524 UserEnterExclusive(); 1525 1526 /* Register system classes. This thread does not belong to any desktop so the 1527 classes will be allocated from the shared heap */ 1528 UserRegisterSystemClasses(); 1529 1530 KeSetEvent(gpDesktopThreadStartedEvent, IO_NO_INCREMENT, FALSE); 1531 1532 while (TRUE) 1533 { 1534 Ret = co_IntGetPeekMessage(&Msg, 0, 0, 0, PM_REMOVE, TRUE); 1535 if (Ret) 1536 { 1537 IntDispatchMessage(&Msg); 1538 } 1539 } 1540 1541 UserLeave(); 1542 } 1543 1544 HDC FASTCALL 1545 UserGetDesktopDC(ULONG DcType, BOOL bAltDc, BOOL ValidatehWnd) 1546 { 1547 PWND DesktopObject = 0; 1548 HDC DesktopHDC = 0; 1549 1550 /* This can be called from GDI/DX, so acquire the USER lock */ 1551 UserEnterExclusive(); 1552 1553 if (DcType == DC_TYPE_DIRECT) 1554 { 1555 DesktopObject = UserGetDesktopWindow(); 1556 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject); 1557 } 1558 else 1559 { 1560 PMONITOR pMonitor = UserGetPrimaryMonitor(); 1561 DesktopHDC = IntGdiCreateDisplayDC(pMonitor->hDev, DcType, bAltDc); 1562 } 1563 1564 UserLeave(); 1565 1566 return DesktopHDC; 1567 } 1568 1569 VOID APIENTRY 1570 UserRedrawDesktop(VOID) 1571 { 1572 PWND Window = NULL; 1573 PREGION Rgn; 1574 1575 Window = UserGetDesktopWindow(); 1576 Rgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow); 1577 1578 IntInvalidateWindows(Window, 1579 Rgn, 1580 RDW_FRAME | RDW_ERASE | 1581 RDW_INVALIDATE | RDW_ALLCHILDREN); 1582 1583 REGION_Delete(Rgn); 1584 } 1585 1586 1587 NTSTATUS FASTCALL 1588 co_IntShowDesktop(PDESKTOP Desktop, ULONG Width, ULONG Height, BOOL bRedraw) 1589 { 1590 PWND pwnd = Desktop->pDeskInfo->spwnd; 1591 UINT flags = SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW; 1592 ASSERT(pwnd); 1593 1594 if (!bRedraw) 1595 flags |= SWP_NOREDRAW; 1596 1597 co_WinPosSetWindowPos(pwnd, NULL, 0, 0, Width, Height, flags); 1598 1599 if (bRedraw) 1600 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_INVALIDATE ); 1601 1602 return STATUS_SUCCESS; 1603 } 1604 1605 NTSTATUS FASTCALL 1606 IntHideDesktop(PDESKTOP Desktop) 1607 { 1608 PWND DesktopWnd; 1609 1610 DesktopWnd = IntGetWindowObject(Desktop->DesktopWindow); 1611 if (! DesktopWnd) 1612 { 1613 return ERROR_INVALID_WINDOW_HANDLE; 1614 } 1615 DesktopWnd->style &= ~WS_VISIBLE; 1616 1617 return STATUS_SUCCESS; 1618 } 1619 1620 static 1621 HWND* FASTCALL 1622 UserBuildShellHookHwndList(PDESKTOP Desktop) 1623 { 1624 ULONG entries=0; 1625 PLIST_ENTRY ListEntry; 1626 PSHELL_HOOK_WINDOW Current; 1627 HWND* list; 1628 1629 /* FIXME: If we save nb elements in desktop, we don't have to loop to find nb entries */ 1630 ListEntry = Desktop->ShellHookWindows.Flink; 1631 while (ListEntry != &Desktop->ShellHookWindows) 1632 { 1633 ListEntry = ListEntry->Flink; 1634 entries++; 1635 } 1636 1637 if (!entries) return NULL; 1638 1639 list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */ 1640 if (list) 1641 { 1642 HWND* cursor = list; 1643 1644 ListEntry = Desktop->ShellHookWindows.Flink; 1645 while (ListEntry != &Desktop->ShellHookWindows) 1646 { 1647 Current = CONTAINING_RECORD(ListEntry, SHELL_HOOK_WINDOW, ListEntry); 1648 ListEntry = ListEntry->Flink; 1649 *cursor++ = Current->hWnd; 1650 } 1651 1652 *cursor = NULL; /* Nullterm list */ 1653 } 1654 1655 return list; 1656 } 1657 1658 /* 1659 * Send the Message to the windows registered for ShellHook 1660 * notifications. The lParam contents depend on the Message. See 1661 * MSDN for more details (RegisterShellHookWindow) 1662 */ 1663 VOID co_IntShellHookNotify(WPARAM Message, WPARAM wParam, LPARAM lParam) 1664 { 1665 PDESKTOP Desktop = IntGetActiveDesktop(); 1666 HWND* HwndList; 1667 1668 if (!gpsi->uiShellMsg) 1669 { 1670 gpsi->uiShellMsg = IntAddAtom(L"SHELLHOOK"); 1671 1672 TRACE("MsgType = %x\n", gpsi->uiShellMsg); 1673 if (!gpsi->uiShellMsg) 1674 ERR("LastError: %x\n", EngGetLastError()); 1675 } 1676 1677 if (!Desktop) 1678 { 1679 TRACE("IntShellHookNotify: No desktop!\n"); 1680 return; 1681 } 1682 1683 // Allow other devices have a shot at foreground. 1684 if (Message == HSHELL_APPCOMMAND) ptiLastInput = NULL; 1685 1686 // FIXME: System Tray Support. 1687 1688 HwndList = UserBuildShellHookHwndList(Desktop); 1689 if (HwndList) 1690 { 1691 HWND* cursor = HwndList; 1692 1693 for (; *cursor; cursor++) 1694 { 1695 TRACE("Sending notify\n"); 1696 UserPostMessage(*cursor, 1697 gpsi->uiShellMsg, 1698 Message, 1699 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) ); 1700 /* co_IntPostOrSendMessage(*cursor, 1701 gpsi->uiShellMsg, 1702 Message, 1703 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/ 1704 } 1705 1706 ExFreePoolWithTag(HwndList, USERTAG_WINDOWLIST); 1707 } 1708 1709 if (ISITHOOKED(WH_SHELL)) 1710 { 1711 co_HOOK_CallHooks(WH_SHELL, Message, wParam, lParam); 1712 } 1713 } 1714 1715 /* 1716 * Add the window to the ShellHookWindows list. The windows 1717 * on that list get notifications that are important to shell 1718 * type applications. 1719 * 1720 * TODO: Validate the window? I'm not sure if sending these messages to 1721 * an unsuspecting application that is not your own is a nice thing to do. 1722 */ 1723 BOOL IntRegisterShellHookWindow(HWND hWnd) 1724 { 1725 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1726 PDESKTOP Desktop = pti->rpdesk; 1727 PSHELL_HOOK_WINDOW Entry; 1728 1729 TRACE("IntRegisterShellHookWindow\n"); 1730 1731 /* First deregister the window, so we can be sure it's never twice in the 1732 * list. 1733 */ 1734 IntDeRegisterShellHookWindow(hWnd); 1735 1736 Entry = ExAllocatePoolWithTag(PagedPool, 1737 sizeof(SHELL_HOOK_WINDOW), 1738 TAG_WINSTA); 1739 1740 if (!Entry) 1741 return FALSE; 1742 1743 Entry->hWnd = hWnd; 1744 1745 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry); 1746 1747 return TRUE; 1748 } 1749 1750 /* 1751 * Remove the window from the ShellHookWindows list. The windows 1752 * on that list get notifications that are important to shell 1753 * type applications. 1754 */ 1755 BOOL IntDeRegisterShellHookWindow(HWND hWnd) 1756 { 1757 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1758 PDESKTOP Desktop = pti->rpdesk; 1759 PLIST_ENTRY ListEntry; 1760 PSHELL_HOOK_WINDOW Current; 1761 1762 ListEntry = Desktop->ShellHookWindows.Flink; 1763 while (ListEntry != &Desktop->ShellHookWindows) 1764 { 1765 Current = CONTAINING_RECORD(ListEntry, SHELL_HOOK_WINDOW, ListEntry); 1766 ListEntry = ListEntry->Flink; 1767 if (Current->hWnd == hWnd) 1768 { 1769 RemoveEntryList(&Current->ListEntry); 1770 ExFreePoolWithTag(Current, TAG_WINSTA); 1771 return TRUE; 1772 } 1773 } 1774 1775 return FALSE; 1776 } 1777 1778 static VOID 1779 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop) 1780 { 1781 /* FIXME: Disable until unmapping works in mm */ 1782 #if 0 1783 if (Desktop->pheapDesktop != NULL) 1784 { 1785 MmUnmapViewInSessionSpace(Desktop->pheapDesktop); 1786 Desktop->pheapDesktop = NULL; 1787 } 1788 1789 if (Desktop->hsectionDesktop != NULL) 1790 { 1791 ObDereferenceObject(Desktop->hsectionDesktop); 1792 Desktop->hsectionDesktop = NULL; 1793 } 1794 #endif 1795 } 1796 1797 BOOL FASTCALL 1798 IntPaintDesktop(HDC hDC) 1799 { 1800 static WCHAR s_wszSafeMode[] = L"Safe Mode"; // FIXME: Localize! 1801 1802 RECTL Rect; 1803 HBRUSH DesktopBrush, PreviousBrush; 1804 HWND hWndDesktop; 1805 BOOL doPatBlt = TRUE; 1806 PWND WndDesktop; 1807 BOOLEAN InSafeMode; 1808 1809 if (GdiGetClipBox(hDC, &Rect) == ERROR) 1810 return FALSE; 1811 1812 hWndDesktop = IntGetDesktopWindow(); // rpdesk->DesktopWindow; 1813 1814 WndDesktop = UserGetWindowObject(hWndDesktop); // rpdesk->pDeskInfo->spwnd; 1815 if (!WndDesktop) 1816 return FALSE; 1817 1818 /* Retrieve the current SafeMode state */ 1819 InSafeMode = (UserGetSystemMetrics(SM_CLEANBOOT) != 0); // gpsi->aiSysMet[SM_CLEANBOOT]; 1820 1821 if (!InSafeMode) 1822 { 1823 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground; 1824 1825 /* 1826 * Paint desktop background 1827 */ 1828 if (gspv.hbmWallpaper != NULL) 1829 { 1830 SIZE sz; 1831 int x, y; 1832 int scaledWidth, scaledHeight; 1833 int wallpaperX, wallpaperY, wallpaperWidth, wallpaperHeight; 1834 HDC hWallpaperDC; 1835 1836 sz.cx = WndDesktop->rcWindow.right - WndDesktop->rcWindow.left; 1837 sz.cy = WndDesktop->rcWindow.bottom - WndDesktop->rcWindow.top; 1838 1839 if (gspv.WallpaperMode == wmFit || 1840 gspv.WallpaperMode == wmFill) 1841 { 1842 int scaleNum, scaleDen; 1843 1844 // Precision improvement over ((sz.cx / gspv.cxWallpaper) > (sz.cy / gspv.cyWallpaper)) 1845 if ((sz.cx * gspv.cyWallpaper) > (sz.cy * gspv.cxWallpaper)) 1846 { 1847 if (gspv.WallpaperMode == wmFit) 1848 { 1849 scaleNum = sz.cy; 1850 scaleDen = gspv.cyWallpaper; 1851 } 1852 else 1853 { 1854 scaleNum = sz.cx; 1855 scaleDen = gspv.cxWallpaper; 1856 } 1857 } 1858 else 1859 { 1860 if (gspv.WallpaperMode == wmFit) 1861 { 1862 scaleNum = sz.cx; 1863 scaleDen = gspv.cxWallpaper; 1864 } 1865 else 1866 { 1867 scaleNum = sz.cy; 1868 scaleDen = gspv.cyWallpaper; 1869 } 1870 } 1871 1872 scaledWidth = EngMulDiv(gspv.cxWallpaper, scaleNum, scaleDen); 1873 scaledHeight = EngMulDiv(gspv.cyWallpaper, scaleNum, scaleDen); 1874 1875 if (gspv.WallpaperMode == wmFill) 1876 { 1877 wallpaperX = (((scaledWidth - sz.cx) * gspv.cxWallpaper) / (2 * scaledWidth)); 1878 wallpaperY = (((scaledHeight - sz.cy) * gspv.cyWallpaper) / (2 * scaledHeight)); 1879 1880 wallpaperWidth = (sz.cx * gspv.cxWallpaper) / scaledWidth; 1881 wallpaperHeight = (sz.cy * gspv.cyWallpaper) / scaledHeight; 1882 } 1883 } 1884 1885 if (gspv.WallpaperMode == wmStretch || 1886 gspv.WallpaperMode == wmTile || 1887 gspv.WallpaperMode == wmFill) 1888 { 1889 x = 0; 1890 y = 0; 1891 } 1892 else if (gspv.WallpaperMode == wmFit) 1893 { 1894 x = (sz.cx - scaledWidth) / 2; 1895 y = (sz.cy - scaledHeight) / 2; 1896 } 1897 else 1898 { 1899 /* Find the upper left corner, can be negative if the bitmap is bigger than the screen */ 1900 x = (sz.cx / 2) - (gspv.cxWallpaper / 2); 1901 y = (sz.cy / 2) - (gspv.cyWallpaper / 2); 1902 } 1903 1904 hWallpaperDC = NtGdiCreateCompatibleDC(hDC); 1905 if (hWallpaperDC != NULL) 1906 { 1907 HBITMAP hOldBitmap; 1908 1909 /* Fill in the area that the bitmap is not going to cover */ 1910 if (x > 0 || y > 0) 1911 { 1912 /* FIXME: Clip out the bitmap 1913 can be replaced with "NtGdiPatBlt(hDC, x, y, gspv.cxWallpaper, gspv.cyWallpaper, PATCOPY | DSTINVERT);" 1914 once we support DSTINVERT */ 1915 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush); 1916 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY); 1917 NtGdiSelectBrush(hDC, PreviousBrush); 1918 } 1919 1920 /* Do not fill the background after it is painted no matter the size of the picture */ 1921 doPatBlt = FALSE; 1922 1923 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, gspv.hbmWallpaper); 1924 1925 if (gspv.WallpaperMode == wmStretch) 1926 { 1927 if (Rect.right && Rect.bottom) 1928 NtGdiStretchBlt(hDC, 1929 x, 1930 y, 1931 sz.cx, 1932 sz.cy, 1933 hWallpaperDC, 1934 0, 1935 0, 1936 gspv.cxWallpaper, 1937 gspv.cyWallpaper, 1938 SRCCOPY, 1939 0); 1940 } 1941 else if (gspv.WallpaperMode == wmTile) 1942 { 1943 /* Paint the bitmap across the screen then down */ 1944 for (y = 0; y < Rect.bottom; y += gspv.cyWallpaper) 1945 { 1946 for (x = 0; x < Rect.right; x += gspv.cxWallpaper) 1947 { 1948 NtGdiBitBlt(hDC, 1949 x, 1950 y, 1951 gspv.cxWallpaper, 1952 gspv.cyWallpaper, 1953 hWallpaperDC, 1954 0, 1955 0, 1956 SRCCOPY, 1957 0, 1958 0); 1959 } 1960 } 1961 } 1962 else if (gspv.WallpaperMode == wmFit) 1963 { 1964 if (Rect.right && Rect.bottom) 1965 { 1966 NtGdiStretchBlt(hDC, 1967 x, 1968 y, 1969 scaledWidth, 1970 scaledHeight, 1971 hWallpaperDC, 1972 0, 1973 0, 1974 gspv.cxWallpaper, 1975 gspv.cyWallpaper, 1976 SRCCOPY, 1977 0); 1978 } 1979 } 1980 else if (gspv.WallpaperMode == wmFill) 1981 { 1982 if (Rect.right && Rect.bottom) 1983 { 1984 NtGdiStretchBlt(hDC, 1985 x, 1986 y, 1987 sz.cx, 1988 sz.cy, 1989 hWallpaperDC, 1990 wallpaperX, 1991 wallpaperY, 1992 wallpaperWidth, 1993 wallpaperHeight, 1994 SRCCOPY, 1995 0); 1996 } 1997 } 1998 else 1999 { 2000 NtGdiBitBlt(hDC, 2001 x, 2002 y, 2003 gspv.cxWallpaper, 2004 gspv.cyWallpaper, 2005 hWallpaperDC, 2006 0, 2007 0, 2008 SRCCOPY, 2009 0, 2010 0); 2011 } 2012 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap); 2013 NtGdiDeleteObjectApp(hWallpaperDC); 2014 } 2015 } 2016 } 2017 else 2018 { 2019 /* Black desktop background in Safe Mode */ 2020 DesktopBrush = StockObjects[BLACK_BRUSH]; 2021 } 2022 2023 /* Background is set to none, clear the screen */ 2024 if (doPatBlt) 2025 { 2026 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush); 2027 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY); 2028 NtGdiSelectBrush(hDC, PreviousBrush); 2029 } 2030 2031 /* 2032 * Display the system version on the desktop background 2033 */ 2034 if (InSafeMode || g_AlwaysDisplayVersion || g_PaintDesktopVersion) 2035 { 2036 NTSTATUS Status; 2037 static WCHAR wszzVersion[1024] = L"\0"; 2038 2039 /* Only used in normal mode */ 2040 // We expect at most 4 strings (3 for version, 1 for optional NtSystemRoot) 2041 static POLYTEXTW VerStrs[4] = {{0},{0},{0},{0}}; 2042 INT i = 0; 2043 SIZE_T len; 2044 2045 HFONT hFont1 = NULL, hFont2 = NULL, hOldFont = NULL; 2046 COLORREF crText, color_old; 2047 UINT align_old; 2048 INT mode_old; 2049 PDC pdc; 2050 2051 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &Rect, 0)) 2052 { 2053 Rect.left = Rect.top = 0; 2054 Rect.right = UserGetSystemMetrics(SM_CXSCREEN); 2055 Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN); 2056 } 2057 else 2058 { 2059 RECTL_vOffsetRect(&Rect, -Rect.left, -Rect.top); 2060 } 2061 2062 /* 2063 * Set up the fonts (otherwise use default ones) 2064 */ 2065 2066 /* Font for the principal version string */ 2067 hFont1 = GreCreateFontIndirectW(&gspv.ncm.lfCaptionFont); 2068 /* Font for the secondary version strings */ 2069 hFont2 = GreCreateFontIndirectW(&gspv.ncm.lfMenuFont); 2070 2071 if (hFont1) 2072 hOldFont = NtGdiSelectFont(hDC, hFont1); 2073 2074 if (gspv.hbmWallpaper == NULL) 2075 { 2076 /* Retrieve the brush fill colour */ 2077 // TODO: The following code constitutes "GreGetBrushColor". 2078 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush); 2079 pdc = DC_LockDc(hDC); 2080 if (pdc) 2081 { 2082 crText = pdc->eboFill.ulRGBColor; 2083 DC_UnlockDc(pdc); 2084 } 2085 else 2086 { 2087 crText = RGB(0, 0, 0); 2088 } 2089 NtGdiSelectBrush(hDC, PreviousBrush); 2090 2091 /* Adjust text colour according to the brush */ 2092 if (GetRValue(crText) + GetGValue(crText) + GetBValue(crText) > 128 * 3) 2093 crText = RGB(0, 0, 0); 2094 else 2095 crText = RGB(255, 255, 255); 2096 } 2097 else 2098 { 2099 /* Always use white when the text is displayed on top of a wallpaper */ 2100 crText = RGB(255, 255, 255); 2101 } 2102 2103 color_old = IntGdiSetTextColor(hDC, crText); 2104 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT); 2105 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT); 2106 2107 /* Display the system version information */ 2108 if (!*wszzVersion) 2109 { 2110 Status = GetSystemVersionString(wszzVersion, 2111 ARRAYSIZE(wszzVersion), 2112 InSafeMode, 2113 g_AlwaysDisplayVersion); 2114 if (!InSafeMode && NT_SUCCESS(Status) && *wszzVersion) 2115 { 2116 PWCHAR pstr = wszzVersion; 2117 for (i = 0; (i < ARRAYSIZE(VerStrs)) && *pstr; ++i) 2118 { 2119 VerStrs[i].n = lstrlenW(pstr); 2120 VerStrs[i].lpstr = pstr; 2121 pstr += (VerStrs[i].n + 1); 2122 } 2123 } 2124 } 2125 else 2126 { 2127 Status = STATUS_SUCCESS; 2128 } 2129 if (NT_SUCCESS(Status) && *wszzVersion) 2130 { 2131 if (!InSafeMode) 2132 { 2133 SIZE Size = {0, 0}; 2134 LONG TotalHeight = 0; 2135 2136 /* Normal Mode: multiple version information text separated by newlines */ 2137 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BOTTOM); 2138 2139 /* Compute the heights of the strings */ 2140 if (hFont1) NtGdiSelectFont(hDC, hFont1); 2141 for (i = 0; i < ARRAYSIZE(VerStrs); ++i) 2142 { 2143 if (!VerStrs[i].lpstr || !*VerStrs[i].lpstr || (VerStrs[i].n == 0)) 2144 break; 2145 2146 GreGetTextExtentW(hDC, VerStrs[i].lpstr, VerStrs[i].n, &Size, 1); 2147 VerStrs[i].y = Size.cy; // Store the string height 2148 TotalHeight += Size.cy; 2149 2150 /* While the first string was using hFont1, all the others use hFont2 */ 2151 if (hFont2) NtGdiSelectFont(hDC, hFont2); 2152 } 2153 /* The total height must not exceed the screen height */ 2154 TotalHeight = min(TotalHeight, Rect.bottom); 2155 2156 /* Display the strings */ 2157 if (hFont1) NtGdiSelectFont(hDC, hFont1); 2158 for (i = 0; i < ARRAYSIZE(VerStrs); ++i) 2159 { 2160 if (!VerStrs[i].lpstr || !*VerStrs[i].lpstr || (VerStrs[i].n == 0)) 2161 break; 2162 2163 TotalHeight -= VerStrs[i].y; 2164 GreExtTextOutW(hDC, 2165 Rect.right - 5, 2166 Rect.bottom - TotalHeight - 5, 2167 0, NULL, 2168 VerStrs[i].lpstr, 2169 VerStrs[i].n, 2170 NULL, 0); 2171 2172 /* While the first string was using hFont1, all the others use hFont2 */ 2173 if (hFont2) NtGdiSelectFont(hDC, hFont2); 2174 } 2175 } 2176 else 2177 { 2178 if (hFont1) NtGdiSelectFont(hDC, hFont1); 2179 2180 /* Safe Mode: single version information text in top center */ 2181 len = wcslen(wszzVersion); 2182 2183 IntGdiSetTextAlign(hDC, TA_CENTER | TA_TOP); 2184 GreExtTextOutW(hDC, (Rect.right + Rect.left)/2, Rect.top + 3, 0, NULL, wszzVersion, len, NULL, 0); 2185 } 2186 } 2187 2188 if (InSafeMode) 2189 { 2190 if (hFont1) NtGdiSelectFont(hDC, hFont1); 2191 2192 /* Print Safe Mode text in corners */ 2193 len = wcslen(s_wszSafeMode); 2194 2195 IntGdiSetTextAlign(hDC, TA_LEFT | TA_TOP); 2196 GreExtTextOutW(hDC, Rect.left, Rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0); 2197 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_TOP); 2198 GreExtTextOutW(hDC, Rect.right, Rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0); 2199 IntGdiSetTextAlign(hDC, TA_LEFT | TA_BOTTOM); 2200 GreExtTextOutW(hDC, Rect.left, Rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0); 2201 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BOTTOM); 2202 GreExtTextOutW(hDC, Rect.right, Rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0); 2203 } 2204 2205 IntGdiSetBkMode(hDC, mode_old); 2206 IntGdiSetTextAlign(hDC, align_old); 2207 IntGdiSetTextColor(hDC, color_old); 2208 2209 if (hFont2) 2210 GreDeleteObject(hFont2); 2211 2212 if (hFont1) 2213 { 2214 NtGdiSelectFont(hDC, hOldFont); 2215 GreDeleteObject(hFont1); 2216 } 2217 } 2218 2219 return TRUE; 2220 } 2221 2222 static NTSTATUS 2223 UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta) 2224 { 2225 PVOID DesktopHeapSystemBase = NULL; 2226 ULONG_PTR HeapSize = gdwDesktopSectionSize * 1024; 2227 SIZE_T DesktopInfoSize; 2228 ULONG i; 2229 2230 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk, DesktopName); 2231 2232 RtlZeroMemory(pdesk, sizeof(DESKTOP)); 2233 2234 /* Link the desktop with the parent window station */ 2235 ObReferenceObject(pwinsta); 2236 pdesk->rpwinstaParent = pwinsta; 2237 InsertTailList(&pwinsta->DesktopListHead, &pdesk->ListEntry); 2238 2239 /* Create the desktop heap */ 2240 pdesk->hsectionDesktop = NULL; 2241 pdesk->pheapDesktop = UserCreateHeap(&pdesk->hsectionDesktop, 2242 &DesktopHeapSystemBase, 2243 HeapSize); 2244 if (pdesk->pheapDesktop == NULL) 2245 { 2246 ERR("Failed to create desktop heap!\n"); 2247 return STATUS_NO_MEMORY; 2248 } 2249 2250 /* Create DESKTOPINFO */ 2251 DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName->Length + sizeof(WCHAR); 2252 pdesk->pDeskInfo = RtlAllocateHeap(pdesk->pheapDesktop, 2253 HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, 2254 DesktopInfoSize); 2255 if (pdesk->pDeskInfo == NULL) 2256 { 2257 ERR("Failed to create the DESKTOP structure!\n"); 2258 return STATUS_NO_MEMORY; 2259 } 2260 2261 /* Initialize the DESKTOPINFO */ 2262 pdesk->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase; 2263 pdesk->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize); 2264 RtlCopyMemory(pdesk->pDeskInfo->szDesktopName, 2265 DesktopName->Buffer, 2266 DesktopName->Length + sizeof(WCHAR)); 2267 for (i = 0; i < NB_HOOKS; i++) 2268 { 2269 InitializeListHead(&pdesk->pDeskInfo->aphkStart[i]); 2270 } 2271 2272 InitializeListHead(&pdesk->ShellHookWindows); 2273 InitializeListHead(&pdesk->PtiList); 2274 2275 return STATUS_SUCCESS; 2276 } 2277 2278 /* SYSCALLS *******************************************************************/ 2279 2280 /* 2281 * NtUserCreateDesktop 2282 * 2283 * Creates a new desktop. 2284 * 2285 * Parameters 2286 * poaAttribs 2287 * Object Attributes. 2288 * 2289 * lpszDesktopDevice 2290 * Name of the device. 2291 * 2292 * pDeviceMode 2293 * Device Mode. 2294 * 2295 * dwFlags 2296 * Interaction flags. 2297 * 2298 * dwDesiredAccess 2299 * Requested type of access. 2300 * 2301 * 2302 * Return Value 2303 * If the function succeeds, the return value is a handle to the newly 2304 * created desktop. If the specified desktop already exists, the function 2305 * succeeds and returns a handle to the existing desktop. When you are 2306 * finished using the handle, call the CloseDesktop function to close it. 2307 * If the function fails, the return value is NULL. 2308 * 2309 * Status 2310 * @implemented 2311 */ 2312 2313 NTSTATUS 2314 FASTCALL 2315 IntCreateDesktop( 2316 OUT HDESK* phDesktop, 2317 IN POBJECT_ATTRIBUTES ObjectAttributes, 2318 IN KPROCESSOR_MODE AccessMode, 2319 IN PUNICODE_STRING lpszDesktopDevice OPTIONAL, 2320 IN LPDEVMODEW lpdmw OPTIONAL, 2321 IN DWORD dwFlags, 2322 IN ACCESS_MASK dwDesiredAccess) 2323 { 2324 NTSTATUS Status; 2325 PDESKTOP pdesk = NULL; 2326 HDESK hDesk; 2327 BOOLEAN Context = FALSE; 2328 UNICODE_STRING ClassName; 2329 LARGE_STRING WindowName; 2330 BOOL NoHooks = FALSE; 2331 PWND pWnd = NULL; 2332 CREATESTRUCTW Cs; 2333 PTHREADINFO ptiCurrent; 2334 PCLS pcls; 2335 2336 TRACE("Enter IntCreateDesktop\n"); 2337 2338 ASSERT(UserIsEnteredExclusive()); 2339 2340 ASSERT(phDesktop); 2341 *phDesktop = NULL; 2342 2343 ptiCurrent = PsGetCurrentThreadWin32Thread(); 2344 ASSERT(ptiCurrent); 2345 ASSERT(gptiDesktopThread); 2346 2347 /* Turn off hooks when calling any CreateWindowEx from inside win32k */ 2348 NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); 2349 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS; 2350 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 2351 2352 /* 2353 * Try to open already existing desktop 2354 */ 2355 Status = ObOpenObjectByName(ObjectAttributes, 2356 ExDesktopObjectType, 2357 AccessMode, 2358 NULL, 2359 dwDesiredAccess, 2360 (PVOID)&Context, 2361 (PHANDLE)&hDesk); 2362 if (!NT_SUCCESS(Status)) 2363 { 2364 ERR("ObOpenObjectByName failed to open/create desktop\n"); 2365 goto Quit; 2366 } 2367 2368 /* In case the object was not created (eg if it existed), return now */ 2369 if (Context == FALSE) 2370 { 2371 TRACE("IntCreateDesktop opened desktop '%wZ'\n", ObjectAttributes->ObjectName); 2372 Status = STATUS_SUCCESS; 2373 goto Quit; 2374 } 2375 2376 /* Reference the desktop */ 2377 Status = ObReferenceObjectByHandle(hDesk, 2378 0, 2379 ExDesktopObjectType, 2380 KernelMode, 2381 (PVOID*)&pdesk, 2382 NULL); 2383 if (!NT_SUCCESS(Status)) 2384 { 2385 ERR("Failed to reference desktop object\n"); 2386 goto Quit; 2387 } 2388 2389 /* Get the desktop window class. The thread desktop does not belong to any desktop 2390 * so the classes created there (including the desktop class) are allocated in the shared heap 2391 * It would cause problems if we used a class that belongs to the caller 2392 */ 2393 ClassName.Buffer = WC_DESKTOP; 2394 ClassName.Length = 0; 2395 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE); 2396 if (pcls == NULL) 2397 { 2398 ASSERT(FALSE); 2399 Status = STATUS_UNSUCCESSFUL; 2400 goto Quit; 2401 } 2402 2403 RtlZeroMemory(&WindowName, sizeof(WindowName)); 2404 RtlZeroMemory(&Cs, sizeof(Cs)); 2405 Cs.x = UserGetSystemMetrics(SM_XVIRTUALSCREEN), 2406 Cs.y = UserGetSystemMetrics(SM_YVIRTUALSCREEN), 2407 Cs.cx = UserGetSystemMetrics(SM_CXVIRTUALSCREEN), 2408 Cs.cy = UserGetSystemMetrics(SM_CYVIRTUALSCREEN), 2409 Cs.style = WS_POPUP|WS_CLIPCHILDREN; 2410 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc! 2411 Cs.lpszName = (LPCWSTR) &WindowName; 2412 Cs.lpszClass = (LPCWSTR) &ClassName; 2413 2414 /* Use IntCreateWindow instead of co_UserCreateWindowEx because the later expects a thread with a desktop */ 2415 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk, WINVER); 2416 if (pWnd == NULL) 2417 { 2418 ERR("Failed to create desktop window for the new desktop\n"); 2419 Status = STATUS_UNSUCCESSFUL; 2420 goto Quit; 2421 } 2422 2423 pdesk->dwSessionId = PsGetCurrentProcessSessionId(); 2424 pdesk->DesktopWindow = pWnd->head.h; 2425 pdesk->pDeskInfo->spwnd = pWnd; 2426 pWnd->fnid = FNID_DESKTOP; 2427 2428 ClassName.Buffer = MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]); 2429 ClassName.Length = 0; 2430 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE); 2431 if (pcls == NULL) 2432 { 2433 ASSERT(FALSE); 2434 Status = STATUS_UNSUCCESSFUL; 2435 goto Quit; 2436 } 2437 2438 RtlZeroMemory(&WindowName, sizeof(WindowName)); 2439 RtlZeroMemory(&Cs, sizeof(Cs)); 2440 Cs.cx = Cs.cy = 100; 2441 Cs.style = WS_POPUP|WS_CLIPCHILDREN; 2442 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc! 2443 Cs.lpszName = (LPCWSTR)&WindowName; 2444 Cs.lpszClass = (LPCWSTR)&ClassName; 2445 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk, WINVER); 2446 if (pWnd == NULL) 2447 { 2448 ERR("Failed to create message window for the new desktop\n"); 2449 Status = STATUS_UNSUCCESSFUL; 2450 goto Quit; 2451 } 2452 2453 pdesk->spwndMessage = pWnd; 2454 pWnd->fnid = FNID_MESSAGEWND; 2455 2456 /* Now... 2457 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki) 2458 Create Tooltip. Saved in DesktopObject->spwndTooltip. 2459 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST 2460 hWndParent are spwndMessage. Use hModuleWin for server side winproc! 2461 The rest is same as message window. 2462 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx 2463 */ 2464 Status = STATUS_SUCCESS; 2465 2466 Quit: 2467 if (pdesk != NULL) 2468 { 2469 ObDereferenceObject(pdesk); 2470 } 2471 if (!NT_SUCCESS(Status) && hDesk != NULL) 2472 { 2473 ObCloseHandle(hDesk, AccessMode); 2474 hDesk = NULL; 2475 } 2476 if (!NoHooks) 2477 { 2478 ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS; 2479 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; 2480 } 2481 2482 TRACE("Leave IntCreateDesktop, Status 0x%08lx\n", Status); 2483 2484 if (NT_SUCCESS(Status)) 2485 *phDesktop = hDesk; 2486 else 2487 SetLastNtError(Status); 2488 return Status; 2489 } 2490 2491 HDESK APIENTRY 2492 NtUserCreateDesktop( 2493 POBJECT_ATTRIBUTES ObjectAttributes, 2494 PUNICODE_STRING lpszDesktopDevice, 2495 LPDEVMODEW lpdmw, 2496 DWORD dwFlags, 2497 ACCESS_MASK dwDesiredAccess) 2498 { 2499 NTSTATUS Status; 2500 HDESK hDesk; 2501 2502 DECLARE_RETURN(HDESK); 2503 2504 TRACE("Enter NtUserCreateDesktop\n"); 2505 UserEnterExclusive(); 2506 2507 Status = IntCreateDesktop(&hDesk, 2508 ObjectAttributes, 2509 UserMode, 2510 lpszDesktopDevice, 2511 lpdmw, 2512 dwFlags, 2513 dwDesiredAccess); 2514 if (!NT_SUCCESS(Status)) 2515 { 2516 ERR("IntCreateDesktop failed, Status 0x%08lx\n", Status); 2517 // SetLastNtError(Status); 2518 RETURN(NULL); 2519 } 2520 2521 RETURN(hDesk); 2522 2523 CLEANUP: 2524 TRACE("Leave NtUserCreateDesktop, ret=0x%p\n", _ret_); 2525 UserLeave(); 2526 END_CLEANUP; 2527 } 2528 2529 /* 2530 * NtUserOpenDesktop 2531 * 2532 * Opens an existing desktop. 2533 * 2534 * Parameters 2535 * lpszDesktopName 2536 * Name of the existing desktop. 2537 * 2538 * dwFlags 2539 * Interaction flags. 2540 * 2541 * dwDesiredAccess 2542 * Requested type of access. 2543 * 2544 * Return Value 2545 * Handle to the desktop or zero on failure. 2546 * 2547 * Status 2548 * @implemented 2549 */ 2550 2551 HDESK APIENTRY 2552 NtUserOpenDesktop( 2553 POBJECT_ATTRIBUTES ObjectAttributes, 2554 DWORD dwFlags, 2555 ACCESS_MASK dwDesiredAccess) 2556 { 2557 NTSTATUS Status; 2558 HDESK Desktop; 2559 2560 Status = ObOpenObjectByName( 2561 ObjectAttributes, 2562 ExDesktopObjectType, 2563 UserMode, 2564 NULL, 2565 dwDesiredAccess, 2566 NULL, 2567 (HANDLE*)&Desktop); 2568 2569 if (!NT_SUCCESS(Status)) 2570 { 2571 ERR("Failed to open desktop\n"); 2572 SetLastNtError(Status); 2573 return NULL; 2574 } 2575 2576 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes->ObjectName->Buffer, Desktop); 2577 2578 return Desktop; 2579 } 2580 2581 HDESK UserOpenInputDesktop(DWORD dwFlags, 2582 BOOL fInherit, 2583 ACCESS_MASK dwDesiredAccess) 2584 { 2585 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 2586 NTSTATUS Status; 2587 ULONG HandleAttributes = 0; 2588 HDESK hdesk = NULL; 2589 2590 if (!gpdeskInputDesktop) 2591 { 2592 return NULL; 2593 } 2594 2595 if (pti->ppi->prpwinsta != InputWindowStation) 2596 { 2597 ERR("Tried to open input desktop from non interactive winsta!\n"); 2598 EngSetLastError(ERROR_INVALID_FUNCTION); 2599 return NULL; 2600 } 2601 2602 if (fInherit) HandleAttributes = OBJ_INHERIT; 2603 2604 /* Create a new handle to the object */ 2605 Status = ObOpenObjectByPointer( 2606 gpdeskInputDesktop, 2607 HandleAttributes, 2608 NULL, 2609 dwDesiredAccess, 2610 ExDesktopObjectType, 2611 UserMode, 2612 (PHANDLE)&hdesk); 2613 2614 if (!NT_SUCCESS(Status)) 2615 { 2616 ERR("Failed to open input desktop object\n"); 2617 SetLastNtError(Status); 2618 } 2619 2620 return hdesk; 2621 } 2622 2623 /* 2624 * NtUserOpenInputDesktop 2625 * 2626 * Opens the input (interactive) desktop. 2627 * 2628 * Parameters 2629 * dwFlags 2630 * Interaction flags. 2631 * 2632 * fInherit 2633 * Inheritance option. 2634 * 2635 * dwDesiredAccess 2636 * Requested type of access. 2637 * 2638 * Return Value 2639 * Handle to the input desktop or zero on failure. 2640 * 2641 * Status 2642 * @implemented 2643 */ 2644 2645 HDESK APIENTRY 2646 NtUserOpenInputDesktop( 2647 DWORD dwFlags, 2648 BOOL fInherit, 2649 ACCESS_MASK dwDesiredAccess) 2650 { 2651 HDESK hdesk; 2652 2653 UserEnterExclusive(); 2654 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n", gpdeskInputDesktop); 2655 2656 hdesk = UserOpenInputDesktop(dwFlags, fInherit, dwDesiredAccess); 2657 2658 TRACE("NtUserOpenInputDesktop returning 0x%p\n", hdesk); 2659 UserLeave(); 2660 return hdesk; 2661 } 2662 2663 /* 2664 * NtUserCloseDesktop 2665 * 2666 * Closes a desktop handle. 2667 * 2668 * Parameters 2669 * hDesktop 2670 * Handle to the desktop. 2671 * 2672 * Return Value 2673 * Status 2674 * 2675 * Remarks 2676 * The desktop handle can be created with NtUserCreateDesktop or 2677 * NtUserOpenDesktop. This function will fail if any thread in the calling 2678 * process is using the specified desktop handle or if the handle refers 2679 * to the initial desktop of the calling process. 2680 * 2681 * Status 2682 * @implemented 2683 */ 2684 2685 BOOL APIENTRY 2686 NtUserCloseDesktop(HDESK hDesktop) 2687 { 2688 PDESKTOP pdesk; 2689 NTSTATUS Status; 2690 DECLARE_RETURN(BOOL); 2691 2692 TRACE("NtUserCloseDesktop(0x%p) called\n", hDesktop); 2693 UserEnterExclusive(); 2694 2695 if (hDesktop == gptiCurrent->hdesk || hDesktop == gptiCurrent->ppi->hdeskStartup) 2696 { 2697 ERR("Attempted to close thread desktop\n"); 2698 EngSetLastError(ERROR_BUSY); 2699 RETURN(FALSE); 2700 } 2701 2702 Status = IntValidateDesktopHandle(hDesktop, UserMode, 0, &pdesk); 2703 if (!NT_SUCCESS(Status)) 2704 { 2705 ERR("Validation of desktop handle 0x%p failed\n", hDesktop); 2706 RETURN(FALSE); 2707 } 2708 2709 ObDereferenceObject(pdesk); 2710 2711 Status = ObCloseHandle(hDesktop, UserMode); 2712 if (!NT_SUCCESS(Status)) 2713 { 2714 ERR("Failed to close desktop handle 0x%p\n", hDesktop); 2715 SetLastNtError(Status); 2716 RETURN(FALSE); 2717 } 2718 2719 RETURN(TRUE); 2720 2721 CLEANUP: 2722 TRACE("Leave NtUserCloseDesktop, ret=%i\n", _ret_); 2723 UserLeave(); 2724 END_CLEANUP; 2725 } 2726 2727 /* 2728 * NtUserPaintDesktop 2729 * 2730 * The NtUserPaintDesktop function fills the clipping region in the 2731 * specified device context with the desktop pattern or wallpaper. The 2732 * function is provided primarily for shell desktops. 2733 * 2734 * Parameters 2735 * hDC 2736 * Handle to the device context. 2737 * 2738 * Status 2739 * @implemented 2740 */ 2741 2742 BOOL APIENTRY 2743 NtUserPaintDesktop(HDC hDC) 2744 { 2745 BOOL Ret; 2746 2747 UserEnterExclusive(); 2748 TRACE("Enter NtUserPaintDesktop\n"); 2749 2750 Ret = IntPaintDesktop(hDC); 2751 2752 TRACE("Leave NtUserPaintDesktop, ret=%i\n", Ret); 2753 UserLeave(); 2754 return Ret; 2755 } 2756 2757 /* 2758 * NtUserResolveDesktop 2759 * 2760 * The NtUserResolveDesktop function attempts to retrieve valid handles to 2761 * a desktop and a window station suitable for the specified process. 2762 * The specified desktop path string is used only as a hint for the resolution. 2763 * 2764 * See the description of IntResolveDesktop for more details. 2765 * 2766 * Parameters 2767 * ProcessHandle 2768 * Handle to a user process. 2769 * 2770 * DesktopPath 2771 * The desktop path string used as a hint for desktop resolution. 2772 * 2773 * bInherit 2774 * Whether or not the returned handles are inheritable. 2775 * 2776 * phWinSta 2777 * Pointer to a window station handle. 2778 * 2779 * Return Value 2780 * Handle to the desktop (direct return value) and 2781 * handle to the associated window station (by pointer). 2782 * NULL in case of failure. 2783 * 2784 * Remarks 2785 * Callable by CSRSS only. 2786 * 2787 * Status 2788 * @implemented 2789 */ 2790 2791 HDESK 2792 NTAPI 2793 NtUserResolveDesktop( 2794 IN HANDLE ProcessHandle, 2795 IN PUNICODE_STRING DesktopPath, 2796 IN BOOL bInherit, 2797 OUT HWINSTA* phWinSta) 2798 { 2799 NTSTATUS Status; 2800 PEPROCESS Process; 2801 HWINSTA hWinSta = NULL; 2802 HDESK hDesktop = NULL; 2803 UNICODE_STRING CapturedDesktopPath; 2804 2805 /* Allow only the Console Server to perform this operation (via CSRSS) */ 2806 if (PsGetCurrentProcess() != gpepCSRSS) 2807 return NULL; 2808 2809 /* Get the process object the user handle was referencing */ 2810 Status = ObReferenceObjectByHandle(ProcessHandle, 2811 PROCESS_QUERY_INFORMATION, 2812 *PsProcessType, 2813 UserMode, 2814 (PVOID*)&Process, 2815 NULL); 2816 if (!NT_SUCCESS(Status)) 2817 return NULL; 2818 2819 UserEnterExclusive(); 2820 2821 _SEH2_TRY 2822 { 2823 /* Probe the handle pointer */ 2824 // ProbeForWriteHandle 2825 ProbeForWrite(phWinSta, sizeof(HWINSTA), sizeof(HWINSTA)); 2826 } 2827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2828 { 2829 Status = _SEH2_GetExceptionCode(); 2830 _SEH2_YIELD(goto Quit); 2831 } 2832 _SEH2_END; 2833 2834 /* Capture the user desktop path string */ 2835 Status = ProbeAndCaptureUnicodeString(&CapturedDesktopPath, 2836 UserMode, 2837 DesktopPath); 2838 if (!NT_SUCCESS(Status)) 2839 goto Quit; 2840 2841 /* Call the internal function */ 2842 Status = IntResolveDesktop(Process, 2843 &CapturedDesktopPath, 2844 bInherit, 2845 &hWinSta, 2846 &hDesktop); 2847 if (!NT_SUCCESS(Status)) 2848 { 2849 ERR("IntResolveDesktop failed, Status 0x%08lx\n", Status); 2850 hWinSta = NULL; 2851 hDesktop = NULL; 2852 } 2853 2854 _SEH2_TRY 2855 { 2856 /* Return the window station handle */ 2857 *phWinSta = hWinSta; 2858 } 2859 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2860 { 2861 Status = _SEH2_GetExceptionCode(); 2862 2863 /* We failed, close the opened desktop and window station */ 2864 if (hDesktop) ObCloseHandle(hDesktop, UserMode); 2865 hDesktop = NULL; 2866 if (hWinSta) ObCloseHandle(hWinSta, UserMode); 2867 } 2868 _SEH2_END; 2869 2870 /* Free the captured string */ 2871 ReleaseCapturedUnicodeString(&CapturedDesktopPath, UserMode); 2872 2873 Quit: 2874 UserLeave(); 2875 2876 /* Dereference the process object */ 2877 ObDereferenceObject(Process); 2878 2879 /* Return the desktop handle */ 2880 return hDesktop; 2881 } 2882 2883 /* 2884 * NtUserSwitchDesktop 2885 * 2886 * Sets the current input (interactive) desktop. 2887 * 2888 * Parameters 2889 * hDesktop 2890 * Handle to desktop. 2891 * 2892 * Return Value 2893 * Status 2894 * 2895 * Status 2896 * @unimplemented 2897 */ 2898 2899 BOOL APIENTRY 2900 NtUserSwitchDesktop(HDESK hdesk) 2901 { 2902 PDESKTOP pdesk; 2903 NTSTATUS Status; 2904 BOOL bRedrawDesktop; 2905 DECLARE_RETURN(BOOL); 2906 2907 UserEnterExclusive(); 2908 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk); 2909 2910 Status = IntValidateDesktopHandle(hdesk, UserMode, 0, &pdesk); 2911 if (!NT_SUCCESS(Status)) 2912 { 2913 ERR("Validation of desktop handle 0x%p failed\n", hdesk); 2914 RETURN(FALSE); 2915 } 2916 2917 if (PsGetCurrentProcessSessionId() != pdesk->rpwinstaParent->dwSessionId) 2918 { 2919 ObDereferenceObject(pdesk); 2920 ERR("NtUserSwitchDesktop called for a desktop of a different session\n"); 2921 RETURN(FALSE); 2922 } 2923 2924 if (pdesk == gpdeskInputDesktop) 2925 { 2926 ObDereferenceObject(pdesk); 2927 WARN("NtUserSwitchDesktop called for active desktop\n"); 2928 RETURN(TRUE); 2929 } 2930 2931 /* 2932 * Don't allow applications switch the desktop if it's locked, unless the caller 2933 * is the logon application itself 2934 */ 2935 if ((pdesk->rpwinstaParent->Flags & WSS_LOCKED) && 2936 gpidLogon != PsGetCurrentProcessId()) 2937 { 2938 ObDereferenceObject(pdesk); 2939 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk); 2940 RETURN(FALSE); 2941 } 2942 2943 if (pdesk->rpwinstaParent != InputWindowStation) 2944 { 2945 ObDereferenceObject(pdesk); 2946 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk); 2947 RETURN(FALSE); 2948 } 2949 2950 /* FIXME: Fail if the process is associated with a secured 2951 desktop such as Winlogon or Screen-Saver */ 2952 /* FIXME: Connect to input device */ 2953 2954 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop, pdesk); 2955 2956 bRedrawDesktop = FALSE; 2957 2958 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */ 2959 if (gpdeskInputDesktop != NULL) 2960 { 2961 if ((gpdeskInputDesktop->pDeskInfo->spwnd->style & WS_VISIBLE) == WS_VISIBLE) 2962 bRedrawDesktop = TRUE; 2963 2964 /* Hide the previous desktop window */ 2965 IntHideDesktop(gpdeskInputDesktop); 2966 } 2967 2968 /* Set the active desktop in the desktop's window station. */ 2969 InputWindowStation->ActiveDesktop = pdesk; 2970 2971 /* Set the global state. */ 2972 gpdeskInputDesktop = pdesk; 2973 2974 /* Show the new desktop window */ 2975 co_IntShowDesktop(pdesk, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN), bRedrawDesktop); 2976 2977 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n", gpdeskInputDesktop); 2978 ObDereferenceObject(pdesk); 2979 2980 RETURN(TRUE); 2981 2982 CLEANUP: 2983 TRACE("Leave NtUserSwitchDesktop, ret=%i\n", _ret_); 2984 UserLeave(); 2985 END_CLEANUP; 2986 } 2987 2988 /* 2989 * NtUserGetThreadDesktop 2990 * 2991 * Status 2992 * @implemented 2993 */ 2994 2995 HDESK APIENTRY 2996 NtUserGetThreadDesktop(DWORD dwThreadId, HDESK hConsoleDesktop) 2997 { 2998 HDESK hDesk; 2999 NTSTATUS Status; 3000 PTHREADINFO pti; 3001 PEPROCESS Process; 3002 PDESKTOP DesktopObject; 3003 OBJECT_HANDLE_INFORMATION HandleInformation; 3004 3005 UserEnterExclusive(); 3006 TRACE("Enter NtUserGetThreadDesktop\n"); 3007 3008 if (!dwThreadId) 3009 { 3010 EngSetLastError(ERROR_INVALID_PARAMETER); 3011 hDesk = NULL; 3012 goto Quit; 3013 } 3014 3015 /* Validate the Win32 thread and retrieve its information */ 3016 pti = IntTID2PTI(UlongToHandle(dwThreadId)); 3017 if (pti) 3018 { 3019 /* Get the desktop handle of the thread */ 3020 hDesk = pti->hdesk; 3021 Process = pti->ppi->peProcess; 3022 } 3023 else if (hConsoleDesktop) 3024 { 3025 /* 3026 * The thread may belong to a console, so attempt to use the provided 3027 * console desktop handle as a fallback. Otherwise this means that the 3028 * thread is either not Win32 or invalid. 3029 */ 3030 hDesk = hConsoleDesktop; 3031 Process = gpepCSRSS; 3032 } 3033 else 3034 { 3035 EngSetLastError(ERROR_INVALID_PARAMETER); 3036 hDesk = NULL; 3037 goto Quit; 3038 } 3039 3040 if (!hDesk) 3041 { 3042 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId); 3043 goto Quit; 3044 } 3045 3046 if (Process == PsGetCurrentProcess()) 3047 { 3048 /* 3049 * Just return the handle, since we queried the desktop handle 3050 * of a thread running in the same context. 3051 */ 3052 goto Quit; 3053 } 3054 3055 /* 3056 * We could just use the cached rpdesk instead of looking up the handle, 3057 * but it may actually be safer to validate the desktop and get a temporary 3058 * reference to it so that it does not disappear under us (e.g. when the 3059 * desktop is being destroyed) during the operation. 3060 */ 3061 /* 3062 * Switch into the context of the thread we are trying to get 3063 * the desktop from, so we can use the handle. 3064 */ 3065 KeAttachProcess(&Process->Pcb); 3066 Status = ObReferenceObjectByHandle(hDesk, 3067 0, 3068 ExDesktopObjectType, 3069 UserMode, 3070 (PVOID*)&DesktopObject, 3071 &HandleInformation); 3072 KeDetachProcess(); 3073 3074 if (NT_SUCCESS(Status)) 3075 { 3076 /* 3077 * Lookup our handle table if we can find a handle to the desktop object. 3078 * If not, create one. 3079 * QUESTION: Do we really need to create a handle in case it doesn't exist?? 3080 */ 3081 hDesk = IntGetDesktopObjectHandle(DesktopObject); 3082 3083 /* All done, we got a valid handle to the desktop */ 3084 ObDereferenceObject(DesktopObject); 3085 } 3086 else 3087 { 3088 /* The handle could not be found, there is nothing to get... */ 3089 hDesk = NULL; 3090 } 3091 3092 if (!hDesk) 3093 { 3094 ERR("Could not retrieve or access desktop for thread 0x%x\n", dwThreadId); 3095 EngSetLastError(ERROR_ACCESS_DENIED); 3096 } 3097 3098 Quit: 3099 TRACE("Leave NtUserGetThreadDesktop, hDesk = 0x%p\n", hDesk); 3100 UserLeave(); 3101 return hDesk; 3102 } 3103 3104 static NTSTATUS 3105 IntUnmapDesktopView(IN PDESKTOP pdesk) 3106 { 3107 PPROCESSINFO ppi; 3108 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink; 3109 NTSTATUS Status = STATUS_SUCCESS; 3110 3111 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk); 3112 3113 ppi = PsGetCurrentProcessWin32Process(); 3114 3115 /* 3116 * Unmap if we're the last thread using the desktop. 3117 * Start the search at the next mapping: skip the first entry 3118 * as it must be the global user heap mapping. 3119 */ 3120 PrevLink = &ppi->HeapMappings.Next; 3121 HeapMapping = *PrevLink; 3122 while (HeapMapping != NULL) 3123 { 3124 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop) 3125 { 3126 if (--HeapMapping->Count == 0) 3127 { 3128 *PrevLink = HeapMapping->Next; 3129 3130 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi, pdesk); 3131 Status = MmUnmapViewOfSection(PsGetCurrentProcess(), 3132 HeapMapping->UserMapping); 3133 3134 ObDereferenceObject(pdesk); 3135 3136 UserHeapFree(HeapMapping); 3137 break; 3138 } 3139 } 3140 3141 PrevLink = &HeapMapping->Next; 3142 HeapMapping = HeapMapping->Next; 3143 } 3144 3145 return Status; 3146 } 3147 3148 static NTSTATUS 3149 IntMapDesktopView(IN PDESKTOP pdesk) 3150 { 3151 PPROCESSINFO ppi; 3152 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink; 3153 PVOID UserBase = NULL; 3154 SIZE_T ViewSize = 0; 3155 LARGE_INTEGER Offset; 3156 NTSTATUS Status; 3157 3158 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk); 3159 3160 ppi = PsGetCurrentProcessWin32Process(); 3161 3162 /* 3163 * Find out if another thread already mapped the desktop heap. 3164 * Start the search at the next mapping: skip the first entry 3165 * as it must be the global user heap mapping. 3166 */ 3167 PrevLink = &ppi->HeapMappings.Next; 3168 HeapMapping = *PrevLink; 3169 while (HeapMapping != NULL) 3170 { 3171 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop) 3172 { 3173 HeapMapping->Count++; 3174 return STATUS_SUCCESS; 3175 } 3176 3177 PrevLink = &HeapMapping->Next; 3178 HeapMapping = HeapMapping->Next; 3179 } 3180 3181 /* We're the first, map the heap */ 3182 Offset.QuadPart = 0; 3183 Status = MmMapViewOfSection(pdesk->hsectionDesktop, 3184 PsGetCurrentProcess(), 3185 &UserBase, 3186 0, 3187 0, 3188 &Offset, 3189 &ViewSize, 3190 ViewUnmap, 3191 SEC_NO_CHANGE, 3192 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */ 3193 if (!NT_SUCCESS(Status)) 3194 { 3195 ERR("Failed to map desktop\n"); 3196 return Status; 3197 } 3198 3199 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi, pdesk); 3200 3201 /* Add the mapping */ 3202 HeapMapping = UserHeapAlloc(sizeof(*HeapMapping)); 3203 if (HeapMapping == NULL) 3204 { 3205 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase); 3206 ERR("UserHeapAlloc() failed!\n"); 3207 return STATUS_NO_MEMORY; 3208 } 3209 3210 HeapMapping->Next = NULL; 3211 HeapMapping->KernelMapping = (PVOID)pdesk->pheapDesktop; 3212 HeapMapping->UserMapping = UserBase; 3213 HeapMapping->Limit = ViewSize; 3214 HeapMapping->Count = 1; 3215 *PrevLink = HeapMapping; 3216 3217 ObReferenceObject(pdesk); 3218 3219 return STATUS_SUCCESS; 3220 } 3221 3222 BOOL 3223 IntSetThreadDesktop(IN HDESK hDesktop, 3224 IN BOOL FreeOnFailure) 3225 { 3226 PDESKTOP pdesk = NULL, pdeskOld; 3227 PTHREADINFO pti; 3228 NTSTATUS Status; 3229 PCLIENTTHREADINFO pctiOld, pctiNew = NULL; 3230 PCLIENTINFO pci; 3231 3232 ASSERT(NtCurrentTeb()); 3233 3234 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop, FreeOnFailure); 3235 3236 pti = PsGetCurrentThreadWin32Thread(); 3237 pci = pti->pClientInfo; 3238 3239 /* If the caller gave us a desktop, ensure it is valid */ 3240 if (hDesktop != NULL) 3241 { 3242 /* Validate the new desktop. */ 3243 Status = IntValidateDesktopHandle(hDesktop, UserMode, 0, &pdesk); 3244 if (!NT_SUCCESS(Status)) 3245 { 3246 ERR("Validation of desktop handle 0x%p failed\n", hDesktop); 3247 return FALSE; 3248 } 3249 3250 if (pti->rpdesk == pdesk) 3251 { 3252 /* Nothing to do */ 3253 ObDereferenceObject(pdesk); 3254 return TRUE; 3255 } 3256 } 3257 3258 /* Make sure that we don't own any window in the current desktop */ 3259 if (!IsListEmpty(&pti->WindowListHead)) 3260 { 3261 if (pdesk) 3262 ObDereferenceObject(pdesk); 3263 ERR("Attempted to change thread desktop although the thread has windows!\n"); 3264 EngSetLastError(ERROR_BUSY); 3265 return FALSE; 3266 } 3267 3268 /* Desktop is being re-set so clear out foreground. */ 3269 if (pti->rpdesk != pdesk && pti->MessageQueue == gpqForeground) 3270 { 3271 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop! 3272 IntSetFocusMessageQueue(NULL); 3273 } 3274 3275 /* Before doing the switch, map the new desktop heap and allocate the new pcti */ 3276 if (pdesk != NULL) 3277 { 3278 Status = IntMapDesktopView(pdesk); 3279 if (!NT_SUCCESS(Status)) 3280 { 3281 ERR("Failed to map desktop heap!\n"); 3282 ObDereferenceObject(pdesk); 3283 SetLastNtError(Status); 3284 return FALSE; 3285 } 3286 3287 pctiNew = DesktopHeapAlloc(pdesk, sizeof(CLIENTTHREADINFO)); 3288 if (pctiNew == NULL) 3289 { 3290 ERR("Failed to allocate new pcti\n"); 3291 IntUnmapDesktopView(pdesk); 3292 ObDereferenceObject(pdesk); 3293 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 3294 return FALSE; 3295 } 3296 } 3297 3298 /* 3299 * Processes, in particular Winlogon.exe, that manage window stations 3300 * (especially the interactive WinSta0 window station) and desktops, 3301 * may not be able to connect at startup to a window station and have 3302 * an associated desktop as well, if none exists on the system already. 3303 * Because creating a new window station does not affect the window station 3304 * associated to the process, and because neither by associating a window 3305 * station to the process nor creating a new desktop on it does associate 3306 * a startup desktop to that process, the process has to actually assigns 3307 * one of its threads to a desktop so that it gets automatically an assigned 3308 * startup desktop. 3309 * 3310 * This is what actually happens for Winlogon.exe, which is started without 3311 * any window station and desktop. By creating the first (and therefore 3312 * interactive) WinSta0 window station, then assigning WinSta0 to itself 3313 * and creating the Default desktop on it, and then assigning this desktop 3314 * to its main thread, Winlogon.exe basically does the similar steps that 3315 * would have been done automatically at its startup if there were already 3316 * an existing WinSta0 window station and Default desktop. 3317 * 3318 * Of course all this must not be done if we are a SYSTEM or CSRSS thread. 3319 */ 3320 // if (pti->ppi->peProcess != gpepCSRSS) 3321 if (!(pti->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) && 3322 pti->ppi->rpdeskStartup == NULL && hDesktop != NULL) 3323 { 3324 ERR("The process 0x%p '%s' didn't have an assigned startup desktop before, assigning it now!\n", 3325 pti->ppi->peProcess, pti->ppi->peProcess->ImageFileName); 3326 3327 pti->ppi->hdeskStartup = hDesktop; 3328 pti->ppi->rpdeskStartup = pdesk; 3329 } 3330 3331 /* free all classes or move them to the shared heap */ 3332 if (pti->rpdesk != NULL) 3333 { 3334 if (!IntCheckProcessDesktopClasses(pti->rpdesk, FreeOnFailure)) 3335 { 3336 ERR("Failed to move process classes to shared heap!\n"); 3337 if (pdesk) 3338 { 3339 DesktopHeapFree(pdesk, pctiNew); 3340 IntUnmapDesktopView(pdesk); 3341 ObDereferenceObject(pdesk); 3342 } 3343 return FALSE; 3344 } 3345 } 3346 3347 pdeskOld = pti->rpdesk; 3348 if (pti->pcti != &pti->cti) 3349 pctiOld = pti->pcti; 3350 else 3351 pctiOld = NULL; 3352 3353 /* do the switch */ 3354 if (pdesk != NULL) 3355 { 3356 pti->rpdesk = pdesk; 3357 pti->hdesk = hDesktop; 3358 pti->pDeskInfo = pti->rpdesk->pDeskInfo; 3359 pti->pcti = pctiNew; 3360 3361 pci->ulClientDelta = DesktopHeapGetUserDelta(); 3362 pci->pDeskInfo = (PVOID)((ULONG_PTR)pti->pDeskInfo - pci->ulClientDelta); 3363 pci->pClientThreadInfo = (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta); 3364 3365 /* initialize the new pcti */ 3366 if (pctiOld != NULL) 3367 { 3368 RtlCopyMemory(pctiNew, pctiOld, sizeof(CLIENTTHREADINFO)); 3369 } 3370 else 3371 { 3372 RtlZeroMemory(pctiNew, sizeof(CLIENTTHREADINFO)); 3373 pci->fsHooks = pti->fsHooks; 3374 pci->dwTIFlags = pti->TIF_flags; 3375 } 3376 } 3377 else 3378 { 3379 pti->rpdesk = NULL; 3380 pti->hdesk = NULL; 3381 pti->pDeskInfo = NULL; 3382 pti->pcti = &pti->cti; // Always point inside so there will be no crash when posting or sending msg's! 3383 pci->ulClientDelta = 0; 3384 pci->pDeskInfo = NULL; 3385 pci->pClientThreadInfo = NULL; 3386 } 3387 3388 /* clean up the old desktop */ 3389 if (pdeskOld != NULL) 3390 { 3391 RemoveEntryList(&pti->PtiLink); 3392 if (pctiOld) DesktopHeapFree(pdeskOld, pctiOld); 3393 IntUnmapDesktopView(pdeskOld); 3394 ObDereferenceObject(pdeskOld); 3395 } 3396 3397 if (pdesk) 3398 { 3399 InsertTailList(&pdesk->PtiList, &pti->PtiLink); 3400 } 3401 3402 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti, pti->ppi, pdeskOld, pdesk); 3403 3404 return TRUE; 3405 } 3406 3407 /* 3408 * NtUserSetThreadDesktop 3409 * 3410 * Status 3411 * @implemented 3412 */ 3413 3414 BOOL APIENTRY 3415 NtUserSetThreadDesktop(HDESK hDesktop) 3416 { 3417 BOOL ret = FALSE; 3418 3419 UserEnterExclusive(); 3420 3421 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen 3422 // here too and set the NT error level. Q. Is it necessary to have the validation 3423 // in IntSetThreadDesktop? Is it needed there too? 3424 if (hDesktop || (!hDesktop && PsGetCurrentProcess() == gpepCSRSS)) 3425 ret = IntSetThreadDesktop(hDesktop, FALSE); 3426 3427 UserLeave(); 3428 3429 return ret; 3430 } 3431 3432 /* EOF */ 3433