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