[YAROTOWS] Reintegrate the branch. For a brighter future.
[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 <win32k.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->rpwinstaParent = (PWINSTATION_OBJECT)ParseObject;
148
149 /* Put the desktop on the window station's list of associated desktops */
150 InsertTailList(&Desktop->rpwinstaParent->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 PDESKTOP FASTCALL
423 IntGetActiveDesktop(VOID)
424 {
425 return InputDesktop;
426 }
427
428 /*
429 * returns or creates a handle to the desktop object
430 */
431 HDESK FASTCALL
432 IntGetDesktopObjectHandle(PDESKTOP DesktopObject)
433 {
434 NTSTATUS Status;
435 HDESK Ret;
436
437 ASSERT(DesktopObject);
438
439 if (!ObFindHandleForObject(PsGetCurrentProcess(),
440 DesktopObject,
441 ExDesktopObjectType,
442 NULL,
443 (PHANDLE)&Ret))
444 {
445 Status = ObOpenObjectByPointer(DesktopObject,
446 0,
447 NULL,
448 0,
449 ExDesktopObjectType,
450 UserMode,
451 (PHANDLE)&Ret);
452 if(!NT_SUCCESS(Status))
453 {
454 /* unable to create a handle */
455 DPRINT1("Unable to create a desktop handle\n");
456 return NULL;
457 }
458 }
459 else
460 {
461 DPRINT1("Got handle: %lx\n", Ret);
462 }
463
464 return Ret;
465 }
466
467 PUSER_MESSAGE_QUEUE FASTCALL
468 IntGetFocusMessageQueue(VOID)
469 {
470 PDESKTOP pdo = IntGetActiveDesktop();
471 if (!pdo)
472 {
473 DPRINT("No active desktop\n");
474 return(NULL);
475 }
476 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
477 }
478
479 VOID FASTCALL
480 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
481 {
482 PUSER_MESSAGE_QUEUE Old;
483 PDESKTOP pdo = IntGetActiveDesktop();
484 if (!pdo)
485 {
486 DPRINT("No active desktop\n");
487 return;
488 }
489 if(NewQueue != NULL)
490 {
491 if(NewQueue->Desktop != NULL)
492 {
493 DPRINT("Message Queue already attached to another desktop!\n");
494 return;
495 }
496 IntReferenceMessageQueue(NewQueue);
497 (void)InterlockedExchangePointer((PVOID*)&NewQueue->Desktop, pdo);
498 }
499 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchangePointer((PVOID*)&pdo->ActiveMessageQueue, NewQueue);
500 if(Old != NULL)
501 {
502 (void)InterlockedExchangePointer((PVOID*)&Old->Desktop, 0);
503 IntDereferenceMessageQueue(Old);
504 }
505 }
506
507 HWND FASTCALL IntGetDesktopWindow(VOID)
508 {
509 PDESKTOP pdo = IntGetActiveDesktop();
510 if (!pdo)
511 {
512 DPRINT("No active desktop\n");
513 return NULL;
514 }
515 return pdo->DesktopWindow;
516 }
517
518 PWND FASTCALL UserGetDesktopWindow(VOID)
519 {
520 PDESKTOP pdo = IntGetActiveDesktop();
521
522 if (!pdo)
523 {
524 DPRINT("No active desktop\n");
525 return NULL;
526 }
527
528 return UserGetWindowObject(pdo->DesktopWindow);
529 }
530
531 HWND FASTCALL IntGetMessageWindow(VOID)
532 {
533 PDESKTOP pdo = IntGetActiveDesktop();
534
535 if (!pdo)
536 {
537 DPRINT("No active desktop\n");
538 return NULL;
539 }
540 return pdo->spwndMessage->head.h;
541 }
542
543 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
544 {
545 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
546 PDESKTOP pdo = pti->rpdesk;
547 if (NULL == pdo)
548 {
549 DPRINT1("Thread doesn't have a desktop\n");
550 return NULL;
551 }
552 return pdo->DesktopWindow;
553 }
554
555 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
556 {
557 if (bEnable)
558 {
559 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
560 NTSTATUS Status;
561
562 RtlZeroMemory(QueryTable, sizeof(QueryTable));
563
564 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
565 QueryTable[0].Name = L"PaintDesktopVersion";
566 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
567
568 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
569 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
570 L"Control Panel\\Desktop",
571 QueryTable, NULL, NULL);
572 if (!NT_SUCCESS(Status))
573 {
574 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
575 Status);
576 g_PaintDesktopVersion = FALSE;
577 return FALSE;
578 }
579
580 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
581
582 return TRUE;
583 }
584 else
585 {
586 g_PaintDesktopVersion = FALSE;
587 return TRUE;
588 }
589 }
590
591 /* PUBLIC FUNCTIONS ***********************************************************/
592
593 HDC FASTCALL
594 UserGetDesktopDC(ULONG DcType, BOOL EmptyDC, BOOL ValidatehWnd)
595 {
596 PWND DesktopObject = 0;
597 HDC DesktopHDC = 0;
598
599 if (DcType == DC_TYPE_DIRECT)
600 {
601 DesktopObject = UserGetDesktopWindow();
602 DesktopHDC = (HDC)UserGetWindowDC(DesktopObject);
603 }
604 else
605 {
606 HDEV hDev;
607 hDev = (HDEV)pPrimarySurface;
608 DesktopHDC = IntGdiCreateDisplayDC(hDev, DcType, EmptyDC);
609 }
610
611 return DesktopHDC;
612 }
613
614 VOID APIENTRY
615 UserRedrawDesktop()
616 {
617 PWND Window = NULL;
618
619 Window = UserGetDesktopWindow();
620
621 IntInvalidateWindows( Window,
622 Window->hrgnUpdate,
623 RDW_FRAME |
624 RDW_ERASE |
625 RDW_INVALIDATE |
626 RDW_ALLCHILDREN);
627 }
628
629
630 NTSTATUS FASTCALL
631 co_IntShowDesktop(PDESKTOP Desktop, ULONG Width, ULONG Height)
632 {
633 CSR_API_MESSAGE Request;
634
635 Request.Type = MAKE_CSR_API(SHOW_DESKTOP, CSR_GUI);
636 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
637 Request.Data.ShowDesktopRequest.Width = Width;
638 Request.Data.ShowDesktopRequest.Height = Height;
639
640 return co_CsrNotify(&Request);
641 }
642
643 NTSTATUS FASTCALL
644 IntHideDesktop(PDESKTOP Desktop)
645 {
646 #if 0
647 CSRSS_API_REQUEST Request;
648 CSRSS_API_REPLY Reply;
649
650 Request.Type = CSRSS_HIDE_DESKTOP;
651 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
652
653 return NotifyCsrss(&Request, &Reply);
654 #else
655
656 PWND DesktopWnd;
657
658 DesktopWnd = IntGetWindowObject(Desktop->DesktopWindow);
659 if (! DesktopWnd)
660 {
661 return ERROR_INVALID_WINDOW_HANDLE;
662 }
663 DesktopWnd->style &= ~WS_VISIBLE;
664
665 return STATUS_SUCCESS;
666 #endif
667 }
668
669
670
671
672 static
673 HWND* FASTCALL
674 UserBuildShellHookHwndList(PDESKTOP Desktop)
675 {
676 ULONG entries=0;
677 PSHELL_HOOK_WINDOW Current;
678 HWND* list;
679
680 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
681 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
682 entries++;
683
684 if (!entries) return NULL;
685
686 list = ExAllocatePoolWithTag(PagedPool, sizeof(HWND) * (entries + 1), USERTAG_WINDOWLIST); /* alloc one extra for nullterm */
687 if (list)
688 {
689 HWND* cursor = list;
690
691 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
692 *cursor++ = Current->hWnd;
693
694 *cursor = NULL; /* nullterm list */
695 }
696
697 return list;
698 }
699
700 /*
701 * Send the Message to the windows registered for ShellHook
702 * notifications. The lParam contents depend on the Message. See
703 * MSDN for more details (RegisterShellHookWindow)
704 */
705 VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
706 {
707 PDESKTOP Desktop = IntGetActiveDesktop();
708 HWND* HwndList;
709
710 static UINT MsgType = 0;
711
712 if (!MsgType)
713 {
714
715 /* Too bad, this doesn't work.*/
716 #if 0
717 UNICODE_STRING Str;
718 RtlInitUnicodeString(&Str, L"SHELLHOOK");
719 MsgType = UserRegisterWindowMessage(&Str);
720 #endif
721
722 MsgType = IntAddAtom(L"SHELLHOOK");
723
724 DPRINT("MsgType = %x\n", MsgType);
725 if (!MsgType)
726 DPRINT1("LastError: %x\n", GetLastNtError());
727 }
728
729 if (!Desktop)
730 {
731 DPRINT("IntShellHookNotify: No desktop!\n");
732 return;
733 }
734
735 HwndList = UserBuildShellHookHwndList(Desktop);
736 if (HwndList)
737 {
738 HWND* cursor = HwndList;
739
740 for (; *cursor; cursor++)
741 {
742 DPRINT("Sending notify\n");
743 co_IntPostOrSendMessage(*cursor,
744 MsgType,
745 Message,
746 lParam);
747 }
748
749 ExFreePool(HwndList);
750 }
751
752 }
753
754 /*
755 * Add the window to the ShellHookWindows list. The windows
756 * on that list get notifications that are important to shell
757 * type applications.
758 *
759 * TODO: Validate the window? I'm not sure if sending these messages to
760 * an unsuspecting application that is not your own is a nice thing to do.
761 */
762 BOOL IntRegisterShellHookWindow(HWND hWnd)
763 {
764 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
765 PDESKTOP Desktop = pti->rpdesk;
766 PSHELL_HOOK_WINDOW Entry;
767
768 DPRINT("IntRegisterShellHookWindow\n");
769
770 /* First deregister the window, so we can be sure it's never twice in the
771 * list.
772 */
773 IntDeRegisterShellHookWindow(hWnd);
774
775 Entry = ExAllocatePoolWithTag(PagedPool,
776 sizeof(SHELL_HOOK_WINDOW),
777 TAG_WINSTA);
778
779 if (!Entry)
780 return FALSE;
781
782 Entry->hWnd = hWnd;
783
784 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
785
786 return TRUE;
787 }
788
789 /*
790 * Remove the window from the ShellHookWindows list. The windows
791 * on that list get notifications that are important to shell
792 * type applications.
793 */
794 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
795 {
796 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
797 PDESKTOP Desktop = pti->rpdesk;
798 PSHELL_HOOK_WINDOW Current;
799
800 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
801 {
802 if (Current->hWnd == hWnd)
803 {
804 RemoveEntryList(&Current->ListEntry);
805 ExFreePool(Current);
806 return TRUE;
807 }
808 }
809
810 return FALSE;
811 }
812
813 static VOID
814 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop)
815 {
816 if (Desktop->hsectionDesktop != NULL)
817 {
818 ObDereferenceObject(Desktop->hsectionDesktop);
819 Desktop->hsectionDesktop = NULL;
820 }
821 }
822 /* SYSCALLS *******************************************************************/
823
824 /*
825 * NtUserCreateDesktop
826 *
827 * Creates a new desktop.
828 *
829 * Parameters
830 * poaAttribs
831 * Object Attributes.
832 *
833 * lpszDesktopDevice
834 * Name of the device.
835 *
836 * pDeviceMode
837 * Device Mode.
838 *
839 * dwFlags
840 * Interaction flags.
841 *
842 * dwDesiredAccess
843 * Requested type of access.
844 *
845 *
846 * Return Value
847 * If the function succeeds, the return value is a handle to the newly
848 * created desktop. If the specified desktop already exists, the function
849 * succeeds and returns a handle to the existing desktop. When you are
850 * finished using the handle, call the CloseDesktop function to close it.
851 * If the function fails, the return value is NULL.
852 *
853 * Status
854 * @implemented
855 */
856
857 HDESK APIENTRY
858 NtUserCreateDesktop(
859 POBJECT_ATTRIBUTES poa,
860 PUNICODE_STRING lpszDesktopDevice,
861 LPDEVMODEW lpdmw,
862 DWORD dwFlags,
863 ACCESS_MASK dwDesiredAccess)
864 {
865 OBJECT_ATTRIBUTES ObjectAttributes;
866 PTHREADINFO W32Thread;
867 PWINSTATION_OBJECT WinStaObject;
868 PDESKTOP DesktopObject;
869 UNICODE_STRING DesktopName;
870 NTSTATUS Status = STATUS_SUCCESS;
871 HDESK Desktop;
872 CSR_API_MESSAGE Request;
873 PVOID DesktopHeapSystemBase = NULL;
874 SIZE_T DesktopInfoSize;
875 UNICODE_STRING SafeDesktopName;
876 ULONG DummyContext;
877 ULONG_PTR HeapSize = 4 * 1024 * 1024; /* FIXME */
878 HWINSTA hWindowStation = NULL ;
879 PUNICODE_STRING lpszDesktopName = NULL;
880 UNICODE_STRING ClassName, MenuName;
881 LARGE_STRING WindowName;
882 PWND pWnd = NULL;
883 CREATESTRUCTW Cs;
884 INT i;
885 DECLARE_RETURN(HDESK);
886
887 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
888 UserEnterExclusive();
889
890 _SEH2_TRY
891 {
892 ProbeForRead( poa,
893 sizeof(OBJECT_ATTRIBUTES),
894 1);
895
896 hWindowStation = poa->RootDirectory;
897 lpszDesktopName = poa->ObjectName;
898 }
899 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
900 {
901 Status =_SEH2_GetExceptionCode();
902 }
903 _SEH2_END
904
905 if (! NT_SUCCESS(Status))
906 {
907 DPRINT1("Failed reading Object Attributes from user space.\n");
908 SetLastNtError(Status);
909 RETURN( NULL);
910 }
911
912 Status = IntValidateWindowStationHandle(
913 hWindowStation,
914 KernelMode,
915 0, /* FIXME - WINSTA_CREATEDESKTOP */
916 &WinStaObject);
917
918 if (! NT_SUCCESS(Status))
919 {
920 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
921 hWindowStation, lpszDesktopName);
922 SetLastNtError(Status);
923 RETURN( NULL);
924 }
925 if(lpszDesktopName != NULL)
926 {
927 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
928 if(!NT_SUCCESS(Status))
929 {
930 SetLastNtError(Status);
931 RETURN( NULL);
932 }
933 }
934 else
935 {
936 RtlInitUnicodeString(&SafeDesktopName, NULL);
937 }
938
939 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
940 &SafeDesktopName))
941 {
942 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
943 ObDereferenceObject(WinStaObject);
944 if (lpszDesktopName)
945 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
946 RETURN( NULL);
947 }
948 if (lpszDesktopName)
949 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
950 ObDereferenceObject(WinStaObject);
951
952 /*
953 * Try to open already existing desktop
954 */
955
956 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
957
958 /* Initialize ObjectAttributes for the desktop object */
959 InitializeObjectAttributes(
960 &ObjectAttributes,
961 &DesktopName,
962 0,
963 NULL,
964 NULL);
965
966 Status = ObOpenObjectByName(
967 &ObjectAttributes,
968 ExDesktopObjectType,
969 KernelMode,
970 NULL,
971 dwDesiredAccess,
972 (PVOID)&DummyContext,
973 (HANDLE*)&Desktop);
974 if (!NT_SUCCESS(Status)) RETURN(NULL);
975 if (Status == STATUS_OBJECT_NAME_EXISTS)
976 {
977 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
978 RETURN( Desktop);
979 }
980
981 /* Reference the desktop */
982 Status = ObReferenceObjectByHandle(Desktop,
983 0,
984 ExDesktopObjectType,
985 KernelMode,
986 (PVOID)&DesktopObject,
987 NULL);
988 if (!NT_SUCCESS(Status)) RETURN(NULL);
989
990 DesktopObject->hsectionDesktop = NULL;
991 DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
992 &DesktopHeapSystemBase,
993 HeapSize);
994 if (DesktopObject->pheapDesktop == NULL)
995 {
996 ObDereferenceObject(DesktopObject);
997 DPRINT1("Failed to create desktop heap!\n");
998 RETURN(NULL);
999 }
1000
1001 DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
1002 szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
1003
1004 DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
1005 HEAP_NO_SERIALIZE,
1006 DesktopInfoSize);
1007
1008 if (DesktopObject->pDeskInfo == NULL)
1009 {
1010 ObDereferenceObject(DesktopObject);
1011 DPRINT1("Failed to create the DESKTOP structure!\n");
1012 RETURN(NULL);
1013 }
1014
1015 RtlZeroMemory(DesktopObject->pDeskInfo,
1016 DesktopInfoSize);
1017
1018 DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1019 DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1020 RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
1021 lpszDesktopName->Buffer,
1022 lpszDesktopName->Length);
1023
1024 /* Initialize some local (to win32k) desktop state. */
1025 InitializeListHead(&DesktopObject->PtiList);
1026 DesktopObject->ActiveMessageQueue = NULL;
1027 /* Setup Global Hooks. */
1028 for (i = 0; i < NB_HOOKS; i++)
1029 {
1030 InitializeListHead(&DesktopObject->pDeskInfo->aphkStart[i]);
1031 }
1032 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
1033
1034 if (! NT_SUCCESS(Status))
1035 {
1036 DPRINT1("Failed to create desktop handle\n");
1037 SetLastNtError(Status);
1038 RETURN( NULL);
1039 }
1040
1041 /*
1042 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1043 *
1044 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1045 * to function at the beginning of the project by ramroding the GUI into
1046 * operation and making the desktop window work from user space.
1047 * (jt)
1048 */
1049 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
1050 Status = CsrInsertObject(Desktop,
1051 GENERIC_ALL,
1052 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
1053 if (! NT_SUCCESS(Status))
1054 {
1055 DPRINT1("Failed to create desktop handle for CSRSS\n");
1056 ZwClose(Desktop);
1057 SetLastNtError(Status);
1058 RETURN( NULL);
1059 }
1060
1061 Status = co_CsrNotify(&Request);
1062 if (! NT_SUCCESS(Status))
1063 {
1064 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
1065 DPRINT1("Failed to notify CSRSS about new desktop\n");
1066 ZwClose(Desktop);
1067 SetLastNtError(Status);
1068 RETURN( NULL);
1069 }
1070
1071 W32Thread = PsGetCurrentThreadWin32Thread();
1072
1073 if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
1074
1075 /*
1076 Based on wine/server/window.c in get_desktop_window.
1077 */
1078
1079 ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
1080 ClassName.Length = 0;
1081 RtlZeroMemory(&MenuName, sizeof(MenuName));
1082 RtlZeroMemory(&WindowName, sizeof(WindowName));
1083
1084 RtlZeroMemory(&Cs, sizeof(Cs));
1085 Cs.cx = Cs.cy = 100;
1086 Cs.style = WS_POPUP|WS_CLIPCHILDREN;
1087 Cs.hInstance = hModClient;
1088 Cs.lpszName = (LPCWSTR) &WindowName;
1089 Cs.lpszClass = (LPCWSTR) &ClassName;
1090
1091 pWnd = co_UserCreateWindowEx(&Cs, &ClassName, &WindowName);
1092 if (!pWnd)
1093 {
1094 DPRINT1("Failed to create Message window handle\n");
1095 }
1096 else
1097 {
1098 DesktopObject->spwndMessage = pWnd;
1099 }
1100
1101 RETURN( Desktop);
1102
1103 CLEANUP:
1104 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
1105 UserLeave();
1106 END_CLEANUP;
1107 }
1108
1109 /*
1110 * NtUserOpenDesktop
1111 *
1112 * Opens an existing desktop.
1113 *
1114 * Parameters
1115 * lpszDesktopName
1116 * Name of the existing desktop.
1117 *
1118 * dwFlags
1119 * Interaction flags.
1120 *
1121 * dwDesiredAccess
1122 * Requested type of access.
1123 *
1124 * Return Value
1125 * Handle to the desktop or zero on failure.
1126 *
1127 * Status
1128 * @implemented
1129 */
1130
1131 HDESK APIENTRY
1132 NtUserOpenDesktop(
1133 PUNICODE_STRING lpszDesktopName,
1134 DWORD dwFlags,
1135 ACCESS_MASK dwDesiredAccess)
1136 {
1137 OBJECT_ATTRIBUTES ObjectAttributes;
1138 HWINSTA WinSta;
1139 PWINSTATION_OBJECT WinStaObject;
1140 UNICODE_STRING DesktopName;
1141 UNICODE_STRING SafeDesktopName;
1142 NTSTATUS Status;
1143 HDESK Desktop;
1144 BOOL Result;
1145 DECLARE_RETURN(HDESK);
1146
1147 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
1148 UserEnterExclusive();
1149
1150 /*
1151 * Validate the window station handle and compose the fully
1152 * qualified desktop name
1153 */
1154
1155 WinSta = UserGetProcessWindowStation();
1156 Status = IntValidateWindowStationHandle(
1157 WinSta,
1158 KernelMode,
1159 0,
1160 &WinStaObject);
1161
1162 if (!NT_SUCCESS(Status))
1163 {
1164 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
1165 SetLastNtError(Status);
1166 RETURN( 0);
1167 }
1168
1169 if(lpszDesktopName != NULL)
1170 {
1171 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
1172 if(!NT_SUCCESS(Status))
1173 {
1174 SetLastNtError(Status);
1175 RETURN( NULL);
1176 }
1177 }
1178 else
1179 {
1180 RtlInitUnicodeString(&SafeDesktopName, NULL);
1181 }
1182
1183 Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
1184 &SafeDesktopName);
1185
1186 if (lpszDesktopName)
1187 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
1188 ObDereferenceObject(WinStaObject);
1189
1190
1191 if (!Result)
1192 {
1193 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1194 RETURN( 0);
1195 }
1196
1197
1198 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
1199
1200 /* Initialize ObjectAttributes for the desktop object */
1201 InitializeObjectAttributes(
1202 &ObjectAttributes,
1203 &DesktopName,
1204 0,
1205 NULL,
1206 NULL);
1207
1208 Status = ObOpenObjectByName(
1209 &ObjectAttributes,
1210 ExDesktopObjectType,
1211 KernelMode,
1212 NULL,
1213 dwDesiredAccess,
1214 NULL,
1215 (HANDLE*)&Desktop);
1216
1217 if (!NT_SUCCESS(Status))
1218 {
1219 SetLastNtError(Status);
1220 ExFreePool(DesktopName.Buffer);
1221 RETURN( 0);
1222 }
1223
1224 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1225 ExFreePool(DesktopName.Buffer);
1226
1227 RETURN( Desktop);
1228
1229 CLEANUP:
1230 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1231 UserLeave();
1232 END_CLEANUP;
1233 }
1234
1235 /*
1236 * NtUserOpenInputDesktop
1237 *
1238 * Opens the input (interactive) desktop.
1239 *
1240 * Parameters
1241 * dwFlags
1242 * Interaction flags.
1243 *
1244 * fInherit
1245 * Inheritance option.
1246 *
1247 * dwDesiredAccess
1248 * Requested type of access.
1249 *
1250 * Return Value
1251 * Handle to the input desktop or zero on failure.
1252 *
1253 * Status
1254 * @implemented
1255 */
1256
1257 HDESK APIENTRY
1258 NtUserOpenInputDesktop(
1259 DWORD dwFlags,
1260 BOOL fInherit,
1261 ACCESS_MASK dwDesiredAccess)
1262 {
1263 PDESKTOP Object;
1264 NTSTATUS Status;
1265 HDESK Desktop;
1266 DECLARE_RETURN(HDESK);
1267
1268 DPRINT("Enter NtUserOpenInputDesktop\n");
1269 UserEnterExclusive();
1270
1271 DPRINT("About to open input desktop\n");
1272
1273 /* Get a pointer to the desktop object */
1274
1275 Status = IntValidateDesktopHandle(
1276 InputDesktopHandle,
1277 UserMode,
1278 0,
1279 &Object);
1280
1281 if (!NT_SUCCESS(Status))
1282 {
1283 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1284 RETURN((HDESK)0);
1285 }
1286
1287 /* Create a new handle to the object */
1288
1289 Status = ObOpenObjectByPointer(
1290 Object,
1291 0,
1292 NULL,
1293 dwDesiredAccess,
1294 ExDesktopObjectType,
1295 UserMode,
1296 (HANDLE*)&Desktop);
1297
1298 ObDereferenceObject(Object);
1299
1300 if (NT_SUCCESS(Status))
1301 {
1302 DPRINT("Successfully opened input desktop\n");
1303 RETURN((HDESK)Desktop);
1304 }
1305
1306 SetLastNtError(Status);
1307 RETURN((HDESK)0);
1308
1309 CLEANUP:
1310 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1311 UserLeave();
1312 END_CLEANUP;
1313 }
1314
1315 /*
1316 * NtUserCloseDesktop
1317 *
1318 * Closes a desktop handle.
1319 *
1320 * Parameters
1321 * hDesktop
1322 * Handle to the desktop.
1323 *
1324 * Return Value
1325 * Status
1326 *
1327 * Remarks
1328 * The desktop handle can be created with NtUserCreateDesktop or
1329 * NtUserOpenDesktop. This function will fail if any thread in the calling
1330 * process is using the specified desktop handle or if the handle refers
1331 * to the initial desktop of the calling process.
1332 *
1333 * Status
1334 * @implemented
1335 */
1336
1337 BOOL APIENTRY
1338 NtUserCloseDesktop(HDESK hDesktop)
1339 {
1340 PDESKTOP Object;
1341 NTSTATUS Status;
1342 DECLARE_RETURN(BOOL);
1343
1344 DPRINT("Enter NtUserCloseDesktop\n");
1345 UserEnterExclusive();
1346
1347 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1348
1349 Status = IntValidateDesktopHandle(
1350 hDesktop,
1351 UserMode,
1352 0,
1353 &Object);
1354
1355 if (!NT_SUCCESS(Status))
1356 {
1357 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1358 RETURN(FALSE);
1359 }
1360
1361 ObDereferenceObject(Object);
1362
1363 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1364
1365 Status = ZwClose(hDesktop);
1366 if (!NT_SUCCESS(Status))
1367 {
1368 SetLastNtError(Status);
1369 RETURN(FALSE);
1370 }
1371
1372 RETURN(TRUE);
1373
1374 CLEANUP:
1375 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1376 UserLeave();
1377 END_CLEANUP;
1378 }
1379
1380
1381
1382
1383 /*
1384 * NtUserPaintDesktop
1385 *
1386 * The NtUserPaintDesktop function fills the clipping region in the
1387 * specified device context with the desktop pattern or wallpaper. The
1388 * function is provided primarily for shell desktops.
1389 *
1390 * Parameters
1391 * hDC
1392 * Handle to the device context.
1393 *
1394 * Status
1395 * @implemented
1396 */
1397
1398 BOOL APIENTRY
1399 NtUserPaintDesktop(HDC hDC)
1400 {
1401 RECTL Rect;
1402 HBRUSH DesktopBrush, PreviousBrush;
1403 HWND hWndDesktop;
1404 BOOL doPatBlt = TRUE;
1405 PWND WndDesktop;
1406 int len;
1407 COLORREF color_old;
1408 UINT align_old;
1409 int mode_old;
1410 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1411 PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
1412 DECLARE_RETURN(BOOL);
1413
1414 UserEnterExclusive();
1415 DPRINT("Enter NtUserPaintDesktop\n");
1416
1417 GdiGetClipBox(hDC, &Rect);
1418
1419 hWndDesktop = IntGetDesktopWindow();
1420
1421 WndDesktop = UserGetWindowObject(hWndDesktop);
1422 if (!WndDesktop)
1423 {
1424 RETURN(FALSE);
1425 }
1426
1427 DesktopBrush = (HBRUSH)WndDesktop->pcls->hbrBackground;
1428
1429
1430 /*
1431 * Paint desktop background
1432 */
1433
1434 if (WinSta->hbmWallpaper != NULL)
1435 {
1436 PWND DeskWin;
1437
1438 DeskWin = UserGetWindowObject(hWndDesktop);
1439
1440 if (DeskWin)
1441 {
1442 SIZE sz;
1443 int x, y;
1444 HDC hWallpaperDC;
1445
1446 sz.cx = DeskWin->rcWindow.right - DeskWin->rcWindow.left;
1447 sz.cy = DeskWin->rcWindow.bottom - DeskWin->rcWindow.top;
1448
1449 if (WinSta->WallpaperMode == wmStretch ||
1450 WinSta->WallpaperMode == wmTile)
1451 {
1452 x = 0;
1453 y = 0;
1454 }
1455 else
1456 {
1457 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1458 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1459 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1460 }
1461
1462 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1463 if(hWallpaperDC != NULL)
1464 {
1465 HBITMAP hOldBitmap;
1466
1467 /* fill in the area that the bitmap is not going to cover */
1468 if (x > 0 || y > 0)
1469 {
1470 /* FIXME - clip out the bitmap
1471 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1472 once we support DSTINVERT */
1473 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1474 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1475 NtGdiSelectBrush(hDC, PreviousBrush);
1476 }
1477
1478 /*Do not fill the background after it is painted no matter the size of the picture */
1479 doPatBlt = FALSE;
1480
1481 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
1482
1483 if (WinSta->WallpaperMode == wmStretch)
1484 {
1485 if(Rect.right && Rect.bottom)
1486 NtGdiStretchBlt(hDC,
1487 x,
1488 y,
1489 sz.cx,
1490 sz.cy,
1491 hWallpaperDC,
1492 0,
1493 0,
1494 WinSta->cxWallpaper,
1495 WinSta->cyWallpaper,
1496 SRCCOPY,
1497 0);
1498
1499 }
1500 else if (WinSta->WallpaperMode == wmTile)
1501 {
1502 /* paint the bitmap across the screen then down */
1503 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1504 {
1505 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1506 {
1507 NtGdiBitBlt(hDC,
1508 x,
1509 y,
1510 WinSta->cxWallpaper,
1511 WinSta->cyWallpaper,
1512 hWallpaperDC,
1513 0,
1514 0,
1515 SRCCOPY,
1516 0,
1517 0);
1518 }
1519 }
1520 }
1521 else
1522 {
1523 NtGdiBitBlt(hDC,
1524 x,
1525 y,
1526 WinSta->cxWallpaper,
1527 WinSta->cyWallpaper,
1528 hWallpaperDC,
1529 0,
1530 0,
1531 SRCCOPY,
1532 0,
1533 0);
1534 }
1535 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1536 NtGdiDeleteObjectApp(hWallpaperDC);
1537 }
1538 }
1539 }
1540
1541 /* Back ground is set to none, clear the screen */
1542 if (doPatBlt)
1543 {
1544 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1545 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1546 NtGdiSelectBrush(hDC, PreviousBrush);
1547 }
1548
1549 /*
1550 * Display system version on the desktop background
1551 */
1552
1553 if (g_PaintDesktopVersion)
1554 {
1555 static WCHAR s_wszVersion[256] = {0};
1556 RECTL rect;
1557
1558 if (*s_wszVersion)
1559 {
1560 len = wcslen(s_wszVersion);
1561 }
1562 else
1563 {
1564 len = GetSystemVersionString(s_wszVersion);
1565 }
1566
1567 if (len)
1568 {
1569 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1570 {
1571 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1572 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1573 }
1574
1575 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1576 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1577 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1578
1579 GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
1580
1581 IntGdiSetBkMode(hDC, mode_old);
1582 IntGdiSetTextAlign(hDC, align_old);
1583 IntGdiSetTextColor(hDC, color_old);
1584 }
1585 }
1586
1587 RETURN(TRUE);
1588
1589 CLEANUP:
1590 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1591 UserLeave();
1592 END_CLEANUP;
1593 }
1594
1595
1596 /*
1597 * NtUserSwitchDesktop
1598 *
1599 * Sets the current input (interactive) desktop.
1600 *
1601 * Parameters
1602 * hDesktop
1603 * Handle to desktop.
1604 *
1605 * Return Value
1606 * Status
1607 *
1608 * Status
1609 * @unimplemented
1610 */
1611
1612 BOOL APIENTRY
1613 NtUserSwitchDesktop(HDESK hDesktop)
1614 {
1615 PDESKTOP DesktopObject;
1616 NTSTATUS Status;
1617 DECLARE_RETURN(BOOL);
1618
1619 UserEnterExclusive();
1620 DPRINT("Enter NtUserSwitchDesktop\n");
1621
1622 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1623
1624 Status = IntValidateDesktopHandle(
1625 hDesktop,
1626 UserMode,
1627 0,
1628 &DesktopObject);
1629
1630 if (!NT_SUCCESS(Status))
1631 {
1632 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1633 RETURN(FALSE);
1634 }
1635
1636 /*
1637 * Don't allow applications switch the desktop if it's locked, unless the caller
1638 * is the logon application itself
1639 */
1640 if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
1641 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1642 {
1643 ObDereferenceObject(DesktopObject);
1644 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1645 RETURN(FALSE);
1646 }
1647
1648 if(DesktopObject->rpwinstaParent != InputWindowStation)
1649 {
1650 ObDereferenceObject(DesktopObject);
1651 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
1652 RETURN(FALSE);
1653 }
1654
1655 /* FIXME: Fail if the process is associated with a secured
1656 desktop such as Winlogon or Screen-Saver */
1657 /* FIXME: Connect to input device */
1658
1659 /* Set the active desktop in the desktop's window station. */
1660 InputWindowStation->ActiveDesktop = DesktopObject;
1661
1662 /* Set the global state. */
1663 InputDesktop = DesktopObject;
1664 InputDesktopHandle = hDesktop;
1665
1666 ObDereferenceObject(DesktopObject);
1667
1668 RETURN(TRUE);
1669
1670 CLEANUP:
1671 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1672 UserLeave();
1673 END_CLEANUP;
1674 }
1675
1676 /*
1677 * NtUserResolveDesktopForWOW
1678 *
1679 * Status
1680 * @unimplemented
1681 */
1682
1683 DWORD APIENTRY
1684 NtUserResolveDesktopForWOW(DWORD Unknown0)
1685 {
1686 UNIMPLEMENTED
1687 return 0;
1688 }
1689
1690 /*
1691 * NtUserGetThreadDesktop
1692 *
1693 * Status
1694 * @implemented
1695 */
1696
1697 HDESK APIENTRY
1698 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1699 {
1700 NTSTATUS Status;
1701 PETHREAD Thread;
1702 PDESKTOP DesktopObject;
1703 HDESK Ret, hThreadDesktop;
1704 OBJECT_HANDLE_INFORMATION HandleInformation;
1705 DECLARE_RETURN(HDESK);
1706
1707 UserEnterExclusive();
1708 DPRINT("Enter NtUserGetThreadDesktop\n");
1709
1710 if(!dwThreadId)
1711 {
1712 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1713 RETURN(0);
1714 }
1715
1716 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1717 if(!NT_SUCCESS(Status))
1718 {
1719 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1720 RETURN(0);
1721 }
1722
1723 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1724 {
1725 /* just return the handle, we queried the desktop handle of a thread running
1726 in the same context */
1727 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1728 ObDereferenceObject(Thread);
1729 RETURN(Ret);
1730 }
1731
1732 /* get the desktop handle and the desktop of the thread */
1733 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1734 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1735 {
1736 ObDereferenceObject(Thread);
1737 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1738 RETURN(NULL);
1739 }
1740
1741 /* we could just use DesktopObject instead of looking up the handle, but latter
1742 may be a bit safer (e.g. when the desktop is being destroyed */
1743 /* switch into the context of the thread we're trying to get the desktop from,
1744 so we can use the handle */
1745 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1746 Status = ObReferenceObjectByHandle(hThreadDesktop,
1747 GENERIC_ALL,
1748 ExDesktopObjectType,
1749 UserMode,
1750 (PVOID*)&DesktopObject,
1751 &HandleInformation);
1752 KeDetachProcess();
1753
1754 /* the handle couldn't be found, there's nothing to get... */
1755 if(!NT_SUCCESS(Status))
1756 {
1757 ObDereferenceObject(Thread);
1758 RETURN(NULL);
1759 }
1760
1761 /* lookup our handle table if we can find a handle to the desktop object,
1762 if not, create one */
1763 Ret = IntGetDesktopObjectHandle(DesktopObject);
1764
1765 /* all done, we got a valid handle to the desktop */
1766 ObDereferenceObject(DesktopObject);
1767 ObDereferenceObject(Thread);
1768 RETURN(Ret);
1769
1770 CLEANUP:
1771 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1772 UserLeave();
1773 END_CLEANUP;
1774 }
1775
1776 static NTSTATUS
1777 IntUnmapDesktopView(IN PDESKTOP DesktopObject)
1778 {
1779 PTHREADINFO ti;
1780 PPROCESSINFO CurrentWin32Process;
1781 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1782 NTSTATUS Status = STATUS_SUCCESS;
1783
1784 TRACE("DO %p\n");
1785
1786 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1787 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1788
1789 /* unmap if we're the last thread using the desktop */
1790 HeapMapping = *PrevLink;
1791 while (HeapMapping != NULL)
1792 {
1793 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1794 {
1795 if (--HeapMapping->Count == 0)
1796 {
1797 *PrevLink = HeapMapping->Next;
1798
1799 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1800 HeapMapping->UserMapping);
1801
1802 ObDereferenceObject(DesktopObject);
1803
1804 UserHeapFree(HeapMapping);
1805 break;
1806 }
1807 }
1808
1809 PrevLink = &HeapMapping->Next;
1810 HeapMapping = HeapMapping->Next;
1811 }
1812
1813 ti = GetW32ThreadInfo();
1814 if (ti != NULL)
1815 {
1816 GetWin32ClientInfo()->pDeskInfo = NULL;
1817 }
1818 GetWin32ClientInfo()->ulClientDelta = 0;
1819
1820 return Status;
1821 }
1822
1823 static NTSTATUS
1824 IntMapDesktopView(IN PDESKTOP DesktopObject)
1825 {
1826 PTHREADINFO ti;
1827 PPROCESSINFO CurrentWin32Process;
1828 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1829 PVOID UserBase = NULL;
1830 SIZE_T ViewSize = 0;
1831 LARGE_INTEGER Offset;
1832 NTSTATUS Status;
1833
1834 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1835 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1836
1837 /* find out if another thread already mapped the desktop heap */
1838 HeapMapping = *PrevLink;
1839 while (HeapMapping != NULL)
1840 {
1841 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1842 {
1843 HeapMapping->Count++;
1844 return STATUS_SUCCESS;
1845 }
1846
1847 PrevLink = &HeapMapping->Next;
1848 HeapMapping = HeapMapping->Next;
1849 }
1850
1851 /* we're the first, map the heap */
1852 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
1853 Offset.QuadPart = 0;
1854 Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
1855 PsGetCurrentProcess(),
1856 &UserBase,
1857 0,
1858 0,
1859 &Offset,
1860 &ViewSize,
1861 ViewUnmap,
1862 SEC_NO_CHANGE,
1863 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1864 if (!NT_SUCCESS(Status))
1865 {
1866 DPRINT1("Failed to map desktop\n");
1867 return Status;
1868 }
1869
1870 /* add the mapping */
1871 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1872 if (HeapMapping == NULL)
1873 {
1874 MmUnmapViewOfSection(PsGetCurrentProcess(),
1875 UserBase);
1876 DPRINT1("UserHeapAlloc() failed!\n");
1877 return STATUS_NO_MEMORY;
1878 }
1879
1880 HeapMapping->Next = NULL;
1881 HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
1882 HeapMapping->UserMapping = UserBase;
1883 HeapMapping->Limit = ViewSize;
1884 HeapMapping->Count = 1;
1885 *PrevLink = HeapMapping;
1886
1887 ObReferenceObject(DesktopObject);
1888
1889 /* create a W32THREADINFO structure if not already done, or update it */
1890 ti = GetW32ThreadInfo();
1891 GetWin32ClientInfo()->ulClientDelta = DesktopHeapGetUserDelta();
1892 if (ti != NULL)
1893 {
1894 if (GetWin32ClientInfo()->pDeskInfo == NULL)
1895 {
1896 GetWin32ClientInfo()->pDeskInfo =
1897 (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo -
1898 GetWin32ClientInfo()->ulClientDelta);
1899 }
1900 }
1901
1902 return STATUS_SUCCESS;
1903 }
1904
1905 BOOL
1906 IntSetThreadDesktop(IN PDESKTOP DesktopObject,
1907 IN BOOL FreeOnFailure)
1908 {
1909 PDESKTOP OldDesktop;
1910 PTHREADINFO W32Thread;
1911 NTSTATUS Status;
1912 BOOL MapHeap;
1913
1914 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
1915 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1916 W32Thread = PsGetCurrentThreadWin32Thread();
1917
1918 if (W32Thread->rpdesk != DesktopObject)
1919 {
1920 OldDesktop = W32Thread->rpdesk;
1921
1922 if (!IsListEmpty(&W32Thread->WindowListHead))
1923 {
1924 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1925 SetLastWin32Error(ERROR_BUSY);
1926 return FALSE;
1927 }
1928
1929 W32Thread->rpdesk = DesktopObject;
1930
1931 if (MapHeap && DesktopObject != NULL)
1932 {
1933 Status = IntMapDesktopView(DesktopObject);
1934 if (!NT_SUCCESS(Status))
1935 {
1936 SetLastNtError(Status);
1937 return FALSE;
1938 }
1939 }
1940
1941 /* Hack for system threads */
1942 if (NtCurrentTeb())
1943 {
1944 PCLIENTINFO pci = GetWin32ClientInfo();
1945 pci->ulClientDelta = DesktopHeapGetUserDelta();
1946 if (DesktopObject)
1947 {
1948 pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
1949 }
1950 }
1951
1952 if (OldDesktop != NULL &&
1953 !IntCheckProcessDesktopClasses(OldDesktop,
1954 FreeOnFailure))
1955 {
1956 DPRINT1("Failed to move process classes to shared heap!\n");
1957
1958 /* failed to move desktop classes to the shared heap,
1959 unmap the view and return the error */
1960 if (MapHeap && DesktopObject != NULL)
1961 IntUnmapDesktopView(DesktopObject);
1962
1963 return FALSE;
1964 }
1965
1966 /* Remove the thread from the old desktop's list */
1967 RemoveEntryList(&W32Thread->PtiLink);
1968
1969 if (DesktopObject != NULL)
1970 {
1971 ObReferenceObject(DesktopObject);
1972 /* Insert into new desktop's list */
1973 InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
1974 }
1975
1976 if (OldDesktop != NULL)
1977 {
1978 if (MapHeap)
1979 {
1980 IntUnmapDesktopView(OldDesktop);
1981 }
1982
1983 ObDereferenceObject(OldDesktop);
1984 }
1985 }
1986
1987 return TRUE;
1988 }
1989
1990 /*
1991 * NtUserSetThreadDesktop
1992 *
1993 * Status
1994 * @implemented
1995 */
1996
1997 BOOL APIENTRY
1998 NtUserSetThreadDesktop(HDESK hDesktop)
1999 {
2000 PDESKTOP DesktopObject;
2001 NTSTATUS Status;
2002 DECLARE_RETURN(BOOL);
2003
2004 UserEnterExclusive();
2005 DPRINT("Enter NtUserSetThreadDesktop\n");
2006
2007 /* Validate the new desktop. */
2008 Status = IntValidateDesktopHandle(
2009 hDesktop,
2010 UserMode,
2011 0,
2012 &DesktopObject);
2013
2014 if (!NT_SUCCESS(Status))
2015 {
2016 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
2017 RETURN(FALSE);
2018 }
2019
2020 /* FIXME: Should check here to see if the thread has any windows. */
2021
2022 if (!IntSetThreadDesktop(DesktopObject,
2023 FALSE))
2024 {
2025 RETURN(FALSE);
2026 }
2027
2028 RETURN(TRUE);
2029
2030 CLEANUP:
2031 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
2032 UserLeave();
2033 END_CLEANUP;
2034 }
2035
2036 /* EOF */