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