[WIN32K]
[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 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) != 0))
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 #ifdef NEW_CURSORICON
666 pcurNew->CURSORF_flags |= CURSORF_CURRENT;
667 #endif
668 pcurOld = UserSetCursor(pcurNew, FALSE);
669 if (pcurOld)
670 {
671 #ifdef NEW_CURSORICON
672 pcurOld->CURSORF_flags &= ~CURSORF_CURRENT;
673 #endif
674 UserDereferenceObject(pcurOld);
675 }
676 return TRUE;
677 }
678
679 case WM_WINDOWPOSCHANGING:
680 {
681 PWINDOWPOS pWindowPos = (PWINDOWPOS)lParam;
682 if((pWindowPos->flags & SWP_SHOWWINDOW) != 0)
683 {
684 HDESK hdesk = IntGetDesktopObjectHandle(gpdeskInputDesktop);
685 IntSetThreadDesktop(hdesk, FALSE);
686 }
687 }
688
689 }
690 return TRUE; /* We are done. Do not do any callbacks to user mode */
691 }
692
693 BOOL FASTCALL
694 UserMessageWindowProc(PWND pwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
695 {
696 *lResult = 0;
697
698 switch(Msg)
699 {
700 case WM_NCCREATE:
701 pwnd->fnid |= FNID_MESSAGEWND;
702 *lResult = (LRESULT)TRUE;
703 break;
704 case WM_DESTROY:
705 pwnd->fnid |= FNID_DESTROY;
706 break;
707 }
708
709 return TRUE; /* We are done. Do not do any callbacks to user mode */
710 }
711
712 VOID NTAPI DesktopThreadMain()
713 {
714 BOOL Ret;
715 MSG Msg;
716
717 gptiDesktopThread = PsGetCurrentThreadWin32Thread();
718
719 UserEnterExclusive();
720
721 /* Register system classes. This thread does not belong to any desktop so the
722 classes will be allocated from the shared heap */
723 UserRegisterSystemClasses();
724
725 while(TRUE)
726 {
727 Ret = co_IntGetPeekMessage(&Msg, 0, 0, 0, PM_REMOVE, TRUE);
728 if (Ret)
729 {
730 IntDispatchMessage(&Msg);
731 }
732 }
733
734 UserLeave();
735 }
736
737 HDC FASTCALL
738 UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
739 {
740 PWND DesktopObject = 0;
741 HDC DesktopHDC = 0;
742
743 if (DcType == DC_TYPE_DIRECT)
744 {
745 DesktopObject = UserGetDesktopWindow();
746 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
747 }
748 else
749 {
750 PMONITOR pMonitor = UserGetPrimaryMonitor();
751 DesktopHDC = IntGdiCreateDisplayDC(pMonitor->hDev, DcType, EmptyDC);
752 }
753
754 return DesktopHDC;
755 }
756
757 VOID APIENTRY
758 UserRedrawDesktop()
759 {
760 PWND Window = NULL;
761 PREGION Rgn;
762
763 Window = UserGetDesktopWindow();
764 Rgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow);
765
766 IntInvalidateWindows( Window,
767 Rgn,
768 RDW_FRAME |
769 RDW_ERASE |
770 RDW_INVALIDATE |
771 RDW_ALLCHILDREN);
772
773 REGION_Delete(Rgn);
774 }
775
776
777 NTSTATUS FASTCALL
778 co_IntShowDesktop(PDESKTOP Desktop, ULONG Width, ULONG Height, BOOL bRedraw)
779 {
780 PWND pwnd = Desktop->pDeskInfo->spwnd;
781 UINT flags = SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW;
782 ASSERT(pwnd);
783
784 if(!bRedraw)
785 flags |= SWP_NOREDRAW;
786
787 co_WinPosSetWindowPos(pwnd, NULL, 0, 0, Width, Height, flags);
788
789 if(bRedraw)
790 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_INVALIDATE );
791
792 return STATUS_SUCCESS;
793 }
794
795 NTSTATUS FASTCALL
796 IntHideDesktop(PDESKTOP Desktop)
797 {
798 PWND DesktopWnd;
799
800 DesktopWnd = IntGetWindowObject(Desktop->DesktopWindow);
801 if (! DesktopWnd)
802 {
803 return ERROR_INVALID_WINDOW_HANDLE;
804 }
805 DesktopWnd->style &= ~WS_VISIBLE;
806
807 return STATUS_SUCCESS;
808 }
809
810 static
811 HWND* FASTCALL
812 UserBuildShellHookHwndList(PDESKTOP Desktop)
813 {
814 ULONG entries=0;
815 PLIST_ENTRY ListEntry;
816 PSHELL_HOOK_WINDOW Current;
817 HWND* list;
818
819 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
820 ListEntry = Desktop->ShellHookWindows.Flink;
821 while (ListEntry != &Desktop->ShellHookWindows)
822 {
823 ListEntry = ListEntry->Flink;
824 entries++;
825 }
826
827 if (!entries) return NULL;
828
829 list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */
830 if (list)
831 {
832 HWND* cursor = list;
833
834 ListEntry = Desktop->ShellHookWindows.Flink;
835 while (ListEntry != &Desktop->ShellHookWindows)
836 {
837 Current = CONTAINING_RECORD(ListEntry, SHELL_HOOK_WINDOW, ListEntry);
838 ListEntry = ListEntry->Flink;
839 *cursor++ = Current->hWnd;
840 }
841
842 *cursor = NULL; /* Nullterm list */
843 }
844
845 return list;
846 }
847
848 /*
849 * Send the Message to the windows registered for ShellHook
850 * notifications. The lParam contents depend on the Message. See
851 * MSDN for more details (RegisterShellHookWindow)
852 */
853 VOID co_IntShellHookNotify(WPARAM Message, WPARAM wParam, LPARAM lParam)
854 {
855 PDESKTOP Desktop = IntGetActiveDesktop();
856 HWND* HwndList;
857
858 if (!gpsi->uiShellMsg)
859 {
860 gpsi->uiShellMsg = IntAddAtom(L"SHELLHOOK");
861
862 TRACE("MsgType = %x\n", gpsi->uiShellMsg);
863 if (!gpsi->uiShellMsg)
864 ERR("LastError: %x\n", EngGetLastError());
865 }
866
867 if (!Desktop)
868 {
869 TRACE("IntShellHookNotify: No desktop!\n");
870 return;
871 }
872
873 // Allow other devices have a shot at foreground.
874 if (Message == HSHELL_APPCOMMAND) ptiLastInput = NULL;
875
876 // FIXME: System Tray Support.
877
878 HwndList = UserBuildShellHookHwndList(Desktop);
879 if (HwndList)
880 {
881 HWND* cursor = HwndList;
882
883 for (; *cursor; cursor++)
884 {
885 TRACE("Sending notify\n");
886 UserPostMessage(*cursor,
887 gpsi->uiShellMsg,
888 Message,
889 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );
890 /* co_IntPostOrSendMessage(*cursor,
891 gpsi->uiShellMsg,
892 Message,
893 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/
894 }
895
896 ExFreePoolWithTag(HwndList, USERTAG_WINDOWLIST);
897 }
898
899 if (ISITHOOKED(WH_SHELL))
900 {
901 co_HOOK_CallHooks(WH_SHELL, Message, wParam, lParam);
902 }
903 }
904
905 /*
906 * Add the window to the ShellHookWindows list. The windows
907 * on that list get notifications that are important to shell
908 * type applications.
909 *
910 * TODO: Validate the window? I'm not sure if sending these messages to
911 * an unsuspecting application that is not your own is a nice thing to do.
912 */
913 BOOL IntRegisterShellHookWindow(HWND hWnd)
914 {
915 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
916 PDESKTOP Desktop = pti->rpdesk;
917 PSHELL_HOOK_WINDOW Entry;
918
919 TRACE("IntRegisterShellHookWindow\n");
920
921 /* First deregister the window, so we can be sure it's never twice in the
922 * list.
923 */
924 IntDeRegisterShellHookWindow(hWnd);
925
926 Entry = ExAllocatePoolWithTag(PagedPool,
927 sizeof(SHELL_HOOK_WINDOW),
928 TAG_WINSTA);
929
930 if (!Entry)
931 return FALSE;
932
933 Entry->hWnd = hWnd;
934
935 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
936
937 return TRUE;
938 }
939
940 /*
941 * Remove the window from the ShellHookWindows list. The windows
942 * on that list get notifications that are important to shell
943 * type applications.
944 */
945 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
946 {
947 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
948 PDESKTOP Desktop = pti->rpdesk;
949 PLIST_ENTRY ListEntry;
950 PSHELL_HOOK_WINDOW Current;
951
952 ListEntry = Desktop->ShellHookWindows.Flink;
953 while (ListEntry != &Desktop->ShellHookWindows)
954 {
955 Current = CONTAINING_RECORD(ListEntry, SHELL_HOOK_WINDOW, ListEntry);
956 ListEntry = ListEntry->Flink;
957 if (Current->hWnd == hWnd)
958 {
959 RemoveEntryList(&Current->ListEntry);
960 ExFreePoolWithTag(Current, TAG_WINSTA);
961 return TRUE;
962 }
963 }
964
965 return FALSE;
966 }
967
968 static VOID
969 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
970 {
971 /* FIXME: Disable until unmapping works in mm */
972 #if 0
973 if (Desktop->pheapDesktop != NULL)
974 {
975 MmUnmapViewInSessionSpace(Desktop->pheapDesktop);
976 Desktop->pheapDesktop = NULL;
977 }
978
979 if (Desktop->hsectionDesktop != NULL)
980 {
981 ObDereferenceObject(Desktop->hsectionDesktop);
982 Desktop->hsectionDesktop = NULL;
983 }
984 #endif
985 }
986
987 BOOL FASTCALL
988 IntPaintDesktop(HDC hDC)
989 {
990 RECTL Rect;
991 HBRUSH DesktopBrush, PreviousBrush;
992 HWND hWndDesktop;
993 BOOL doPatBlt = TRUE;
994 PWND WndDesktop;
995 static WCHAR s_wszSafeMode[] = L"Safe Mode";
996 int len;
997 COLORREF color_old;
998 UINT align_old;
999 int mode_old;
1000
1001 GdiGetClipBox(hDC, &Rect);
1002
1003 hWndDesktop = IntGetDesktopWindow(); // rpdesk->DesktopWindow;
1004
1005 WndDesktop = UserGetWindowObject(hWndDesktop); // rpdesk->pDeskInfo->spwnd;
1006 if (!WndDesktop)
1007 {
1008 return FALSE;
1009 }
1010
1011 if (!UserGetSystemMetrics(SM_CLEANBOOT))
1012 {
1013 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
1014
1015 /*
1016 * Paint desktop background
1017 */
1018 if (gspv.hbmWallpaper != NULL)
1019 {
1020 SIZE sz;
1021 int x, y;
1022 HDC hWallpaperDC;
1023
1024 sz.cx = WndDesktop->rcWindow.right - WndDesktop->rcWindow.left;
1025 sz.cy = WndDesktop->rcWindow.bottom - WndDesktop->rcWindow.top;
1026
1027 if (gspv.WallpaperMode == wmStretch ||
1028 gspv.WallpaperMode == wmTile)
1029 {
1030 x = 0;
1031 y = 0;
1032 }
1033 else
1034 {
1035 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
1036 x = (sz.cx / 2) - (gspv.cxWallpaper / 2);
1037 y = (sz.cy / 2) - (gspv.cyWallpaper / 2);
1038 }
1039
1040 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1041 if(hWallpaperDC != NULL)
1042 {
1043 HBITMAP hOldBitmap;
1044
1045 /* Fill in the area that the bitmap is not going to cover */
1046 if (x > 0 || y > 0)
1047 {
1048 /* FIXME: Clip out the bitmap
1049 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1050 once we support DSTINVERT */
1051 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1052 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1053 NtGdiSelectBrush(hDC, PreviousBrush);
1054 }
1055
1056 /* Do not fill the background after it is painted no matter the size of the picture */
1057 doPatBlt = FALSE;
1058
1059 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, gspv.hbmWallpaper);
1060
1061 if (gspv.WallpaperMode == wmStretch)
1062 {
1063 if(Rect.right && Rect.bottom)
1064 NtGdiStretchBlt(hDC,
1065 x,
1066 y,
1067 sz.cx,
1068 sz.cy,
1069 hWallpaperDC,
1070 0,
1071 0,
1072 gspv.cxWallpaper,
1073 gspv.cyWallpaper,
1074 SRCCOPY,
1075 0);
1076
1077 }
1078 else if (gspv.WallpaperMode == wmTile)
1079 {
1080 /* Paint the bitmap across the screen then down */
1081 for(y = 0; y < Rect.bottom; y += gspv.cyWallpaper)
1082 {
1083 for(x = 0; x < Rect.right; x += gspv.cxWallpaper)
1084 {
1085 NtGdiBitBlt(hDC,
1086 x,
1087 y,
1088 gspv.cxWallpaper,
1089 gspv.cyWallpaper,
1090 hWallpaperDC,
1091 0,
1092 0,
1093 SRCCOPY,
1094 0,
1095 0);
1096 }
1097 }
1098 }
1099 else
1100 {
1101 NtGdiBitBlt(hDC,
1102 x,
1103 y,
1104 gspv.cxWallpaper,
1105 gspv.cyWallpaper,
1106 hWallpaperDC,
1107 0,
1108 0,
1109 SRCCOPY,
1110 0,
1111 0);
1112 }
1113 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1114 NtGdiDeleteObjectApp(hWallpaperDC);
1115 }
1116 }
1117 }
1118 else
1119 {
1120 /* Black desktop background in Safe Mode */
1121 DesktopBrush = StockObjects[BLACK_BRUSH];
1122 }
1123 /* Back ground is set to none, clear the screen */
1124 if (doPatBlt)
1125 {
1126 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1127 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1128 NtGdiSelectBrush(hDC, PreviousBrush);
1129 }
1130
1131 /*
1132 * Display system version on the desktop background
1133 */
1134
1135 if (g_PaintDesktopVersion || UserGetSystemMetrics(SM_CLEANBOOT))
1136 {
1137 static WCHAR s_wszVersion[256] = {0};
1138 RECTL rect;
1139
1140 if (*s_wszVersion)
1141 {
1142 len = wcslen(s_wszVersion);
1143 }
1144 else
1145 {
1146 len = GetSystemVersionString(s_wszVersion);
1147 }
1148
1149 if (len)
1150 {
1151 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1152 {
1153 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1154 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1155 }
1156
1157 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1158 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1159 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1160
1161 if(!UserGetSystemMetrics(SM_CLEANBOOT))
1162 {
1163 GreExtTextOutW(hDC, rect.right - 16, rect.bottom - 48, 0, NULL, s_wszVersion, len, NULL, 0);
1164 }
1165 else
1166 {
1167 /* Safe Mode */
1168
1169 /* Version information text in top center */
1170 IntGdiSetTextAlign(hDC, TA_CENTER | TA_TOP);
1171 GreExtTextOutW(hDC, (rect.right + rect.left)/2, rect.top + 3, 0, NULL, s_wszVersion, len, NULL, 0);
1172
1173 /* Safe Mode text in corners */
1174 len = wcslen(s_wszSafeMode);
1175 IntGdiSetTextAlign(hDC, TA_LEFT | TA_TOP);
1176 GreExtTextOutW(hDC, rect.left, rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
1177 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_TOP);
1178 GreExtTextOutW(hDC, rect.right, rect.top + 3, 0, NULL, s_wszSafeMode, len, NULL, 0);
1179 IntGdiSetTextAlign(hDC, TA_LEFT | TA_BASELINE);
1180 GreExtTextOutW(hDC, rect.left, rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
1181 IntGdiSetTextAlign(hDC, TA_RIGHT | TA_BASELINE);
1182 GreExtTextOutW(hDC, rect.right, rect.bottom - 5, 0, NULL, s_wszSafeMode, len, NULL, 0);
1183 }
1184
1185 IntGdiSetBkMode(hDC, mode_old);
1186 IntGdiSetTextAlign(hDC, align_old);
1187 IntGdiSetTextColor(hDC, color_old);
1188 }
1189 }
1190 return TRUE;
1191 }
1192
1193 static NTSTATUS
1194 UserInitializeDesktop(PDESKTOP pdesk, PUNICODE_STRING DesktopName, PWINSTATION_OBJECT pwinsta)
1195 {
1196 PVOID DesktopHeapSystemBase = NULL;
1197 ULONG_PTR HeapSize = 400 * 1024;
1198 SIZE_T DesktopInfoSize;
1199 ULONG i;
1200
1201 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk, DesktopName);
1202
1203 RtlZeroMemory(pdesk, sizeof(DESKTOP));
1204
1205 /* Link the desktop with the parent window station */
1206 pdesk->rpwinstaParent = pwinsta;
1207 InsertTailList(&pwinsta->DesktopListHead, &pdesk->ListEntry);
1208
1209 /* Create the desktop heap */
1210 pdesk->hsectionDesktop = NULL;
1211 pdesk->pheapDesktop = UserCreateHeap(&pdesk->hsectionDesktop,
1212 &DesktopHeapSystemBase,
1213 HeapSize);
1214 if (pdesk->pheapDesktop == NULL)
1215 {
1216 ERR("Failed to create desktop heap!\n");
1217 return STATUS_NO_MEMORY;
1218 }
1219
1220 /* Create DESKTOPINFO */
1221 DesktopInfoSize = sizeof(DESKTOPINFO) + DesktopName->Length + sizeof(WCHAR);
1222 pdesk->pDeskInfo = RtlAllocateHeap(pdesk->pheapDesktop,
1223 HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY,
1224 DesktopInfoSize);
1225 if (pdesk->pDeskInfo == NULL)
1226 {
1227 ERR("Failed to create the DESKTOP structure!\n");
1228 return STATUS_NO_MEMORY;
1229 }
1230
1231 /* Initialize the DESKTOPINFO */
1232 pdesk->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1233 pdesk->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1234 RtlCopyMemory(pdesk->pDeskInfo->szDesktopName,
1235 DesktopName->Buffer,
1236 DesktopName->Length + sizeof(WCHAR));
1237 for (i = 0; i < NB_HOOKS; i++)
1238 {
1239 InitializeListHead(&pdesk->pDeskInfo->aphkStart[i]);
1240 }
1241
1242 InitializeListHead(&pdesk->ShellHookWindows);
1243 InitializeListHead(&pdesk->PtiList);
1244
1245 return STATUS_SUCCESS;
1246 }
1247
1248 /* SYSCALLS *******************************************************************/
1249
1250 /*
1251 * NtUserCreateDesktop
1252 *
1253 * Creates a new desktop.
1254 *
1255 * Parameters
1256 * poaAttribs
1257 * Object Attributes.
1258 *
1259 * lpszDesktopDevice
1260 * Name of the device.
1261 *
1262 * pDeviceMode
1263 * Device Mode.
1264 *
1265 * dwFlags
1266 * Interaction flags.
1267 *
1268 * dwDesiredAccess
1269 * Requested type of access.
1270 *
1271 *
1272 * Return Value
1273 * If the function succeeds, the return value is a handle to the newly
1274 * created desktop. If the specified desktop already exists, the function
1275 * succeeds and returns a handle to the existing desktop. When you are
1276 * finished using the handle, call the CloseDesktop function to close it.
1277 * If the function fails, the return value is NULL.
1278 *
1279 * Status
1280 * @implemented
1281 */
1282
1283 HDESK APIENTRY
1284 NtUserCreateDesktop(
1285 POBJECT_ATTRIBUTES ObjectAttributes,
1286 PUNICODE_STRING lpszDesktopDevice,
1287 LPDEVMODEW lpdmw,
1288 DWORD dwFlags,
1289 ACCESS_MASK dwDesiredAccess)
1290 {
1291 PDESKTOP pdesk = NULL;
1292 NTSTATUS Status = STATUS_SUCCESS;
1293 HDESK hdesk;
1294 BOOLEAN Context;
1295 UNICODE_STRING ClassName;
1296 LARGE_STRING WindowName;
1297 BOOL NoHooks = FALSE;
1298 PWND pWnd = NULL;
1299 CREATESTRUCTW Cs;
1300 PTHREADINFO ptiCurrent;
1301 PCLS pcls;
1302
1303 DECLARE_RETURN(HDESK);
1304
1305 TRACE("Enter NtUserCreateDesktop\n");
1306 UserEnterExclusive();
1307
1308 ptiCurrent = PsGetCurrentThreadWin32Thread();
1309 ASSERT(ptiCurrent);
1310 ASSERT(gptiDesktopThread);
1311
1312 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1313 NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
1314 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
1315 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
1316
1317 /*
1318 * Try to open already existing desktop
1319 */
1320 Status = ObOpenObjectByName(
1321 ObjectAttributes,
1322 ExDesktopObjectType,
1323 UserMode,
1324 NULL,
1325 dwDesiredAccess,
1326 (PVOID)&Context,
1327 (HANDLE*)&hdesk);
1328 if (!NT_SUCCESS(Status))
1329 {
1330 ERR("ObOpenObjectByName failed to open/create desktop\n");
1331 SetLastNtError(Status);
1332 RETURN(NULL);
1333 }
1334
1335 /* In case the object was not created (eg if it existed), return now */
1336 if (Context == FALSE)
1337 {
1338 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes->ObjectName);
1339 RETURN( hdesk);
1340 }
1341
1342 /* Reference the desktop */
1343 Status = ObReferenceObjectByHandle(hdesk,
1344 0,
1345 ExDesktopObjectType,
1346 KernelMode,
1347 (PVOID*)&pdesk,
1348 NULL);
1349 if (!NT_SUCCESS(Status))
1350 {
1351 ERR("Failed to reference desktop object\n");
1352 SetLastNtError(Status);
1353 RETURN(NULL);
1354 }
1355
1356 /* Get the desktop window class. The thread desktop does not belong to any desktop
1357 * so the classes created there (including the desktop class) are allocated in the shared heap
1358 * It would cause problems if we used a class that belongs to the caller
1359 */
1360 ClassName.Buffer = WC_DESKTOP;
1361 ClassName.Length = 0;
1362 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
1363 if (pcls == NULL)
1364 {
1365 ASSERT(FALSE);
1366 RETURN(NULL);
1367 }
1368
1369 RtlZeroMemory(&WindowName, sizeof(WindowName));
1370 RtlZeroMemory(&Cs, sizeof(Cs));
1371 Cs.x = UserGetSystemMetrics(SM_XVIRTUALSCREEN),
1372 Cs.y = UserGetSystemMetrics(SM_YVIRTUALSCREEN),
1373 Cs.cx = UserGetSystemMetrics(SM_CXVIRTUALSCREEN),
1374 Cs.cy = UserGetSystemMetrics(SM_CYVIRTUALSCREEN),
1375 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1376 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
1377 Cs.lpszName = (LPCWSTR) &WindowName;
1378 Cs.lpszClass = (LPCWSTR) &ClassName;
1379
1380 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1381 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
1382 if (pWnd == NULL)
1383 {
1384 ERR("Failed to create desktop window for the new desktop\n");
1385 RETURN(NULL);
1386 }
1387
1388 pdesk->dwSessionId = PsGetCurrentProcessSessionId();
1389 pdesk->DesktopWindow = pWnd->head.h;
1390 pdesk->pDeskInfo->spwnd = pWnd;
1391 pWnd->fnid = FNID_DESKTOP;
1392
1393 ClassName.Buffer = MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]);
1394 ClassName.Length = 0;
1395 pcls = IntGetAndReferenceClass(&ClassName, 0, TRUE);
1396 if (pcls == NULL)
1397 {
1398 ASSERT(FALSE);
1399 RETURN(NULL);
1400 }
1401
1402 RtlZeroMemory(&WindowName, sizeof(WindowName));
1403 RtlZeroMemory(&Cs, sizeof(Cs));
1404 Cs.cx = Cs.cy = 100;
1405 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1406 Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
1407 Cs.lpszName = (LPCWSTR) &WindowName;
1408 Cs.lpszClass = (LPCWSTR) &ClassName;
1409 pWnd = IntCreateWindow(&Cs, &WindowName, pcls, NULL, NULL, NULL, pdesk);
1410 if (pWnd == NULL)
1411 {
1412 ERR("Failed to create message window for the new desktop\n");
1413 RETURN(NULL);
1414 }
1415
1416 pdesk->spwndMessage = pWnd;
1417 pWnd->fnid = FNID_MESSAGEWND;
1418
1419 /* Now,,,
1420 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1421 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1422 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1423 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1424 The rest is same as message window.
1425 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1426 */
1427 RETURN( hdesk);
1428
1429 CLEANUP:
1430 if (pdesk != NULL)
1431 {
1432 ObDereferenceObject(pdesk);
1433 }
1434 if (_ret_ == NULL && hdesk != NULL)
1435 {
1436 ObCloseHandle(hdesk, UserMode);
1437 }
1438 if (!NoHooks)
1439 {
1440 ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS;
1441 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
1442 }
1443 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_);
1444 UserLeave();
1445 END_CLEANUP;
1446 }
1447
1448 /*
1449 * NtUserOpenDesktop
1450 *
1451 * Opens an existing desktop.
1452 *
1453 * Parameters
1454 * lpszDesktopName
1455 * Name of the existing desktop.
1456 *
1457 * dwFlags
1458 * Interaction flags.
1459 *
1460 * dwDesiredAccess
1461 * Requested type of access.
1462 *
1463 * Return Value
1464 * Handle to the desktop or zero on failure.
1465 *
1466 * Status
1467 * @implemented
1468 */
1469
1470 HDESK APIENTRY
1471 NtUserOpenDesktop(
1472 POBJECT_ATTRIBUTES ObjectAttributes,
1473 DWORD dwFlags,
1474 ACCESS_MASK dwDesiredAccess)
1475 {
1476 NTSTATUS Status;
1477 HDESK Desktop;
1478
1479 Status = ObOpenObjectByName(
1480 ObjectAttributes,
1481 ExDesktopObjectType,
1482 UserMode,
1483 NULL,
1484 dwDesiredAccess,
1485 NULL,
1486 (HANDLE*)&Desktop);
1487
1488 if (!NT_SUCCESS(Status))
1489 {
1490 ERR("Failed to open desktop\n");
1491 SetLastNtError(Status);
1492 return 0;
1493 }
1494
1495 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes->ObjectName->Buffer, Desktop);
1496
1497 return Desktop;
1498 }
1499
1500 /*
1501 * NtUserOpenInputDesktop
1502 *
1503 * Opens the input (interactive) desktop.
1504 *
1505 * Parameters
1506 * dwFlags
1507 * Interaction flags.
1508 *
1509 * fInherit
1510 * Inheritance option.
1511 *
1512 * dwDesiredAccess
1513 * Requested type of access.
1514 *
1515 * Return Value
1516 * Handle to the input desktop or zero on failure.
1517 *
1518 * Status
1519 * @implemented
1520 */
1521
1522 HDESK APIENTRY
1523 NtUserOpenInputDesktop(
1524 DWORD dwFlags,
1525 BOOL fInherit,
1526 ACCESS_MASK dwDesiredAccess)
1527 {
1528 NTSTATUS Status;
1529 HDESK hdesk = NULL;
1530 ULONG HandleAttributes = 0;
1531
1532 UserEnterExclusive();
1533 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
1534
1535 if(fInherit) HandleAttributes = OBJ_INHERIT;
1536
1537 /* Create a new handle to the object */
1538 Status = ObOpenObjectByPointer(
1539 gpdeskInputDesktop,
1540 HandleAttributes,
1541 NULL,
1542 dwDesiredAccess,
1543 ExDesktopObjectType,
1544 UserMode,
1545 (PHANDLE)&hdesk);
1546
1547 if (!NT_SUCCESS(Status))
1548 {
1549 ERR("Failed to open input desktop object\n");
1550 SetLastNtError(Status);
1551 }
1552
1553 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk);
1554 UserLeave();
1555 return hdesk;
1556 }
1557
1558 /*
1559 * NtUserCloseDesktop
1560 *
1561 * Closes a desktop handle.
1562 *
1563 * Parameters
1564 * hDesktop
1565 * Handle to the desktop.
1566 *
1567 * Return Value
1568 * Status
1569 *
1570 * Remarks
1571 * The desktop handle can be created with NtUserCreateDesktop or
1572 * NtUserOpenDesktop. This function will fail if any thread in the calling
1573 * process is using the specified desktop handle or if the handle refers
1574 * to the initial desktop of the calling process.
1575 *
1576 * Status
1577 * @implemented
1578 */
1579
1580 BOOL APIENTRY
1581 NtUserCloseDesktop(HDESK hDesktop)
1582 {
1583 PDESKTOP pdesk;
1584 NTSTATUS Status;
1585 DECLARE_RETURN(BOOL);
1586
1587 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop);
1588 UserEnterExclusive();
1589
1590 if( hDesktop == gptiCurrent->hdesk || hDesktop == gptiCurrent->ppi->hdeskStartup)
1591 {
1592 ERR("Attempted to close thread desktop\n");
1593 EngSetLastError(ERROR_BUSY);
1594 RETURN(FALSE);
1595 }
1596
1597 Status = IntValidateDesktopHandle( hDesktop, UserMode, 0, &pdesk);
1598 if (!NT_SUCCESS(Status))
1599 {
1600 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop);
1601 RETURN(FALSE);
1602 }
1603
1604 ObDereferenceObject(pdesk);
1605
1606 Status = ZwClose(hDesktop);
1607 if (!NT_SUCCESS(Status))
1608 {
1609 ERR("Failed to close desktop handle 0x%p\n", hDesktop);
1610 SetLastNtError(Status);
1611 RETURN(FALSE);
1612 }
1613
1614 RETURN(TRUE);
1615
1616 CLEANUP:
1617 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1618 UserLeave();
1619 END_CLEANUP;
1620 }
1621
1622 /*
1623 * NtUserPaintDesktop
1624 *
1625 * The NtUserPaintDesktop function fills the clipping region in the
1626 * specified device context with the desktop pattern or wallpaper. The
1627 * function is provided primarily for shell desktops.
1628 *
1629 * Parameters
1630 * hDC
1631 * Handle to the device context.
1632 *
1633 * Status
1634 * @implemented
1635 */
1636
1637 BOOL APIENTRY
1638 NtUserPaintDesktop(HDC hDC)
1639 {
1640 BOOL Ret;
1641 UserEnterExclusive();
1642 TRACE("Enter NtUserPaintDesktop\n");
1643 Ret = IntPaintDesktop(hDC);
1644 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret);
1645 UserLeave();
1646 return Ret;
1647 }
1648
1649 /*
1650 * NtUserSwitchDesktop
1651 *
1652 * Sets the current input (interactive) desktop.
1653 *
1654 * Parameters
1655 * hDesktop
1656 * Handle to desktop.
1657 *
1658 * Return Value
1659 * Status
1660 *
1661 * Status
1662 * @unimplemented
1663 */
1664
1665 BOOL APIENTRY
1666 NtUserSwitchDesktop(HDESK hdesk)
1667 {
1668 PDESKTOP pdesk;
1669 NTSTATUS Status;
1670 BOOL bRedrawDesktop;
1671 DECLARE_RETURN(BOOL);
1672
1673 UserEnterExclusive();
1674 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk);
1675
1676 Status = IntValidateDesktopHandle( hdesk, UserMode, 0, &pdesk);
1677 if (!NT_SUCCESS(Status))
1678 {
1679 ERR("Validation of desktop handle (0x%p) failed\n", hdesk);
1680 RETURN(FALSE);
1681 }
1682
1683 if (PsGetCurrentProcessSessionId() != pdesk->rpwinstaParent->dwSessionId)
1684 {
1685 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1686 RETURN(FALSE);
1687 }
1688
1689 if(pdesk == gpdeskInputDesktop)
1690 {
1691 WARN("NtUserSwitchDesktop called for active desktop\n");
1692 RETURN(TRUE);
1693 }
1694
1695 /*
1696 * Don't allow applications switch the desktop if it's locked, unless the caller
1697 * is the logon application itself
1698 */
1699 if((pdesk->rpwinstaParent->Flags & WSS_LOCKED) &&
1700 LogonProcess != PsGetCurrentProcessWin32Process())
1701 {
1702 ObDereferenceObject(pdesk);
1703 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk);
1704 RETURN(FALSE);
1705 }
1706
1707 if(pdesk->rpwinstaParent != InputWindowStation)
1708 {
1709 ObDereferenceObject(pdesk);
1710 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk);
1711 RETURN(FALSE);
1712 }
1713
1714 /* FIXME: Fail if the process is associated with a secured
1715 desktop such as Winlogon or Screen-Saver */
1716 /* FIXME: Connect to input device */
1717
1718 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop, pdesk);
1719
1720 bRedrawDesktop = FALSE;
1721
1722 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1723 if(gpdeskInputDesktop != NULL)
1724 {
1725 if((gpdeskInputDesktop->pDeskInfo->spwnd->style & WS_VISIBLE) == WS_VISIBLE)
1726 bRedrawDesktop = TRUE;
1727
1728 /* Hide the previous desktop window */
1729 IntHideDesktop(gpdeskInputDesktop);
1730 }
1731
1732 /* Set the active desktop in the desktop's window station. */
1733 InputWindowStation->ActiveDesktop = pdesk;
1734
1735 /* Set the global state. */
1736 gpdeskInputDesktop = pdesk;
1737
1738 /* Show the new desktop window */
1739 co_IntShowDesktop(pdesk, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN), bRedrawDesktop);
1740
1741 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop);
1742 ObDereferenceObject(pdesk);
1743
1744 RETURN(TRUE);
1745
1746 CLEANUP:
1747 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1748 UserLeave();
1749 END_CLEANUP;
1750 }
1751
1752 /*
1753 * NtUserGetThreadDesktop
1754 *
1755 * Status
1756 * @implemented
1757 */
1758
1759 HDESK APIENTRY
1760 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1761 {
1762 NTSTATUS Status;
1763 PETHREAD Thread;
1764 PDESKTOP DesktopObject;
1765 HDESK Ret, hThreadDesktop;
1766 OBJECT_HANDLE_INFORMATION HandleInformation;
1767 DECLARE_RETURN(HDESK);
1768
1769 UserEnterExclusive();
1770 TRACE("Enter NtUserGetThreadDesktop\n");
1771
1772 if(!dwThreadId)
1773 {
1774 EngSetLastError(ERROR_INVALID_PARAMETER);
1775 RETURN(0);
1776 }
1777
1778 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1779 if(!NT_SUCCESS(Status))
1780 {
1781 EngSetLastError(ERROR_INVALID_PARAMETER);
1782 RETURN(0);
1783 }
1784
1785 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1786 {
1787 /* Just return the handle, we queried the desktop handle of a thread running
1788 in the same context */
1789 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1790 ObDereferenceObject(Thread);
1791 RETURN(Ret);
1792 }
1793
1794 /* Get the desktop handle and the desktop of the thread */
1795 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1796 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1797 {
1798 ObDereferenceObject(Thread);
1799 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1800 RETURN(NULL);
1801 }
1802
1803 /* We could just use DesktopObject instead of looking up the handle, but latter
1804 may be a bit safer (e.g. when the desktop is being destroyed */
1805 /* Switch into the context of the thread we're trying to get the desktop from,
1806 so we can use the handle */
1807 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1808 Status = ObReferenceObjectByHandle(hThreadDesktop,
1809 GENERIC_ALL,
1810 ExDesktopObjectType,
1811 UserMode,
1812 (PVOID*)&DesktopObject,
1813 &HandleInformation);
1814 KeDetachProcess();
1815
1816 /* The handle couldn't be found, there's nothing to get... */
1817 if(!NT_SUCCESS(Status))
1818 {
1819 ObDereferenceObject(Thread);
1820 RETURN(NULL);
1821 }
1822
1823 /* Lookup our handle table if we can find a handle to the desktop object,
1824 if not, create one */
1825 Ret = IntGetDesktopObjectHandle(DesktopObject);
1826
1827 /* All done, we got a valid handle to the desktop */
1828 ObDereferenceObject(DesktopObject);
1829 ObDereferenceObject(Thread);
1830 RETURN(Ret);
1831
1832 CLEANUP:
1833 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_);
1834 UserLeave();
1835 END_CLEANUP;
1836 }
1837
1838 static NTSTATUS
1839 IntUnmapDesktopView(IN PDESKTOP pdesk)
1840 {
1841 PPROCESSINFO ppi;
1842 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1843 NTSTATUS Status = STATUS_SUCCESS;
1844
1845 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk);
1846
1847 ppi = PsGetCurrentProcessWin32Process();
1848 PrevLink = &ppi->HeapMappings.Next;
1849
1850 /* Unmap if we're the last thread using the desktop */
1851 HeapMapping = *PrevLink;
1852 while (HeapMapping != NULL)
1853 {
1854 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop)
1855 {
1856 if (--HeapMapping->Count == 0)
1857 {
1858 *PrevLink = HeapMapping->Next;
1859
1860 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi, pdesk);
1861 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1862 HeapMapping->UserMapping);
1863
1864 ObDereferenceObject(pdesk);
1865
1866 UserHeapFree(HeapMapping);
1867 break;
1868 }
1869 }
1870
1871 PrevLink = &HeapMapping->Next;
1872 HeapMapping = HeapMapping->Next;
1873 }
1874
1875 return Status;
1876 }
1877
1878 static NTSTATUS
1879 IntMapDesktopView(IN PDESKTOP pdesk)
1880 {
1881 PPROCESSINFO ppi;
1882 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1883 PVOID UserBase = NULL;
1884 SIZE_T ViewSize = 0;
1885 LARGE_INTEGER Offset;
1886 NTSTATUS Status;
1887
1888 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk);
1889
1890 ppi = PsGetCurrentProcessWin32Process();
1891 PrevLink = &ppi->HeapMappings.Next;
1892
1893 /* Find out if another thread already mapped the desktop heap */
1894 HeapMapping = *PrevLink;
1895 while (HeapMapping != NULL)
1896 {
1897 if (HeapMapping->KernelMapping == (PVOID)pdesk->pheapDesktop)
1898 {
1899 HeapMapping->Count++;
1900 return STATUS_SUCCESS;
1901 }
1902
1903 PrevLink = &HeapMapping->Next;
1904 HeapMapping = HeapMapping->Next;
1905 }
1906
1907 /* We're the first, map the heap */
1908 Offset.QuadPart = 0;
1909 Status = MmMapViewOfSection(pdesk->hsectionDesktop,
1910 PsGetCurrentProcess(),
1911 &UserBase,
1912 0,
1913 0,
1914 &Offset,
1915 &ViewSize,
1916 ViewUnmap,
1917 SEC_NO_CHANGE,
1918 PAGE_EXECUTE_READ); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1919 if (!NT_SUCCESS(Status))
1920 {
1921 ERR("Failed to map desktop\n");
1922 return Status;
1923 }
1924
1925 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi, pdesk);
1926
1927 /* Add the mapping */
1928 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1929 if (HeapMapping == NULL)
1930 {
1931 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase);
1932 ERR("UserHeapAlloc() failed!\n");
1933 return STATUS_NO_MEMORY;
1934 }
1935
1936 HeapMapping->Next = NULL;
1937 HeapMapping->KernelMapping = (PVOID)pdesk->pheapDesktop;
1938 HeapMapping->UserMapping = UserBase;
1939 HeapMapping->Limit = ViewSize;
1940 HeapMapping->Count = 1;
1941 *PrevLink = HeapMapping;
1942
1943 ObReferenceObject(pdesk);
1944
1945 return STATUS_SUCCESS;
1946 }
1947
1948 BOOL
1949 IntSetThreadDesktop(IN HDESK hDesktop,
1950 IN BOOL FreeOnFailure)
1951 {
1952 PDESKTOP pdesk = NULL, pdeskOld;
1953 HDESK hdeskOld;
1954 PTHREADINFO pti;
1955 NTSTATUS Status;
1956 PCLIENTTHREADINFO pctiOld, pctiNew = NULL;
1957 PCLIENTINFO pci;
1958
1959 ASSERT(NtCurrentTeb());
1960
1961 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop, FreeOnFailure);
1962
1963 pti = PsGetCurrentThreadWin32Thread();
1964 pci = pti->pClientInfo;
1965
1966 /* If the caller gave us a desktop, ensure it is valid */
1967 if(hDesktop != NULL)
1968 {
1969 /* Validate the new desktop. */
1970 Status = IntValidateDesktopHandle( hDesktop, UserMode, 0, &pdesk);
1971 if (!NT_SUCCESS(Status))
1972 {
1973 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop);
1974 return FALSE;
1975 }
1976
1977 if (pti->rpdesk == pdesk)
1978 {
1979 /* Nothing to do */
1980 ObDereferenceObject(pdesk);
1981 return TRUE;
1982 }
1983 }
1984
1985 /* Make sure that we don't own any window in the current desktop */
1986 if (!IsListEmpty(&pti->WindowListHead))
1987 {
1988 if(pdesk)
1989 ObDereferenceObject(pdesk);
1990 ERR("Attempted to change thread desktop although the thread has windows!\n");
1991 EngSetLastError(ERROR_BUSY);
1992 return FALSE;
1993 }
1994
1995 /* Desktop is being re-set so clear out foreground. */
1996 if (pti->rpdesk != pdesk && pti->MessageQueue == gpqForeground)
1997 {
1998 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
1999 IntSetFocusMessageQueue(NULL);
2000 }
2001
2002 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
2003 if(pdesk != NULL)
2004 {
2005 Status = IntMapDesktopView(pdesk);
2006 if (!NT_SUCCESS(Status))
2007 {
2008 ERR("Failed to map desktop heap!\n");
2009 ObDereferenceObject(pdesk);
2010 SetLastNtError(Status);
2011 return FALSE;
2012 }
2013
2014 pctiNew = DesktopHeapAlloc( pdesk, sizeof(CLIENTTHREADINFO));
2015 if(pctiNew == NULL)
2016 {
2017 ERR("Failed to allocate new pcti\n");
2018 IntUnmapDesktopView(pdesk);
2019 ObDereferenceObject(pdesk);
2020 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2021 return FALSE;
2022 }
2023 }
2024
2025 /* free all classes or move them to the shared heap */
2026 if(pti->rpdesk != NULL)
2027 {
2028 if(!IntCheckProcessDesktopClasses(pti->rpdesk, FreeOnFailure))
2029 {
2030 ERR("Failed to move process classes to shared heap!\n");
2031 if(pdesk)
2032 {
2033 DesktopHeapFree(pdesk, pctiNew);
2034 IntUnmapDesktopView(pdesk);
2035 ObDereferenceObject(pdesk);
2036 }
2037 return FALSE;
2038 }
2039 }
2040
2041 pdeskOld = pti->rpdesk;
2042 hdeskOld = pti->hdesk;
2043 if (pti->pcti != &pti->cti)
2044 pctiOld = pti->pcti;
2045 else
2046 pctiOld = NULL;
2047
2048 /* do the switch */
2049 if(pdesk != NULL)
2050 {
2051 pti->rpdesk = pdesk;
2052 pti->hdesk = hDesktop;
2053 pti->pDeskInfo = pti->rpdesk->pDeskInfo;
2054 pti->pcti = pctiNew;
2055
2056 pci->ulClientDelta = DesktopHeapGetUserDelta();
2057 pci->pDeskInfo = (PVOID)((ULONG_PTR)pti->pDeskInfo - pci->ulClientDelta);
2058 pci->pClientThreadInfo = (PVOID)((ULONG_PTR)pti->pcti - pci->ulClientDelta);
2059
2060 /* initialize the new pcti */
2061 if(pctiOld != NULL)
2062 {
2063 RtlCopyMemory(pctiNew, pctiOld, sizeof(CLIENTTHREADINFO));
2064 }
2065 else
2066 {
2067 RtlZeroMemory(pctiNew, sizeof(CLIENTTHREADINFO));
2068 pci->fsHooks = pti->fsHooks;
2069 pci->dwTIFlags = pti->TIF_flags;
2070 }
2071 }
2072 else
2073 {
2074 pti->rpdesk = NULL;
2075 pti->hdesk = NULL;
2076 pti->pDeskInfo = NULL;
2077 pti->pcti = &pti->cti; // Always point inside so there will be no crash when posting or sending msg's!
2078 pci->ulClientDelta = 0;
2079 pci->pDeskInfo = NULL;
2080 pci->pClientThreadInfo = NULL;
2081 }
2082
2083 /* clean up the old desktop */
2084 if(pdeskOld != NULL)
2085 {
2086 RemoveEntryList(&pti->PtiLink);
2087 if (pctiOld) DesktopHeapFree(pdeskOld, pctiOld);
2088 IntUnmapDesktopView(pdeskOld);
2089 ObDereferenceObject(pdeskOld);
2090 ZwClose(hdeskOld);
2091 }
2092
2093 if(pdesk)
2094 {
2095 InsertTailList(&pdesk->PtiList, &pti->PtiLink);
2096 }
2097
2098 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti, pti->ppi, pdeskOld, pdesk);
2099
2100 return TRUE;
2101 }
2102
2103 /*
2104 * NtUserSetThreadDesktop
2105 *
2106 * Status
2107 * @implemented
2108 */
2109
2110 BOOL APIENTRY
2111 NtUserSetThreadDesktop(HDESK hDesktop)
2112 {
2113 BOOL ret = FALSE;
2114
2115 UserEnterExclusive();
2116
2117 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2118 // here too and set the NT error level. Q. Is it necessary to have the validation
2119 // in IntSetThreadDesktop? Is it needed there too?
2120 if (hDesktop || (!hDesktop && PsGetCurrentProcess() == gpepCSRSS))
2121 ret = IntSetThreadDesktop(hDesktop, FALSE);
2122
2123 UserLeave();
2124
2125 return ret;
2126 }
2127
2128 /* EOF */