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