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