[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / desktop.c
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 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <win32k.h>
12 DBG_DEFAULT_CHANNEL(UserDesktop);
13
14 static NTSTATUS
15 UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta);
16
17 static NTSTATUS
18 IntMapDesktopView(IN PDESKTOP pdesk);
19
20 static NTSTATUS
21 IntUnmapDesktopView(IN PDESKTOP pdesk);
22
23 static VOID
24 IntFreeDesktopHeap(IN PDESKTOP pdesk);
25
26 /* GLOBALS *******************************************************************/
27
28 /* Currently active desktop */
29 PDESKTOP gpdeskInputDesktop = NULL;
30 HDC ScreenDeviceContext = NULL;
31 PTHREADINFO gptiDesktopThread = NULL;
32 HCURSOR gDesktopCursor = NULL;
33
34 /* OBJECT CALLBACKS **********************************************************/
35
36 NTSTATUS
37 APIENTRY
38 IntDesktopObjectParse(IN PVOID ParseObject,
39 IN PVOID ObjectType,
40 IN OUT PACCESS_STATE AccessState,
41 IN KPROCESSOR_MODE AccessMode,
42 IN ULONG Attributes,
43 IN OUT PUNICODE_STRING CompleteName,
44 IN OUT PUNICODE_STRING RemainingName,
45 IN OUT PVOID Context OPTIONAL,
46 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
47 OUT PVOID *Object)
48 {
49 NTSTATUS Status;
50 PDESKTOP Desktop;
51 OBJECT_ATTRIBUTES ObjectAttributes;
52 PLIST_ENTRY NextEntry, ListHead;
53 PWINSTATION_OBJECT WinStaObject = (PWINSTATION_OBJECT)ParseObject;
54 PUNICODE_STRING DesktopName;
55 PBOOLEAN pContext = (PBOOLEAN) Context;
56
57 if(pContext)
58 *pContext = FALSE;
59
60 /* Set the list pointers and loop the window station */
61 ListHead = &WinStaObject->DesktopListHead;
62 NextEntry = ListHead->Flink;
63 while (NextEntry != ListHead)
64 {
65 /* Get the current desktop */
66 Desktop = CONTAINING_RECORD(NextEntry, DESKTOP, ListEntry);
67
68 /// @todo Don't mess around with the object headers!
69 /* Get its name */
70 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR)
71 DesktopName = GET_DESKTOP_NAME(Desktop);
72 if (DesktopName)
73 {
74 /* Compare the name */
75 if (RtlEqualUnicodeString(RemainingName,
76 DesktopName,
77 (Attributes & OBJ_CASE_INSENSITIVE)))
78 {
79 /* We found a match. Did this come from a create? */
80 if (Context)
81 {
82 /* Unless OPEN_IF was given, fail with an error */
83 if (!(Attributes & OBJ_OPENIF))
84 {
85 /* Name collision */
86 return STATUS_OBJECT_NAME_COLLISION;
87 }
88 else
89 {
90 /* Otherwise, return with a warning only */
91 Status = STATUS_OBJECT_NAME_EXISTS;
92 }
93 }
94 else
95 {
96 /* This was a real open, so this is OK */
97 Status = STATUS_SUCCESS;
98 }
99
100 /* Reference the desktop and return it */
101 ObReferenceObject(Desktop);
102 *Object = Desktop;
103 return Status;
104 }
105 }
106
107 /* Go to the next desktop */
108 NextEntry = NextEntry->Flink;
109 }
110
111 /* If we got here but this isn't a create, then fail */
112 if (!Context) return STATUS_OBJECT_NAME_NOT_FOUND;
113
114 /* Create the desktop object */
115 InitializeObjectAttributes(&ObjectAttributes, RemainingName, 0, NULL, NULL);
116 Status = ObCreateObject(KernelMode,
117 ExDesktopObjectType,
118 &ObjectAttributes,
119 KernelMode,
120 NULL,
121 sizeof(DESKTOP),
122 0,
123 0,
124 (PVOID*)&Desktop);
125 if (!NT_SUCCESS(Status)) return Status;
126
127 /* Initialize the desktop */
128 Status = UserInitializeDesktop(Desktop, RemainingName, WinStaObject);
129 if (!NT_SUCCESS(Status))
130 {
131 ObDereferenceObject(Desktop);
132 return Status;
133 }
134
135 /* Set the desktop object and return success */
136 *Object = Desktop;
137 *pContext = TRUE;
138 return STATUS_SUCCESS;
139 }
140
141 NTSTATUS
142 NTAPI
143 IntDesktopObjectDelete(
144 _In_ PVOID Parameters)
145 {
146 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
147 PDESKTOP pdesk = (PDESKTOP)DeleteParameters->Object;
148
149 TRACE("Deleting desktop object 0x%p\n", pdesk);
150
151 ASSERT(pdesk->pDeskInfo->spwnd->spwndChild == NULL);
152
153 if (pdesk->pDeskInfo->spwnd)
154 co_UserDestroyWindow(pdesk->pDeskInfo->spwnd);
155
156 if (pdesk->spwndMessage)
157 co_UserDestroyWindow(pdesk->spwndMessage);
158
159 /* Remove the desktop from the window station's list of associcated desktops */
160 RemoveEntryList(&pdesk->ListEntry);
161
162 /* Free the heap */
163 IntFreeDesktopHeap(pdesk);
164 return STATUS_SUCCESS;
165 }
166
167 NTSTATUS
168 NTAPI
169 IntDesktopOkToClose(
170 _In_ PVOID Parameters)
171 {
172 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
173 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
174
175 if( pti == NULL)
176 {
177 /* This happens when we leak desktop handles */
178 return STATUS_SUCCESS;
179 }
180
181 /* Do not allow the current desktop or the initial desktop to be closed */
182 if( OkToCloseParameters->Handle == pti->ppi->hdeskStartup ||
183 OkToCloseParameters->Handle == pti->hdesk)
184 {
185 return STATUS_ACCESS_DENIED;
186 }
187
188 return STATUS_SUCCESS;
189 }
190
191 NTSTATUS
192 NTAPI
193 IntDesktopObjectOpen(
194 _In_ PVOID Parameters)
195 {
196 PWIN32_OPENMETHOD_PARAMETERS OpenParameters = Parameters;
197 PPROCESSINFO ppi = PsGetProcessWin32Process(OpenParameters->Process);
198 if (ppi == NULL)
199 return STATUS_SUCCESS;
200
201 return IntMapDesktopView((PDESKTOP)OpenParameters->Object);
202 }
203
204 NTSTATUS
205 NTAPI
206 IntDesktopObjectClose(
207 _In_ PVOID Parameters)
208 {
209 PWIN32_CLOSEMETHOD_PARAMETERS CloseParameters = Parameters;
210 PPROCESSINFO ppi = PsGetProcessWin32Process(CloseParameters->Process);
211 if (ppi == NULL)
212 {
213 /* This happens when the process leaks desktop handles.
214 * At this point the PPROCESSINFO is already destroyed */
215 return STATUS_SUCCESS;
216 }
217
218 return IntUnmapDesktopView((PDESKTOP)CloseParameters->Object);
219 }
220
221
222 /* PRIVATE FUNCTIONS **********************************************************/
223
224 INIT_FUNCTION
225 NTSTATUS
226 NTAPI
227 InitDesktopImpl(VOID)
228 {
229 GENERIC_MAPPING IntDesktopMapping = { DESKTOP_READ,
230 DESKTOP_WRITE,
231 DESKTOP_EXECUTE,
232 DESKTOP_ALL_ACCESS};
233
234 /* Set Desktop Object Attributes */
235 ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP);
236 ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping;
237 ExDesktopObjectType->TypeInfo.ValidAccessMask = DESKTOP_ALL_ACCESS;
238 return STATUS_SUCCESS;
239 }
240
241 static int GetSystemVersionString(LPWSTR buffer)
242 {
243 RTL_OSVERSIONINFOEXW versionInfo;
244 int len;
245
246 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
247
248 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
249 return 0;
250
251 if (versionInfo.dwMajorVersion <= 4)
252 len = swprintf(buffer,
253 L"ReactOS Version %lu.%lu %s Build %lu",
254 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
255 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
256 else
257 len = swprintf(buffer,
258 L"ReactOS %s (Build %lu)",
259 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
260
261 return len;
262 }
263
264
265 NTSTATUS FASTCALL
266 IntParseDesktopPath(PEPROCESS Process,
267 PUNICODE_STRING DesktopPath,
268 HWINSTA *hWinSta,
269 HDESK *hDesktop)
270 {
271 OBJECT_ATTRIBUTES ObjectAttributes;
272 UNICODE_STRING ObjectName;
273 NTSTATUS Status;
274 WCHAR wstrWinstaFullName[MAX_PATH], *pwstrWinsta = NULL, *pwstrDesktop = NULL;
275
276 ASSERT(hWinSta);
277 ASSERT(hDesktop);
278 ASSERT(DesktopPath);
279
280 *hWinSta = NULL;
281 *hDesktop = NULL;
282
283 if(DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
284 {
285 /*
286 * Parse the desktop path string which can be in the form "WinSta\Desktop"
287 * or just "Desktop". In latter case WinSta0 will be used.
288 */
289
290 pwstrDesktop = wcschr(DesktopPath->Buffer, L'\\');
291 if(pwstrDesktop != NULL)
292 {
293 *pwstrDesktop = 0;
294 pwstrDesktop++;
295 pwstrWinsta = DesktopPath->Buffer;
296 }
297 else
298 {
299 pwstrDesktop = DesktopPath->Buffer;
300 pwstrWinsta = NULL;
301 }
302
303 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta, pwstrDesktop);
304 }
305
306 #if 0
307 /* Search the process handle table for (inherited) window station
308 handles, use a more appropriate one than WinSta0 if possible. */
309 if (!ObFindHandleForObject(Process,
310 NULL,
311 ExWindowStationObjectType,
312 NULL,
313 (PHANDLE)hWinSta))
314 #endif
315 {
316 /* We had no luck searching for opened handles, use WinSta0 now */
317 if(!pwstrWinsta)
318 pwstrWinsta = L"WinSta0";
319 }
320
321 #if 0
322 /* Search the process handle table for (inherited) desktop
323 handles, use a more appropriate one than Default if possible. */
324 if (!ObFindHandleForObject(Process,
325 NULL,
326 ExDesktopObjectType,
327 NULL,
328 (PHANDLE)hDesktop))
329 #endif
330 {
331 /* We had no luck searching for opened handles, use Desktop now */
332 if(!pwstrDesktop)
333 pwstrDesktop = L"Default";
334 }
335
336 if(*hWinSta == NULL)
337 {
338 swprintf(wstrWinstaFullName, L"%wZ\\%ws", &gustrWindowStationsDir, pwstrWinsta);
339 RtlInitUnicodeString( &ObjectName, wstrWinstaFullName);
340
341 TRACE("parsed initial winsta: %wZ\n", &ObjectName);
342
343 /* Open the window station */
344 InitializeObjectAttributes(&ObjectAttributes,
345 &ObjectName,
346 OBJ_CASE_INSENSITIVE,
347 NULL,
348 NULL);
349
350 Status = ObOpenObjectByName(&ObjectAttributes,
351 ExWindowStationObjectType,
352 KernelMode,
353 NULL,
354 WINSTA_ACCESS_ALL,
355 NULL,
356 (HANDLE*)hWinSta);
357
358 if(!NT_SUCCESS(Status))
359 {
360 SetLastNtError(Status);
361 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName );
362 return Status;
363 }
364 }
365
366 if(*hDesktop == NULL)
367 {
368 RtlInitUnicodeString(&ObjectName, pwstrDesktop);
369
370 TRACE("parsed initial desktop: %wZ\n", &ObjectName);
371
372 /* Open the desktop object */
373 InitializeObjectAttributes(&ObjectAttributes,
374 &ObjectName,
375 OBJ_CASE_INSENSITIVE,
376 *hWinSta,
377 NULL);
378
379 Status = ObOpenObjectByName(&ObjectAttributes,
380 ExDesktopObjectType,
381 KernelMode,
382 NULL,
383 DESKTOP_ALL_ACCESS,
384 NULL,
385 (HANDLE*)hDesktop);
386
387 if(!NT_SUCCESS(Status))
388 {
389 *hDesktop = NULL;
390 NtClose(*hWinSta);
391 *hWinSta = NULL;
392 SetLastNtError(Status);
393 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName);
394 return Status;
395 }
396 }
397 return STATUS_SUCCESS;
398 }
399
400 /*
401 * IntValidateDesktopHandle
402 *
403 * Validates the desktop handle.
404 *
405 * Remarks
406 * If the function succeeds, the handle remains referenced. If the
407 * fucntion fails, last error is set.
408 */
409
410 NTSTATUS FASTCALL
411 IntValidateDesktopHandle(
412 HDESK Desktop,
413 KPROCESSOR_MODE AccessMode,
414 ACCESS_MASK DesiredAccess,
415 PDESKTOP *Object)
416 {
417 NTSTATUS Status;
418
419 Status = ObReferenceObjectByHandle(
420 Desktop,
421 DesiredAccess,
422 ExDesktopObjectType,
423 AccessMode,
424 (PVOID*)Object,
425 NULL);
426
427 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
428 Desktop, *Object, DesiredAccess, Status);
429
430 if (!NT_SUCCESS(Status))
431 SetLastNtError(Status);
432
433 return Status;
434 }
435
436 PDESKTOP FASTCALL
437 IntGetActiveDesktop(VOID)
438 {
439 return gpdeskInputDesktop;
440 }
441
442 /*
443 * Returns or creates a handle to the desktop object
444 */
445 HDESK FASTCALL
446 IntGetDesktopObjectHandle(PDESKTOP DesktopObject)
447 {
448 NTSTATUS Status;
449 HDESK Ret;
450
451 ASSERT(DesktopObject);
452
453 if (!ObFindHandleForObject(PsGetCurrentProcess(),
454 DesktopObject,
455 ExDesktopObjectType,
456 NULL,
457 (PHANDLE)&Ret))
458 {
459 Status = ObOpenObjectByPointer(DesktopObject,
460 0,
461 NULL,
462 0,
463 ExDesktopObjectType,
464 UserMode,
465 (PHANDLE)&Ret);
466 if(!NT_SUCCESS(Status))
467 {
468 /* Unable to create a handle */
469 ERR("Unable to create a desktop handle\n");
470 return NULL;
471 }
472 }
473 else
474 {
475 ERR("Got handle: %p\n", Ret);
476 }
477
478 return Ret;
479 }
480
481 PUSER_MESSAGE_QUEUE FASTCALL
482 IntGetFocusMessageQueue(VOID)
483 {
484 PDESKTOP pdo = IntGetActiveDesktop();
485 if (!pdo)
486 {
487 TRACE("No active desktop\n");
488 return(NULL);
489 }
490 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
491 }
492
493 VOID FASTCALL
494 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
495 {
496 PUSER_MESSAGE_QUEUE Old;
497 PDESKTOP pdo = IntGetActiveDesktop();
498 if (!pdo)
499 {
500 TRACE("No active desktop\n");
501 return;
502 }
503 if(NewQueue != NULL)
504 {
505 if(NewQueue->Desktop != NULL)
506 {
507 TRACE("Message Queue already attached to another desktop!\n");
508 return;
509 }
510 IntReferenceMessageQueue(NewQueue);
511 (void)InterlockedExchangePointer((PVOID*)&NewQueue->Desktop, pdo);
512 }
513 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchangePointer((PVOID*)&pdo->ActiveMessageQueue, NewQueue);
514 if(Old != NULL)
515 {
516 (void)InterlockedExchangePointer((PVOID*)&Old->Desktop, 0);
517 IntDereferenceMessageQueue(Old);
518 gpqForegroundPrev = Old;
519 }
520 // Only one Q can have active foreground even when there are more than one desktop.
521 if (NewQueue)
522 {
523 gpqForeground = pdo->ActiveMessageQueue;
524 }
525 else
526 {
527 gpqForeground = NULL;
528 ERR("ptiLastInput is CLEARED!!\n");
529 ptiLastInput = NULL; // ReactOS hacks,,,, should check for process death.
530 }
531 }
532
533 PWND FASTCALL
534 IntGetThreadDesktopWindow(PTHREADINFO pti)
535 {
536 if (!pti) pti = PsGetCurrentThreadWin32Thread();
537 if (pti->pDeskInfo) return pti->pDeskInfo->spwnd;
538 return NULL;
539 }
540
541 PWND FASTCALL co_GetDesktopWindow(PWND pWnd)
542 {
543 if (pWnd->head.rpdesk &&
544 pWnd->head.rpdesk->pDeskInfo)
545 return pWnd->head.rpdesk->pDeskInfo->spwnd;
546 return NULL;
547 }
548
549 HWND FASTCALL IntGetDesktopWindow(VOID)
550 {
551 PDESKTOP pdo = IntGetActiveDesktop();
552 if (!pdo)
553 {
554 TRACE("No active desktop\n");
555 return NULL;
556 }
557 return pdo->DesktopWindow;
558 }
559
560 PWND FASTCALL UserGetDesktopWindow(VOID)
561 {
562 PDESKTOP pdo = IntGetActiveDesktop();
563
564 if (!pdo)
565 {
566 TRACE("No active desktop\n");
567 return NULL;
568 }
569 // return pdo->pDeskInfo->spwnd;
570 return UserGetWindowObject(pdo->DesktopWindow);
571 }
572
573 HWND FASTCALL IntGetMessageWindow(VOID)
574 {
575 PDESKTOP pdo = IntGetActiveDesktop();
576
577 if (!pdo)
578 {
579 TRACE("No active desktop\n");
580 return NULL;
581 }
582 return pdo->spwndMessage->head.h;
583 }
584
585 PWND FASTCALL UserGetMessageWindow(VOID)
586 {
587 PDESKTOP pdo = IntGetActiveDesktop();
588
589 if (!pdo)
590 {
591 TRACE("No active desktop\n");
592 return NULL;
593 }
594 return pdo->spwndMessage;
595 }
596
597 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
598 {
599 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
600 PDESKTOP pdo = pti->rpdesk;
601 if (NULL == pdo)
602 {
603 ERR("Thread doesn't have a desktop\n");
604 return NULL;
605 }
606 return pdo->DesktopWindow;
607 }
608
609 /* PUBLIC FUNCTIONS ***********************************************************/
610
611 BOOL FASTCALL
612 DesktopWindowProc(PWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
613 {
614 PAINTSTRUCT Ps;
615 ULONG Value;
616 //ERR("DesktopWindowProc\n");
617
618 *lResult = 0;
619
620 switch (Msg)
621 {
622 case WM_NCCREATE:
623 if (!Wnd->fnid)
624 {
625 Wnd->fnid = FNID_DESKTOP;
626 }
627 *lResult = (LRESULT)TRUE;
628 return TRUE;
629
630 case WM_CREATE:
631 Value = HandleToULong(PsGetCurrentProcessId());
632 // Save Process ID
633 co_UserSetWindowLong(UserHMGetHandle(Wnd), DT_GWL_PROCESSID, Value, FALSE);
634 Value = HandleToULong(PsGetCurrentThreadId());
635 // Save Thread ID
636 co_UserSetWindowLong(UserHMGetHandle(Wnd), DT_GWL_THREADID, Value, FALSE);
637 case WM_CLOSE:
638 return TRUE;
639
640 case WM_DISPLAYCHANGE:
641 co_WinPosSetWindowPos(Wnd, 0, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE);
642 return TRUE;
643
644 case WM_ERASEBKGND:
645 IntPaintDesktop((HDC)wParam);
646 *lResult = 1;
647 return TRUE;
648
649 case WM_PAINT:
650 {
651 if (IntBeginPaint(Wnd, &Ps))
652 {
653 IntEndPaint(Wnd, &Ps);
654 }
655 return TRUE;
656 }
657 case WM_SYSCOLORCHANGE:
658 co_UserRedrawWindow(Wnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
659 return TRUE;
660 case WM_SETCURSOR:
661 {
662 PCURICON_OBJECT pcurOld, pcurNew;
663 pcurNew = UserGetCurIconObject(gDesktopCursor);
664 if (!pcurNew)
665 {
666 return TRUE;
667 }
668 pcurOld = UserSetCursor(pcurNew, FALSE);
669 if (pcurOld)
670 {
671 UserDereferenceObject(pcurOld);
672 }
673 return TRUE;
674 }
675
676 case WM_WINDOWPOSCHANGING:
677 {
678 PWINDOWPOS pWindowPos = (PWINDOWPOS)lParam;
679 if((pWindowPos->flags & SWP_SHOWWINDOW) != 0)
680 {
681 HDESK hdesk = IntGetDesktopObjectHandle(gpdeskInputDesktop);
682 IntSetThreadDesktop(hdesk, FALSE);
683 }
684 }
685
686 }
687 return TRUE; /* We are done. Do not do any callbacks to user mode */
688 }
689
690 BOOL FASTCALL
691 UserMessageWindowProc(PWND pwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
692 {
693 *lResult = 0;
694
695 switch(Msg)
696 {
697 case WM_NCCREATE:
698 pwnd->fnid |= FNID_MESSAGEWND;
699 *lResult = (LRESULT)TRUE;
700 break;
701 case WM_DESTROY:
702 pwnd->fnid |= FNID_DESTROY;
703 break;
704 }
705
706 return TRUE; /* We are done. Do not do any callbacks to user mode */
707 }
708
709 VOID NTAPI DesktopThreadMain()
710 {
711 BOOL Ret;
712 MSG Msg;
713
714 gptiDesktopThread = PsGetCurrentThreadWin32Thread();
715
716 UserEnterExclusive();
717
718 /* Register system classes. This thread does not belong to any desktop so the
719 classes will be allocated from the shared heap */
720 UserRegisterSystemClasses();
721
722 while(TRUE)
723 {
724 Ret = co_IntGetPeekMessage(&Msg, 0, 0, 0, PM_REMOVE, TRUE);
725 if (Ret)
726 {
727 IntDispatchMessage(&Msg);
728 }
729 }
730
731 UserLeave();
732 }
733
734 HDC FASTCALL
735 UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
736 {
737 PWND DesktopObject = 0;
738 HDC DesktopHDC = 0;
739
740 if (DcType == DC_TYPE_DIRECT)
741 {
742 DesktopObject = UserGetDesktopWindow();
743 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
744 }
745 else
746 {
747 PMONITOR pMonitor = UserGetPrimaryMonitor();
748 DesktopHDC = IntGdiCreateDisplayDC(pMonitor->hDev, DcType, EmptyDC);
749 }
750
751 return DesktopHDC;
752 }
753
754 VOID APIENTRY
755 UserRedrawDesktop()
756 {
757 PWND Window = NULL;
758 HRGN hRgn;
759
760 Window = UserGetDesktopWindow();
761 hRgn = IntSysCreateRectRgnIndirect(&Window->rcWindow);
762
763 IntInvalidateWindows( Window,
764 hRgn,
765 RDW_FRAME |
766 RDW_ERASE |
767 RDW_INVALIDATE |
768 RDW_ALLCHILDREN);
769
770 GreDeleteObject(hRgn);
771 }
772
773
774 NTSTATUS FASTCALL
775 co_IntShowDesktop(PDESKTOP Desktop, ULONG Width, ULONG Height, BOOL bRedraw)
776 {
777 PWND pwnd = Desktop->pDeskInfo->spwnd;
778 UINT flags = SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW;
779 ASSERT(pwnd);
780
781 if(!bRedraw)
782 flags |= SWP_NOREDRAW;
783
784 co_WinPosSetWindowPos(pwnd, NULL, 0, 0, Width, Height, flags);
785
786 if(bRedraw)
787 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_INVALIDATE );
788
789 return STATUS_SUCCESS;
790 }
791
792 NTSTATUS FASTCALL
793 IntHideDesktop(PDESKTOP Desktop)
794 {
795 PWND DesktopWnd;
796
797 DesktopWnd = IntGetWindowObject(Desktop->DesktopWindow);
798 if (! DesktopWnd)
799 {
800 return ERROR_INVALID_WINDOW_HANDLE;
801 }
802 DesktopWnd->style &= ~WS_VISIBLE;
803
804 return STATUS_SUCCESS;
805 }
806
807 static
808 HWND* FASTCALL
809 UserBuildShellHookHwndList(PDESKTOP Desktop)
810 {
811 ULONG entries=0;
812 PSHELL_HOOK_WINDOW Current;
813 HWND* list;
814
815 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
816 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
817 entries++;
818
819 if (!entries) return NULL;
820
821 list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */
822 if (list)
823 {
824 HWND* cursor = list;
825
826 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
827 *cursor++ = Current->hWnd;
828
829 *cursor = NULL; /* Nullterm list */
830 }
831
832 return list;
833 }
834
835 /*
836 * Send the Message to the windows registered for ShellHook
837 * notifications. The lParam contents depend on the Message. See
838 * MSDN for more details (RegisterShellHookWindow)
839 */
840 VOID co_IntShellHookNotify(WPARAM Message, WPARAM wParam, LPARAM lParam)
841 {
842 PDESKTOP Desktop = IntGetActiveDesktop();
843 HWND* HwndList;
844
845 if (!gpsi->uiShellMsg)
846 {
847 gpsi->uiShellMsg = IntAddAtom(L"SHELLHOOK");
848
849 TRACE("MsgType = %x\n", gpsi->uiShellMsg);
850 if (!gpsi->uiShellMsg)
851 ERR("LastError: %x\n", EngGetLastError());
852 }
853
854 if (!Desktop)
855 {
856 TRACE("IntShellHookNotify: No desktop!\n");
857 return;
858 }
859
860 // Allow other devices have a shot at foreground.
861 if (Message == HSHELL_APPCOMMAND) ptiLastInput = NULL;
862
863 // FIXME: System Tray Support.
864
865 HwndList = UserBuildShellHookHwndList(Desktop);
866 if (HwndList)
867 {
868 HWND* cursor = HwndList;
869
870 for (; *cursor; cursor++)
871 {
872 TRACE("Sending notify\n");
873 UserPostMessage(*cursor,
874 gpsi->uiShellMsg,
875 Message,
876 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );
877 /* co_IntPostOrSendMessage(*cursor,
878 gpsi->uiShellMsg,
879 Message,
880 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/
881 }
882
883 ExFreePoolWithTag(HwndList, USERTAG_WINDOWLIST);
884 }
885
886 if (ISITHOOKED(WH_SHELL))
887 {
888 co_HOOK_CallHooks(WH_SHELL, Message, wParam, lParam);
889 }
890 }
891
892 /*
893 * Add the window to the ShellHookWindows list. The windows
894 * on that list get notifications that are important to shell
895 * type applications.
896 *
897 * TODO: Validate the window? I'm not sure if sending these messages to
898 * an unsuspecting application that is not your own is a nice thing to do.
899 */
900 BOOL IntRegisterShellHookWindow(HWND hWnd)
901 {
902 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
903 PDESKTOP Desktop = pti->rpdesk;
904 PSHELL_HOOK_WINDOW Entry;
905
906 TRACE("IntRegisterShellHookWindow\n");
907
908 /* First deregister the window, so we can be sure it's never twice in the
909 * list.
910 */
911 IntDeRegisterShellHookWindow(hWnd);
912
913 Entry = ExAllocatePoolWithTag(PagedPool,
914 sizeof(SHELL_HOOK_WINDOW),
915 TAG_WINSTA);
916
917 if (!Entry)
918 return FALSE;
919
920 Entry->hWnd = hWnd;
921
922 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
923
924 return TRUE;
925 }
926
927 /*
928 * Remove the window from the ShellHookWindows list. The windows
929 * on that list get notifications that are important to shell
930 * type applications.
931 */
932 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
933 {
934 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
935 PDESKTOP Desktop = pti->rpdesk;
936 PSHELL_HOOK_WINDOW Current;
937
938 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
939 {
940 if (Current->hWnd == hWnd)
941 {
942 RemoveEntryList(&Current->ListEntry);
943 ExFreePoolWithTag(Current, TAG_WINSTA);
944 return TRUE;
945 }
946 }
947
948 return FALSE;
949 }
950
951 static VOID
952 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
953 {
954 /* FIXME: Disable until unmapping works in mm */
955 #if 0
956 if (Desktop->pheapDesktop != NULL)
957 {
958 MmUnmapViewInSessionSpace(Desktop->pheapDesktop);
959 Desktop->pheapDesktop = NULL;
960 }
961
962 if (Desktop->hsectionDesktop != NULL)
963 {
964 ObDereferenceObject(Desktop->hsectionDesktop);
965 Desktop->hsectionDesktop = NULL;
966 }
967 #endif
968 }
969
970 BOOL FASTCALL
971 IntPaintDesktop(HDC hDC)
972 {
973 RECTL Rect;
974 HBRUSH DesktopBrush, PreviousBrush;
975 HWND hWndDesktop;
976 BOOL doPatBlt = TRUE;
977 PWND WndDesktop;
978 static WCHAR s_wszSafeMode[] = L"Safe Mode";
979 int len;
980 COLORREF color_old;
981 UINT align_old;
982 int mode_old;
983
984 GdiGetClipBox(hDC, &Rect);
985
986 hWndDesktop = IntGetDesktopWindow(); // rpdesk->DesktopWindow;
987
988 WndDesktop = UserGetWindowObject(hWndDesktop); // rpdesk->pDeskInfo->spwnd;
989 if (!WndDesktop)
990 {
991 return FALSE;
992 }
993
994 if (!UserGetSystemMetrics(SM_CLEANBOOT))
995 {
996 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
997
998 /*
999 * Paint desktop background
1000 */
1001 if (gspv.hbmWallpaper != NULL)
1002 {
1003 SIZE sz;
1004 int x, y;
1005 HDC hWallpaperDC;
1006
1007 sz.cx = WndDesktop->rcWindow.right - WndDesktop->rcWindow.left;
1008 sz.cy = WndDesktop->rcWindow.bottom - WndDesktop->rcWindow.top;
1009
1010 if (gspv.WallpaperMode == wmStretch ||
1011 gspv.WallpaperMode == wmTile)
1012 {
1013 x = 0;
1014 y = 0;
1015 }
1016 else
1017 {
1018 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
1019 x = (sz.cx / 2) - (gspv.cxWallpaper / 2);
1020 y = (sz.cy / 2) - (gspv.cyWallpaper / 2);
1021 }
1022
1023 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1024 if(hWallpaperDC != NULL)
1025 {
1026 HBITMAP hOldBitmap;
1027
1028 /* Fill in the area that the bitmap is not going to cover */
1029 if (x > 0 || y > 0)
1030 {
1031 /* FIXME: Clip out the bitmap
1032 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1033 once we support DSTINVERT */
1034 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1035 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1036 NtGdiSelectBrush(hDC, PreviousBrush);
1037 }
1038
1039 /* Do not fill the background after it is painted no matter the size of the picture */
1040 doPatBlt = FALSE;
1041
1042 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, gspv.hbmWallpaper);
1043
1044 if (gspv.WallpaperMode == wmStretch)
1045 {
1046 if(Rect.right && Rect.bottom)
1047 NtGdiStretchBlt(hDC,
1048 x,
1049 y,
1050 sz.cx,
1051 sz.cy,
1052 hWallpaperDC,
1053 0,
1054 0,
1055 gspv.cxWallpaper,
1056 gspv.cyWallpaper,
1057 SRCCOPY,
1058 0);
1059
1060 }
1061 else if (gspv.WallpaperMode == wmTile)
1062 {
1063 /* Paint the bitmap across the screen then down */
1064 for(y = 0; y < Rect.bottom; y += gspv.cyWallpaper)
1065 {
1066 for(x = 0; x < Rect.right; x += gspv.cxWallpaper)
1067 {
1068 NtGdiBitBlt(hDC,
1069 x,
1070 y,
1071 gspv.cxWallpaper,
1072 gspv.cyWallpaper,
1073 hWallpaperDC,
1074 0,
1075 0,
1076 SRCCOPY,
1077 0,
1078 0);
1079 }
1080 }
1081 }
1082 else
1083 {
1084 NtGdiBitBlt(hDC,
1085 x,
1086 y,
1087 gspv.cxWallpaper,
1088 gspv.cyWallpaper,
1089 hWallpaperDC,
1090 0,
1091 0,
1092 SRCCOPY,
1093 0,
1094 0);
1095 }
1096 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1097 NtGdiDeleteObjectApp(hWallpaperDC);
1098 }
1099 }
1100 }
1101 else
1102 {
1103 /* Black desktop background in Safe Mode */
1104 DesktopBrush = StockObjects[BLACK_BRUSH];
1105 }
1106 /* Back ground is set to none, clear the screen */
1107 if (doPatBlt)
1108 {
1109 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1110 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1111 NtGdiSelectBrush(hDC, PreviousBrush);
1112 }
1113
1114 /*
1115 * Display system version on the desktop background
1116 */
1117
1118 if (g_PaintDesktopVersion || UserGetSystemMetrics(SM_CLEANBOOT))
1119 {
1120 static WCHAR s_wszVersion[256] = {0};
1121 RECTL rect;
1122
1123 if (*s_wszVersion)
1124 {
1125 len = wcslen(s_wszVersion);
1126 }
1127 else
1128 {
1129 len = GetSystemVersionString(s_wszVersion);
1130 }
1131
1132 if (len)
1133 {
1134 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1135 {
1136 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1137 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1138 }
1139
1140 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1141 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1142 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1143
1144 if(!UserGetSystemMetrics(SM_CLEANBOOT))
1145 {
1146 GreExtTextOutW(hDC, rect.right - 16, rect.bottom - 48, 0, NULL, s_wszVersion, len, NULL, 0);
1147 }
1148 else
1149 {
1150 /* Safe Mode */
1151
1152 /* Version information text in top center */
1153 IntGdiSetTextAlign(hDC, TA_CENTER | TA_TOP);
1154 GreExtTextOutW(hDC, (rect.right + rect.left)/2, rect.top + 3, 0, NULL, s_wszVersion, len, NULL, 0);
1155
1156 /* Safe Mode text in corners */
1157 len = wcslen(s_wszSafeMode);
1158 IntGdiSetTextAlign(hDC, TA_LEFT | TA_TOP);
1159 GreExtTextOutW(hDC, rect.left, rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
1160 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_TOP);
1161 GreExtTextOutW(hDC, rect.right, rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
1162 IntGdiSetTextAlign(hDC, TA_LEFT | TA_BASELINE);
1163 GreExtTextOutW(hDC, rect.left, rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
1164 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BASELINE);
1165 GreExtTextOutW(hDC, rect.right, rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
1166 }
1167
1168 IntGdiSetBkMode(hDC, mode_old);
1169 IntGdiSetTextAlign(hDC, align_old);
1170 IntGdiSetTextColor(hDC, color_old);
1171 }
1172 }
1173 return TRUE;
1174 }
1175
1176 static NTSTATUS
1177 UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta)
1178 {
1179 PVOID DesktopHeapSystemBase = NULL;
1180 ULONG_PTR HeapSize = 400 * 1024;
1181 SIZE_T DesktopInfoSize;
1182 ULONG i;
1183
1184 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk, DesktopName);
1185
1186 RtlZeroMemory(pdesk, sizeof(DESKTOP));
1187
1188 /* Link the desktop with the parent window station */
1189 pdesk->rpwinstaParent = pwinsta;
1190 InsertTailList(&pwinsta->DesktopListHead, &pdesk->ListEntry);
1191
1192 /* Create the desktop heap */
1193 pdesk->hsectionDesktop = NULL;
1194 pdesk->pheapDesktop = UserCreateHeap(&pdesk->hsectionDesktop,
1195 &DesktopHeapSystemBase,
1196 HeapSize);
1197 if (pdesk->pheapDesktop == NULL)
1198 {
1199 ERR("Failed to create desktop heap!\n");
1200 return STATUS_NO_MEMORY;
1201 }
1202
1203 /* Create DESKTOPINFO */
1204 DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName->Length + sizeof(WCHAR);
1205 pdesk->pDeskInfo = RtlAllocateHeap(pdesk->pheapDesktop,
1206 HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY,
1207 DesktopInfoSize);
1208 if (pdesk->pDeskInfo == NULL)
1209 {
1210 ERR("Failed to create the DESKTOP structure!\n");
1211 return STATUS_NO_MEMORY;
1212 }
1213
1214 /* Initialize the DESKTOPINFO */
1215 pdesk->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1216 pdesk->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1217 RtlCopyMemory(pdesk->pDeskInfo->szDesktopName,
1218 DesktopName->Buffer,
1219 DesktopName->Length + sizeof(WCHAR));
1220 for (i = 0; i < NB_HOOKS; i++)
1221 {
1222 InitializeListHead(&pdesk->pDeskInfo->aphkStart[i]);
1223 }
1224
1225 InitializeListHead(&pdesk->ShellHookWindows);
1226 InitializeListHead(&pdesk->PtiList);
1227
1228 return STATUS_SUCCESS;
1229 }
1230
1231 /* SYSCALLS *******************************************************************/
1232
1233 /*
1234 * NtUserCreateDesktop
1235 *
1236 * Creates a new desktop.
1237 *
1238 * Parameters
1239 * poaAttribs
1240 * Object Attributes.
1241 *
1242 * lpszDesktopDevice
1243 * Name of the device.
1244 *
1245 * pDeviceMode
1246 * Device Mode.
1247 *
1248 * dwFlags
1249 * Interaction flags.
1250 *
1251 * dwDesiredAccess
1252 * Requested type of access.
1253 *
1254 *
1255 * Return Value
1256 * If the function succeeds, the return value is a handle to the newly
1257 * created desktop. If the specified desktop already exists, the function
1258 * succeeds and returns a handle to the existing desktop. When you are
1259 * finished using the handle, call the CloseDesktop function to close it.
1260 * If the function fails, the return value is NULL.
1261 *
1262 * Status
1263 * @implemented
1264 */
1265
1266 HDESK APIENTRY
1267 NtUserCreateDesktop(
1268 POBJECT_ATTRIBUTES ObjectAttributes,
1269 PUNICODE_STRING lpszDesktopDevice,
1270 LPDEVMODEW lpdmw,
1271 DWORD dwFlags,
1272 ACCESS_MASK dwDesiredAccess)
1273 {
1274 PDESKTOP pdesk = NULL;
1275 NTSTATUS Status = STATUS_SUCCESS;
1276 HDESK hdesk;
1277 BOOLEAN Context;
1278 UNICODE_STRING ClassName;
1279 LARGE_STRING WindowName;
1280 BOOL NoHooks = FALSE;
1281 PWND pWnd = NULL;
1282 CREATESTRUCTW Cs;
1283 PTHREADINFO ptiCurrent;
1284 PCLS pcls;
1285
1286 DECLARE_RETURN(HDESK);
1287
1288 TRACE("Enter NtUserCreateDesktop\n");
1289 UserEnterExclusive();
1290
1291 ptiCurrent = PsGetCurrentThreadWin32Thread();
1292 ASSERT(ptiCurrent);
1293 ASSERT(gptiDesktopThread);
1294
1295 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1296 NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
1297 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
1298 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
1299
1300 /*
1301 * Try to open already existing desktop
1302 */
1303 Status = ObOpenObjectByName(
1304 ObjectAttributes,
1305 ExDesktopObjectType,
1306 UserMode,
1307 NULL,
1308 dwDesiredAccess,
1309 (PVOID)&Context,
1310 (HANDLE*)&hdesk);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 ERR("ObOpenObjectByName failed to open/create desktop\n");
1314 SetLastNtError(Status);
1315 RETURN(NULL);
1316 }
1317
1318 /* In case the object was not created (eg if it existed), return now */
1319 if (Context == FALSE)
1320 {
1321 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes->ObjectName);
1322 RETURN( hdesk);
1323 }
1324
1325 /* Reference the desktop */
1326 Status = ObReferenceObjectByHandle(hdesk,
1327 0,
1328 ExDesktopObjectType,
1329 KernelMode,
1330 (PVOID*)&pdesk,
1331 NULL);
1332 if (!NT_SUCCESS(Status))
1333 {
1334 ERR("Failed to reference desktop object\n");
1335 SetLastNtError(Status);
1336 RETURN(NULL);
1337 }
1338
1339 /* Get the desktop window class. The thread desktop does not belong to any desktop
1340 * so the classes created there (including the desktop class) are allocated in the shared heap
1341 * It would cause problems if we used a class that belongs to the caller
1342 */
1343 ClassName.Buffer = WC_DESKTOP;
1344 ClassName.Length = 0;
1345 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
1346 if (pcls == NULL)
1347 {
1348 ASSERT(FALSE);
1349 RETURN(NULL);
1350 }
1351
1352 RtlZeroMemory(&WindowName, sizeof(WindowName));
1353 RtlZeroMemory(&Cs, sizeof(Cs));
1354 Cs.x = UserGetSystemMetrics(SM_XVIRTUALSCREEN),
1355 Cs.y = UserGetSystemMetrics(SM_YVIRTUALSCREEN),
1356 Cs.cx = UserGetSystemMetrics(SM_CXVIRTUALSCREEN),
1357 Cs.cy = UserGetSystemMetrics(SM_CYVIRTUALSCREEN),
1358 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1359 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
1360 Cs.lpszName = (LPCWSTR) &WindowName;
1361 Cs.lpszClass = (LPCWSTR) &ClassName;
1362
1363 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1364 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
1365 if (pWnd == NULL)
1366 {
1367 ERR("Failed to create desktop window for the new desktop\n");
1368 RETURN(NULL);
1369 }
1370
1371 pdesk->dwSessionId = PsGetCurrentProcessSessionId();
1372 pdesk->DesktopWindow = pWnd->head.h;
1373 pdesk->pDeskInfo->spwnd = pWnd;
1374 pWnd->fnid = FNID_DESKTOP;
1375
1376 ClassName.Buffer = MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]);
1377 ClassName.Length = 0;
1378 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
1379 if (pcls == NULL)
1380 {
1381 ASSERT(FALSE);
1382 RETURN(NULL);
1383 }
1384
1385 RtlZeroMemory(&WindowName, sizeof(WindowName));
1386 RtlZeroMemory(&Cs, sizeof(Cs));
1387 Cs.cx = Cs.cy = 100;
1388 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1389 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
1390 Cs.lpszName = (LPCWSTR) &WindowName;
1391 Cs.lpszClass = (LPCWSTR) &ClassName;
1392 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
1393 if (pWnd == NULL)
1394 {
1395 ERR("Failed to create message window for the new desktop\n");
1396 RETURN(NULL);
1397 }
1398
1399 pdesk->spwndMessage = pWnd;
1400 pWnd->fnid = FNID_MESSAGEWND;
1401
1402 /* Now,,,
1403 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1404 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1405 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1406 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1407 The rest is same as message window.
1408 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1409 */
1410 RETURN( hdesk);
1411
1412 CLEANUP:
1413 if (pdesk != NULL)
1414 {
1415 ObDereferenceObject(pdesk);
1416 }
1417 if (_ret_ == NULL && hdesk != NULL)
1418 {
1419 ObCloseHandle(hdesk, UserMode);
1420 }
1421 if (!NoHooks)
1422 {
1423 ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS;
1424 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
1425 }
1426 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_);
1427 UserLeave();
1428 END_CLEANUP;
1429 }
1430
1431 /*
1432 * NtUserOpenDesktop
1433 *
1434 * Opens an existing desktop.
1435 *
1436 * Parameters
1437 * lpszDesktopName
1438 * Name of the existing desktop.
1439 *
1440 * dwFlags
1441 * Interaction flags.
1442 *
1443 * dwDesiredAccess
1444 * Requested type of access.
1445 *
1446 * Return Value
1447 * Handle to the desktop or zero on failure.
1448 *
1449 * Status
1450 * @implemented
1451 */
1452
1453 HDESK APIENTRY
1454 NtUserOpenDesktop(
1455 POBJECT_ATTRIBUTES ObjectAttributes,
1456 DWORD dwFlags,
1457 ACCESS_MASK dwDesiredAccess)
1458 {
1459 NTSTATUS Status;
1460 HDESK Desktop;
1461
1462 Status = ObOpenObjectByName(
1463 ObjectAttributes,
1464 ExDesktopObjectType,
1465 UserMode,
1466 NULL,
1467 dwDesiredAccess,
1468 NULL,
1469 (HANDLE*)&Desktop);
1470
1471 if (!NT_SUCCESS(Status))
1472 {
1473 ERR("Failed to open desktop\n");
1474 SetLastNtError(Status);
1475 return 0;
1476 }
1477
1478 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes->ObjectName->Buffer, Desktop);
1479
1480 return Desktop;
1481 }
1482
1483 /*
1484 * NtUserOpenInputDesktop
1485 *
1486 * Opens the input (interactive) desktop.
1487 *
1488 * Parameters
1489 * dwFlags
1490 * Interaction flags.
1491 *
1492 * fInherit
1493 * Inheritance option.
1494 *
1495 * dwDesiredAccess
1496 * Requested type of access.
1497 *
1498 * Return Value
1499 * Handle to the input desktop or zero on failure.
1500 *
1501 * Status
1502 * @implemented
1503 */
1504
1505 HDESK APIENTRY
1506 NtUserOpenInputDesktop(
1507 DWORD dwFlags,
1508 BOOL fInherit,
1509 ACCESS_MASK dwDesiredAccess)
1510 {
1511 NTSTATUS Status;
1512 HDESK hdesk = NULL;
1513 ULONG HandleAttributes = 0;
1514
1515 UserEnterExclusive();
1516 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
1517
1518 if(fInherit) HandleAttributes = OBJ_INHERIT;
1519
1520 /* Create a new handle to the object */
1521 Status = ObOpenObjectByPointer(
1522 gpdeskInputDesktop,
1523 HandleAttributes,
1524 NULL,
1525 dwDesiredAccess,
1526 ExDesktopObjectType,
1527 UserMode,
1528 (PHANDLE)&hdesk);
1529
1530 if (!NT_SUCCESS(Status))
1531 {
1532 ERR("Failed to open input desktop object\n");
1533 SetLastNtError(Status);
1534 }
1535
1536 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk);
1537 UserLeave();
1538 return hdesk;
1539 }
1540
1541 /*
1542 * NtUserCloseDesktop
1543 *
1544 * Closes a desktop handle.
1545 *
1546 * Parameters
1547 * hDesktop
1548 * Handle to the desktop.
1549 *
1550 * Return Value
1551 * Status
1552 *
1553 * Remarks
1554 * The desktop handle can be created with NtUserCreateDesktop or
1555 * NtUserOpenDesktop. This function will fail if any thread in the calling
1556 * process is using the specified desktop handle or if the handle refers
1557 * to the initial desktop of the calling process.
1558 *
1559 * Status
1560 * @implemented
1561 */
1562
1563 BOOL APIENTRY
1564 NtUserCloseDesktop(HDESK hDesktop)
1565 {
1566 PDESKTOP pdesk;
1567 NTSTATUS Status;
1568 DECLARE_RETURN(BOOL);
1569
1570 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop);
1571 UserEnterExclusive();
1572
1573 if( hDesktop == gptiCurrent->hdesk || hDesktop == gptiCurrent->ppi->hdeskStartup)
1574 {
1575 ERR("Attempted to close thread desktop\n");
1576 EngSetLastError(ERROR_BUSY);
1577 RETURN(FALSE);
1578 }
1579
1580 Status = IntValidateDesktopHandle( hDesktop, UserMode, 0, &pdesk);
1581 if (!NT_SUCCESS(Status))
1582 {
1583 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop);
1584 RETURN(FALSE);
1585 }
1586
1587 ObDereferenceObject(pdesk);
1588
1589 Status = ZwClose(hDesktop);
1590 if (!NT_SUCCESS(Status))
1591 {
1592 ERR("Failed to close desktop handle 0x%p\n", hDesktop);
1593 SetLastNtError(Status);
1594 RETURN(FALSE);
1595 }
1596
1597 RETURN(TRUE);
1598
1599 CLEANUP:
1600 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1601 UserLeave();
1602 END_CLEANUP;
1603 }
1604
1605 /*
1606 * NtUserPaintDesktop
1607 *
1608 * The NtUserPaintDesktop function fills the clipping region in the
1609 * specified device context with the desktop pattern or wallpaper. The
1610 * function is provided primarily for shell desktops.
1611 *
1612 * Parameters
1613 * hDC
1614 * Handle to the device context.
1615 *
1616 * Status
1617 * @implemented
1618 */
1619
1620 BOOL APIENTRY
1621 NtUserPaintDesktop(HDC hDC)
1622 {
1623 BOOL Ret;
1624 UserEnterExclusive();
1625 TRACE("Enter NtUserPaintDesktop\n");
1626 Ret = IntPaintDesktop(hDC);
1627 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret);
1628 UserLeave();
1629 return Ret;
1630 }
1631
1632 /*
1633 * NtUserSwitchDesktop
1634 *
1635 * Sets the current input (interactive) desktop.
1636 *
1637 * Parameters
1638 * hDesktop
1639 * Handle to desktop.
1640 *
1641 * Return Value
1642 * Status
1643 *
1644 * Status
1645 * @unimplemented
1646 */
1647
1648 BOOL APIENTRY
1649 NtUserSwitchDesktop(HDESK hdesk)
1650 {
1651 PDESKTOP pdesk;
1652 NTSTATUS Status;
1653 BOOL bRedrawDesktop;
1654 DECLARE_RETURN(BOOL);
1655
1656 UserEnterExclusive();
1657 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk);
1658
1659 Status = IntValidateDesktopHandle( hdesk, UserMode, 0, &pdesk);
1660 if (!NT_SUCCESS(Status))
1661 {
1662 ERR("Validation of desktop handle (0x%p) failed\n", hdesk);
1663 RETURN(FALSE);
1664 }
1665
1666 if (PsGetCurrentProcessSessionId() != pdesk->rpwinstaParent->dwSessionId)
1667 {
1668 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1669 RETURN(FALSE);
1670 }
1671
1672 if(pdesk == gpdeskInputDesktop)
1673 {
1674 WARN("NtUserSwitchDesktop called for active desktop\n");
1675 RETURN(TRUE);
1676 }
1677
1678 /*
1679 * Don't allow applications switch the desktop if it's locked, unless the caller
1680 * is the logon application itself
1681 */
1682 if((pdesk->rpwinstaParent->Flags & WSS_LOCKED) &&
1683 LogonProcess != PsGetCurrentProcessWin32Process())
1684 {
1685 ObDereferenceObject(pdesk);
1686 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk);
1687 RETURN(FALSE);
1688 }
1689
1690 if(pdesk->rpwinstaParent != InputWindowStation)
1691 {
1692 ObDereferenceObject(pdesk);
1693 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk);
1694 RETURN(FALSE);
1695 }
1696
1697 /* FIXME: Fail if the process is associated with a secured
1698 desktop such as Winlogon or Screen-Saver */
1699 /* FIXME: Connect to input device */
1700
1701 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop, pdesk);
1702
1703 bRedrawDesktop = FALSE;
1704
1705 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1706 if(gpdeskInputDesktop != NULL)
1707 {
1708 if((gpdeskInputDesktop->pDeskInfo->spwnd->style & WS_VISIBLE) == WS_VISIBLE)
1709 bRedrawDesktop = TRUE;
1710
1711 /* Hide the previous desktop window */
1712 IntHideDesktop(gpdeskInputDesktop);
1713 }
1714
1715 /* Set the active desktop in the desktop's window station. */
1716 InputWindowStation->ActiveDesktop = pdesk;
1717
1718 /* Set the global state. */
1719 gpdeskInputDesktop = pdesk;
1720
1721 /* Show the new desktop window */
1722 co_IntShowDesktop(pdesk, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN), bRedrawDesktop);
1723
1724 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
1725 ObDereferenceObject(pdesk);
1726
1727 RETURN(TRUE);
1728
1729 CLEANUP:
1730 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1731 UserLeave();
1732 END_CLEANUP;
1733 }
1734
1735 /*
1736 * NtUserGetThreadDesktop
1737 *
1738 * Status
1739 * @implemented
1740 */
1741
1742 HDESK APIENTRY
1743 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1744 {
1745 NTSTATUS Status;
1746 PETHREAD Thread;
1747 PDESKTOP DesktopObject;
1748 HDESK Ret, hThreadDesktop;
1749 OBJECT_HANDLE_INFORMATION HandleInformation;
1750 DECLARE_RETURN(HDESK);
1751
1752 UserEnterExclusive();
1753 TRACE("Enter NtUserGetThreadDesktop\n");
1754
1755 if(!dwThreadId)
1756 {
1757 EngSetLastError(ERROR_INVALID_PARAMETER);
1758 RETURN(0);
1759 }
1760
1761 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1762 if(!NT_SUCCESS(Status))
1763 {
1764 EngSetLastError(ERROR_INVALID_PARAMETER);
1765 RETURN(0);
1766 }
1767
1768 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1769 {
1770 /* Just return the handle, we queried the desktop handle of a thread running
1771 in the same context */
1772 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1773 ObDereferenceObject(Thread);
1774 RETURN(Ret);
1775 }
1776
1777 /* Get the desktop handle and the desktop of the thread */
1778 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1779 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1780 {
1781 ObDereferenceObject(Thread);
1782 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1783 RETURN(NULL);
1784 }
1785
1786 /* We could just use DesktopObject instead of looking up the handle, but latter
1787 may be a bit safer (e.g. when the desktop is being destroyed */
1788 /* Switch into the context of the thread we're trying to get the desktop from,
1789 so we can use the handle */
1790 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1791 Status = ObReferenceObjectByHandle(hThreadDesktop,
1792 GENERIC_ALL,
1793 ExDesktopObjectType,
1794 UserMode,
1795 (PVOID*)&DesktopObject,
1796 &HandleInformation);
1797 KeDetachProcess();
1798
1799 /* The handle couldn't be found, there's nothing to get... */
1800 if(!NT_SUCCESS(Status))
1801 {
1802 ObDereferenceObject(Thread);
1803 RETURN(NULL);
1804 }
1805
1806 /* Lookup our handle table if we can find a handle to the desktop object,
1807 if not, create one */
1808 Ret = IntGetDesktopObjectHandle(DesktopObject);
1809
1810 /* All done, we got a valid handle to the desktop */
1811 ObDereferenceObject(DesktopObject);
1812 ObDereferenceObject(Thread);
1813 RETURN(Ret);
1814
1815 CLEANUP:
1816 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_);
1817 UserLeave();
1818 END_CLEANUP;
1819 }
1820
1821 static NTSTATUS
1822 IntUnmapDesktopView(IN PDESKTOP pdesk)
1823 {
1824 PPROCESSINFO ppi;
1825 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1826 NTSTATUS Status = STATUS_SUCCESS;
1827
1828 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk);
1829
1830 ppi = PsGetCurrentProcessWin32Process();
1831 PrevLink = &ppi->HeapMappings.Next;
1832
1833 /* Unmap if we're the last thread using the desktop */
1834 HeapMapping = *PrevLink;
1835 while (HeapMapping != NULL)
1836 {
1837 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop)
1838 {
1839 if (--HeapMapping->Count == 0)
1840 {
1841 *PrevLink = HeapMapping->Next;
1842
1843 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi, pdesk);
1844 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1845 HeapMapping->UserMapping);
1846
1847 ObDereferenceObject(pdesk);
1848
1849 UserHeapFree(HeapMapping);
1850 break;
1851 }
1852 }
1853
1854 PrevLink = &HeapMapping->Next;
1855 HeapMapping = HeapMapping->Next;
1856 }
1857
1858 return Status;
1859 }
1860
1861 static NTSTATUS
1862 IntMapDesktopView(IN PDESKTOP pdesk)
1863 {
1864 PPROCESSINFO ppi;
1865 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1866 PVOID UserBase = NULL;
1867 SIZE_T ViewSize = 0;
1868 LARGE_INTEGER Offset;
1869 NTSTATUS Status;
1870
1871 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk);
1872
1873 ppi = PsGetCurrentProcessWin32Process();
1874 PrevLink = &ppi->HeapMappings.Next;
1875
1876 /* Find out if another thread already mapped the desktop heap */
1877 HeapMapping = *PrevLink;
1878 while (HeapMapping != NULL)
1879 {
1880 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop)
1881 {
1882 HeapMapping->Count++;
1883 return STATUS_SUCCESS;
1884 }
1885
1886 PrevLink = &HeapMapping->Next;
1887 HeapMapping = HeapMapping->Next;
1888 }
1889
1890 /* We're the first, map the heap */
1891 Offset.QuadPart = 0;
1892 Status = MmMapViewOfSection(pdesk->hsectionDesktop,
1893 PsGetCurrentProcess(),
1894 &UserBase,
1895 0,
1896 0,
1897 &Offset,
1898 &ViewSize,
1899 ViewUnmap,
1900 SEC_NO_CHANGE,
1901 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1902 if (!NT_SUCCESS(Status))
1903 {
1904 ERR("Failed to map desktop\n");
1905 return Status;
1906 }
1907
1908 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi, pdesk);
1909
1910 /* Add the mapping */
1911 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1912 if (HeapMapping == NULL)
1913 {
1914 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase);
1915 ERR("UserHeapAlloc() failed!\n");
1916 return STATUS_NO_MEMORY;
1917 }
1918
1919 HeapMapping->Next = NULL;
1920 HeapMapping->KernelMapping = (PVOID)pdesk->pheapDesktop;
1921 HeapMapping->UserMapping = UserBase;
1922 HeapMapping->Limit = ViewSize;
1923 HeapMapping->Count = 1;
1924 *PrevLink = HeapMapping;
1925
1926 ObReferenceObject(pdesk);
1927
1928 return STATUS_SUCCESS;
1929 }
1930
1931 BOOL
1932 IntSetThreadDesktop(IN HDESK hDesktop,
1933 IN BOOL FreeOnFailure)
1934 {
1935 PDESKTOP pdesk = NULL, pdeskOld;
1936 HDESK hdeskOld;
1937 PTHREADINFO pti;
1938 NTSTATUS Status;
1939 PCLIENTTHREADINFO pctiOld, pctiNew = NULL;
1940 PCLIENTINFO pci;
1941
1942 ASSERT(NtCurrentTeb());
1943
1944 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop, FreeOnFailure);
1945
1946 pti = PsGetCurrentThreadWin32Thread();
1947 pci = pti->pClientInfo;
1948
1949 /* If the caller gave us a desktop, ensure it is valid */
1950 if(hDesktop != NULL)
1951 {
1952 /* Validate the new desktop. */
1953 Status = IntValidateDesktopHandle( hDesktop, UserMode, 0, &pdesk);
1954 if (!NT_SUCCESS(Status))
1955 {
1956 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop);
1957 return FALSE;
1958 }
1959
1960 if (pti->rpdesk == pdesk)
1961 {
1962 /* Nothing to do */
1963 ObDereferenceObject(pdesk);
1964 return TRUE;
1965 }
1966 }
1967
1968 /* Make sure that we don't own any window in the current desktop */
1969 if (!IsListEmpty(&pti->WindowListHead))
1970 {
1971 if(pdesk)
1972 ObDereferenceObject(pdesk);
1973 ERR("Attempted to change thread desktop although the thread has windows!\n");
1974 EngSetLastError(ERROR_BUSY);
1975 return FALSE;
1976 }
1977
1978 /* Desktop is being re-set so clear out foreground. */
1979 if (pti->rpdesk != pdesk && pti->MessageQueue == gpqForeground)
1980 {
1981 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
1982 IntSetFocusMessageQueue(NULL);
1983 }
1984
1985 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
1986 if(pdesk != NULL)
1987 {
1988 Status = IntMapDesktopView(pdesk);
1989 if (!NT_SUCCESS(Status))
1990 {
1991 ERR("Failed to map desktop heap!\n");
1992 ObDereferenceObject(pdesk);
1993 SetLastNtError(Status);
1994 return FALSE;
1995 }
1996
1997 pctiNew = DesktopHeapAlloc( pdesk, sizeof(CLIENTTHREADINFO));
1998 if(pctiNew == NULL)
1999 {
2000 ERR("Failed to allocate new pcti\n");
2001 IntUnmapDesktopView(pdesk);
2002 ObDereferenceObject(pdesk);
2003 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2004 return FALSE;
2005 }
2006 }
2007
2008 /* free all classes or move them to the shared heap */
2009 if(pti->rpdesk != NULL)
2010 {
2011 if(!IntCheckProcessDesktopClasses(pti->rpdesk, FreeOnFailure))
2012 {
2013 ERR("Failed to move process classes to shared heap!\n");
2014 if(pdesk)
2015 {
2016 DesktopHeapFree(pdesk, pctiNew);
2017 IntUnmapDesktopView(pdesk);
2018 ObDereferenceObject(pdesk);
2019 }
2020 return FALSE;
2021 }
2022 }
2023
2024 pdeskOld = pti->rpdesk;
2025 hdeskOld = pti->hdesk;
2026 if (pti->pcti != &pti->cti)
2027 pctiOld = pti->pcti;
2028 else
2029 pctiOld = NULL;
2030
2031 /* do the switch */
2032 if(pdesk != NULL)
2033 {
2034 pti->rpdesk = pdesk;
2035 pti->hdesk = hDesktop;
2036 pti->pDeskInfo = pti->rpdesk->pDeskInfo;
2037 pti->pcti = pctiNew;
2038
2039 pci->ulClientDelta = DesktopHeapGetUserDelta();
2040 pci->pDeskInfo = (PVOID)((ULONG_PTR)pti->pDeskInfo - pci->ulClientDelta);
2041 pci->pClientThreadInfo = (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta);
2042
2043 /* initialize the new pcti */
2044 if(pctiOld != NULL)
2045 {
2046 RtlCopyMemory(pctiNew, pctiOld, sizeof(CLIENTTHREADINFO));
2047 }
2048 else
2049 {
2050 RtlZeroMemory(pctiNew, sizeof(CLIENTTHREADINFO));
2051 pci->fsHooks = pti->fsHooks;
2052 pci->dwTIFlags = pti->TIF_flags;
2053 }
2054 }
2055 else
2056 {
2057 pti->rpdesk = NULL;
2058 pti->hdesk = NULL;
2059 pti->pDeskInfo = NULL;
2060 pti->pcti = &pti->cti; // Always point inside so there will be no crash when posting or sending msg's!
2061 pci->ulClientDelta = 0;
2062 pci->pDeskInfo = NULL;
2063 pci->pClientThreadInfo = NULL;
2064 }
2065
2066 /* clean up the old desktop */
2067 if(pdeskOld != NULL)
2068 {
2069 RemoveEntryList(&pti->PtiLink);
2070 if (pctiOld) DesktopHeapFree(pdeskOld, pctiOld);
2071 IntUnmapDesktopView(pdeskOld);
2072 ObDereferenceObject(pdeskOld);
2073 ZwClose(hdeskOld);
2074 }
2075
2076 if(pdesk)
2077 {
2078 InsertTailList(&pdesk->PtiList, &pti->PtiLink);
2079 }
2080
2081 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti, pti->ppi, pdeskOld, pdesk);
2082
2083 return TRUE;
2084 }
2085
2086 /*
2087 * NtUserSetThreadDesktop
2088 *
2089 * Status
2090 * @implemented
2091 */
2092
2093 BOOL APIENTRY
2094 NtUserSetThreadDesktop(HDESK hDesktop)
2095 {
2096 BOOL ret = FALSE;
2097
2098 UserEnterExclusive();
2099
2100 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2101 // here too and set the NT error level. Q. Is it necessary to have the validation
2102 // in IntSetThreadDesktop? Is it needed there too?
2103 if (hDesktop || (!hDesktop && PsGetCurrentProcess() == gpepCSRSS))
2104 ret = IntSetThreadDesktop(hDesktop, FALSE);
2105
2106 UserLeave();
2107
2108 return ret;
2109 }
2110
2111 /* EOF */