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