sync with trunk (r46275)
[reactos.git] / 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->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 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->rpdesk;
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->hrgnUpdate,
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->rpdesk;
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->rpdesk;
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->hsectionDesktop != NULL)
851 {
852 ObDereferenceObject(Desktop->hsectionDesktop);
853 Desktop->hsectionDesktop = 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 PWND pWnd = NULL;
916 DECLARE_RETURN(HDESK);
917
918 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
919 UserEnterExclusive();
920
921 _SEH2_TRY
922 {
923 ProbeForRead( poa,
924 sizeof(OBJECT_ATTRIBUTES),
925 1);
926
927 hWindowStation = poa->RootDirectory;
928 lpszDesktopName = poa->ObjectName;
929 }
930 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
931 {
932 Status =_SEH2_GetExceptionCode();
933 }
934 _SEH2_END
935
936 if (! NT_SUCCESS(Status))
937 {
938 DPRINT1("Failed reading Object Attributes from user space.\n");
939 SetLastNtError(Status);
940 RETURN( NULL);
941 }
942
943 Status = IntValidateWindowStationHandle(
944 hWindowStation,
945 KernelMode,
946 0, /* FIXME - WINSTA_CREATEDESKTOP */
947 &WinStaObject);
948
949 if (! NT_SUCCESS(Status))
950 {
951 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
952 hWindowStation, lpszDesktopName);
953 SetLastNtError(Status);
954 RETURN( NULL);
955 }
956 if(lpszDesktopName != NULL)
957 {
958 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
959 if(!NT_SUCCESS(Status))
960 {
961 SetLastNtError(Status);
962 RETURN( NULL);
963 }
964 }
965 else
966 {
967 RtlInitUnicodeString(&SafeDesktopName, NULL);
968 }
969
970 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
971 &SafeDesktopName))
972 {
973 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
974 ObDereferenceObject(WinStaObject);
975 if (lpszDesktopName)
976 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
977 RETURN( NULL);
978 }
979 if (lpszDesktopName)
980 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
981 ObDereferenceObject(WinStaObject);
982
983 /*
984 * Try to open already existing desktop
985 */
986
987 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
988
989 /* Initialize ObjectAttributes for the desktop object */
990 InitializeObjectAttributes(
991 &ObjectAttributes,
992 &DesktopName,
993 0,
994 NULL,
995 NULL);
996
997 Status = ObOpenObjectByName(
998 &ObjectAttributes,
999 ExDesktopObjectType,
1000 KernelMode,
1001 NULL,
1002 dwDesiredAccess,
1003 (PVOID)&DummyContext,
1004 (HANDLE*)&Desktop);
1005 if (!NT_SUCCESS(Status)) RETURN(NULL);
1006 if (Status == STATUS_OBJECT_NAME_EXISTS)
1007 {
1008 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
1009 RETURN( Desktop);
1010 }
1011
1012 /* Reference the desktop */
1013 Status = ObReferenceObjectByHandle(Desktop,
1014 0,
1015 ExDesktopObjectType,
1016 KernelMode,
1017 (PVOID)&DesktopObject,
1018 NULL);
1019 if (!NT_SUCCESS(Status)) RETURN(NULL);
1020
1021 DesktopObject->hsectionDesktop = NULL;
1022 DesktopObject->pheapDesktop = UserCreateHeap(&DesktopObject->hsectionDesktop,
1023 &DesktopHeapSystemBase,
1024 HeapSize);
1025 if (DesktopObject->pheapDesktop == NULL)
1026 {
1027 ObDereferenceObject(DesktopObject);
1028 DPRINT1("Failed to create desktop heap!\n");
1029 RETURN(NULL);
1030 }
1031
1032 DesktopInfoSize = FIELD_OFFSET(DESKTOPINFO,
1033 szDesktopName[(lpszDesktopName->Length / sizeof(WCHAR)) + 1]);
1034
1035 DesktopObject->pDeskInfo = RtlAllocateHeap(DesktopObject->pheapDesktop,
1036 HEAP_NO_SERIALIZE,
1037 DesktopInfoSize);
1038
1039 if (DesktopObject->pDeskInfo == NULL)
1040 {
1041 ObDereferenceObject(DesktopObject);
1042 DPRINT1("Failed to create the DESKTOP structure!\n");
1043 RETURN(NULL);
1044 }
1045
1046 RtlZeroMemory(DesktopObject->pDeskInfo,
1047 DesktopInfoSize);
1048
1049 DesktopObject->pDeskInfo->pvDesktopBase = DesktopHeapSystemBase;
1050 DesktopObject->pDeskInfo->pvDesktopLimit = (PVOID)((ULONG_PTR)DesktopHeapSystemBase + HeapSize);
1051 RtlCopyMemory(DesktopObject->pDeskInfo->szDesktopName,
1052 lpszDesktopName->Buffer,
1053 lpszDesktopName->Length);
1054
1055 // init desktop area
1056 DesktopObject->WorkArea.left = 0;
1057 DesktopObject->WorkArea.top = 0;
1058 DesktopObject->WorkArea.right = -1;
1059 DesktopObject->WorkArea.bottom = -1;
1060 IntGetDesktopWorkArea(DesktopObject, NULL);
1061
1062 /* Initialize some local (to win32k) desktop state. */
1063 InitializeListHead(&DesktopObject->PtiList);
1064 DesktopObject->ActiveMessageQueue = NULL;
1065 ExFreePoolWithTag(DesktopName.Buffer, TAG_STRING);
1066
1067 if (! NT_SUCCESS(Status))
1068 {
1069 DPRINT1("Failed to create desktop handle\n");
1070 SetLastNtError(Status);
1071 RETURN( NULL);
1072 }
1073
1074 /*
1075 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1076 *
1077 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1078 * to function at the beginning of the project by ramroding the GUI into
1079 * operation and making the desktop window work from user space.
1080 * (jt)
1081 */
1082 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
1083 Status = CsrInsertObject(Desktop,
1084 GENERIC_ALL,
1085 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
1086 if (! NT_SUCCESS(Status))
1087 {
1088 DPRINT1("Failed to create desktop handle for CSRSS\n");
1089 ZwClose(Desktop);
1090 SetLastNtError(Status);
1091 RETURN( NULL);
1092 }
1093
1094 Status = co_CsrNotify(&Request);
1095 if (! NT_SUCCESS(Status))
1096 {
1097 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
1098 DPRINT1("Failed to notify CSRSS about new desktop\n");
1099 ZwClose(Desktop);
1100 SetLastNtError(Status);
1101 RETURN( NULL);
1102 }
1103
1104 W32Thread = PsGetCurrentThreadWin32Thread();
1105
1106 if (!W32Thread->rpdesk) IntSetThreadDesktop(DesktopObject,FALSE);
1107
1108 /*
1109 Based on wine/server/window.c in get_desktop_window.
1110 */
1111
1112 ClassName.Buffer = ((PWSTR)((ULONG_PTR)(WORD)(gpsi->atomSysClass[ICLS_HWNDMESSAGE])));
1113 ClassName.Length = 0;
1114 RtlZeroMemory(&MenuName, sizeof(MenuName));
1115 RtlZeroMemory(&WindowName, sizeof(WindowName));
1116
1117 pWnd = co_IntCreateWindowEx( 0,
1118 &ClassName,
1119 &WindowName,
1120 (WS_POPUP|WS_CLIPCHILDREN),
1121 0,
1122 0,
1123 100,
1124 100,
1125 NULL,
1126 NULL,
1127 hModClient,
1128 NULL,
1129 0,
1130 TRUE);
1131 if (!pWnd)
1132 {
1133 DPRINT1("Failed to create Message window handle\n");
1134 }
1135 else
1136 {
1137 DesktopObject->spwndMessage = pWnd;
1138 }
1139
1140 RETURN( Desktop);
1141
1142 CLEANUP:
1143 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
1144 UserLeave();
1145 END_CLEANUP;
1146 }
1147
1148 /*
1149 * NtUserOpenDesktop
1150 *
1151 * Opens an existing desktop.
1152 *
1153 * Parameters
1154 * lpszDesktopName
1155 * Name of the existing desktop.
1156 *
1157 * dwFlags
1158 * Interaction flags.
1159 *
1160 * dwDesiredAccess
1161 * Requested type of access.
1162 *
1163 * Return Value
1164 * Handle to the desktop or zero on failure.
1165 *
1166 * Status
1167 * @implemented
1168 */
1169
1170 HDESK APIENTRY
1171 NtUserOpenDesktop(
1172 PUNICODE_STRING lpszDesktopName,
1173 DWORD dwFlags,
1174 ACCESS_MASK dwDesiredAccess)
1175 {
1176 OBJECT_ATTRIBUTES ObjectAttributes;
1177 HWINSTA WinSta;
1178 PWINSTATION_OBJECT WinStaObject;
1179 UNICODE_STRING DesktopName;
1180 UNICODE_STRING SafeDesktopName;
1181 NTSTATUS Status;
1182 HDESK Desktop;
1183 BOOL Result;
1184 DECLARE_RETURN(HDESK);
1185
1186 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
1187 UserEnterExclusive();
1188
1189 /*
1190 * Validate the window station handle and compose the fully
1191 * qualified desktop name
1192 */
1193
1194 WinSta = UserGetProcessWindowStation();
1195 Status = IntValidateWindowStationHandle(
1196 WinSta,
1197 KernelMode,
1198 0,
1199 &WinStaObject);
1200
1201 if (!NT_SUCCESS(Status))
1202 {
1203 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
1204 SetLastNtError(Status);
1205 RETURN( 0);
1206 }
1207
1208 if(lpszDesktopName != NULL)
1209 {
1210 Status = IntSafeCopyUnicodeString(&SafeDesktopName, lpszDesktopName);
1211 if(!NT_SUCCESS(Status))
1212 {
1213 SetLastNtError(Status);
1214 RETURN( NULL);
1215 }
1216 }
1217 else
1218 {
1219 RtlInitUnicodeString(&SafeDesktopName, NULL);
1220 }
1221
1222 Result = IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
1223 &SafeDesktopName);
1224
1225 if (lpszDesktopName)
1226 ExFreePoolWithTag(SafeDesktopName.Buffer, TAG_STRING);
1227 ObDereferenceObject(WinStaObject);
1228
1229
1230 if (!Result)
1231 {
1232 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1233 RETURN( 0);
1234 }
1235
1236
1237 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
1238
1239 /* Initialize ObjectAttributes for the desktop object */
1240 InitializeObjectAttributes(
1241 &ObjectAttributes,
1242 &DesktopName,
1243 0,
1244 NULL,
1245 NULL);
1246
1247 Status = ObOpenObjectByName(
1248 &ObjectAttributes,
1249 ExDesktopObjectType,
1250 KernelMode,
1251 NULL,
1252 dwDesiredAccess,
1253 NULL,
1254 (HANDLE*)&Desktop);
1255
1256 if (!NT_SUCCESS(Status))
1257 {
1258 SetLastNtError(Status);
1259 ExFreePool(DesktopName.Buffer);
1260 RETURN( 0);
1261 }
1262
1263 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1264 ExFreePool(DesktopName.Buffer);
1265
1266 RETURN( Desktop);
1267
1268 CLEANUP:
1269 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1270 UserLeave();
1271 END_CLEANUP;
1272 }
1273
1274 /*
1275 * NtUserOpenInputDesktop
1276 *
1277 * Opens the input (interactive) desktop.
1278 *
1279 * Parameters
1280 * dwFlags
1281 * Interaction flags.
1282 *
1283 * fInherit
1284 * Inheritance option.
1285 *
1286 * dwDesiredAccess
1287 * Requested type of access.
1288 *
1289 * Return Value
1290 * Handle to the input desktop or zero on failure.
1291 *
1292 * Status
1293 * @implemented
1294 */
1295
1296 HDESK APIENTRY
1297 NtUserOpenInputDesktop(
1298 DWORD dwFlags,
1299 BOOL fInherit,
1300 ACCESS_MASK dwDesiredAccess)
1301 {
1302 PDESKTOP Object;
1303 NTSTATUS Status;
1304 HDESK Desktop;
1305 DECLARE_RETURN(HDESK);
1306
1307 DPRINT("Enter NtUserOpenInputDesktop\n");
1308 UserEnterExclusive();
1309
1310 DPRINT("About to open input desktop\n");
1311
1312 /* Get a pointer to the desktop object */
1313
1314 Status = IntValidateDesktopHandle(
1315 InputDesktopHandle,
1316 UserMode,
1317 0,
1318 &Object);
1319
1320 if (!NT_SUCCESS(Status))
1321 {
1322 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1323 RETURN((HDESK)0);
1324 }
1325
1326 /* Create a new handle to the object */
1327
1328 Status = ObOpenObjectByPointer(
1329 Object,
1330 0,
1331 NULL,
1332 dwDesiredAccess,
1333 ExDesktopObjectType,
1334 UserMode,
1335 (HANDLE*)&Desktop);
1336
1337 ObDereferenceObject(Object);
1338
1339 if (NT_SUCCESS(Status))
1340 {
1341 DPRINT("Successfully opened input desktop\n");
1342 RETURN((HDESK)Desktop);
1343 }
1344
1345 SetLastNtError(Status);
1346 RETURN((HDESK)0);
1347
1348 CLEANUP:
1349 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1350 UserLeave();
1351 END_CLEANUP;
1352 }
1353
1354 /*
1355 * NtUserCloseDesktop
1356 *
1357 * Closes a desktop handle.
1358 *
1359 * Parameters
1360 * hDesktop
1361 * Handle to the desktop.
1362 *
1363 * Return Value
1364 * Status
1365 *
1366 * Remarks
1367 * The desktop handle can be created with NtUserCreateDesktop or
1368 * NtUserOpenDesktop. This function will fail if any thread in the calling
1369 * process is using the specified desktop handle or if the handle refers
1370 * to the initial desktop of the calling process.
1371 *
1372 * Status
1373 * @implemented
1374 */
1375
1376 BOOL APIENTRY
1377 NtUserCloseDesktop(HDESK hDesktop)
1378 {
1379 PDESKTOP Object;
1380 NTSTATUS Status;
1381 DECLARE_RETURN(BOOL);
1382
1383 DPRINT("Enter NtUserCloseDesktop\n");
1384 UserEnterExclusive();
1385
1386 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1387
1388 Status = IntValidateDesktopHandle(
1389 hDesktop,
1390 UserMode,
1391 0,
1392 &Object);
1393
1394 if (!NT_SUCCESS(Status))
1395 {
1396 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1397 RETURN(FALSE);
1398 }
1399
1400 ObDereferenceObject(Object);
1401
1402 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1403
1404 Status = ZwClose(hDesktop);
1405 if (!NT_SUCCESS(Status))
1406 {
1407 SetLastNtError(Status);
1408 RETURN(FALSE);
1409 }
1410
1411 RETURN(TRUE);
1412
1413 CLEANUP:
1414 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1415 UserLeave();
1416 END_CLEANUP;
1417 }
1418
1419
1420
1421
1422 /*
1423 * NtUserPaintDesktop
1424 *
1425 * The NtUserPaintDesktop function fills the clipping region in the
1426 * specified device context with the desktop pattern or wallpaper. The
1427 * function is provided primarily for shell desktops.
1428 *
1429 * Parameters
1430 * hDC
1431 * Handle to the device context.
1432 *
1433 * Status
1434 * @implemented
1435 */
1436
1437 BOOL APIENTRY
1438 NtUserPaintDesktop(HDC hDC)
1439 {
1440 RECTL Rect;
1441 HBRUSH DesktopBrush, PreviousBrush;
1442 HWND hWndDesktop;
1443 BOOL doPatBlt = TRUE;
1444 PWINDOW_OBJECT WndDesktop;
1445 int len;
1446 COLORREF color_old;
1447 UINT align_old;
1448 int mode_old;
1449 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1450 PWINSTATION_OBJECT WinSta = pti->rpdesk->rpwinstaParent;
1451 DECLARE_RETURN(BOOL);
1452
1453 UserEnterExclusive();
1454 DPRINT("Enter NtUserPaintDesktop\n");
1455
1456 GdiGetClipBox(hDC, &Rect);
1457
1458 hWndDesktop = IntGetDesktopWindow();
1459
1460 WndDesktop = UserGetWindowObject(hWndDesktop);
1461 if (!WndDesktop)
1462 {
1463 RETURN(FALSE);
1464 }
1465
1466 DesktopBrush = (HBRUSH)UserGetClassLongPtr(WndDesktop->Wnd->pcls, GCL_HBRBACKGROUND, FALSE);
1467
1468
1469 /*
1470 * Paint desktop background
1471 */
1472
1473 if (WinSta->hbmWallpaper != NULL)
1474 {
1475 PWINDOW_OBJECT DeskWin;
1476
1477 DeskWin = UserGetWindowObject(hWndDesktop);
1478
1479 if (DeskWin)
1480 {
1481 SIZE sz;
1482 int x, y;
1483 HDC hWallpaperDC;
1484
1485 sz.cx = DeskWin->Wnd->rcWindow.right - DeskWin->Wnd->rcWindow.left;
1486 sz.cy = DeskWin->Wnd->rcWindow.bottom - DeskWin->Wnd->rcWindow.top;
1487
1488 if (WinSta->WallpaperMode == wmStretch ||
1489 WinSta->WallpaperMode == wmTile)
1490 {
1491 x = 0;
1492 y = 0;
1493 }
1494 else
1495 {
1496 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1497 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1498 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1499 }
1500
1501 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1502 if(hWallpaperDC != NULL)
1503 {
1504 HBITMAP hOldBitmap;
1505
1506 /* fill in the area that the bitmap is not going to cover */
1507 if (x > 0 || y > 0)
1508 {
1509 /* FIXME - clip out the bitmap
1510 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1511 once we support DSTINVERT */
1512 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1513 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1514 NtGdiSelectBrush(hDC, PreviousBrush);
1515 }
1516
1517 /*Do not fill the background after it is painted no matter the size of the picture */
1518 doPatBlt = FALSE;
1519
1520 hOldBitmap = NtGdiSelectBitmap(hWallpaperDC, WinSta->hbmWallpaper);
1521
1522 if (WinSta->WallpaperMode == wmStretch)
1523 {
1524 if(Rect.right && Rect.bottom)
1525 NtGdiStretchBlt(hDC,
1526 x,
1527 y,
1528 sz.cx,
1529 sz.cy,
1530 hWallpaperDC,
1531 0,
1532 0,
1533 WinSta->cxWallpaper,
1534 WinSta->cyWallpaper,
1535 SRCCOPY,
1536 0);
1537
1538 }
1539 else if (WinSta->WallpaperMode == wmTile)
1540 {
1541 /* paint the bitmap across the screen then down */
1542 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1543 {
1544 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1545 {
1546 NtGdiBitBlt(hDC,
1547 x,
1548 y,
1549 WinSta->cxWallpaper,
1550 WinSta->cyWallpaper,
1551 hWallpaperDC,
1552 0,
1553 0,
1554 SRCCOPY,
1555 0,
1556 0);
1557 }
1558 }
1559 }
1560 else
1561 {
1562 NtGdiBitBlt(hDC,
1563 x,
1564 y,
1565 WinSta->cxWallpaper,
1566 WinSta->cyWallpaper,
1567 hWallpaperDC,
1568 0,
1569 0,
1570 SRCCOPY,
1571 0,
1572 0);
1573 }
1574 NtGdiSelectBitmap(hWallpaperDC, hOldBitmap);
1575 NtGdiDeleteObjectApp(hWallpaperDC);
1576 }
1577 }
1578 }
1579
1580 /* Back ground is set to none, clear the screen */
1581 if (doPatBlt)
1582 {
1583 PreviousBrush = NtGdiSelectBrush(hDC, DesktopBrush);
1584 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1585 NtGdiSelectBrush(hDC, PreviousBrush);
1586 }
1587
1588 /*
1589 * Display system version on the desktop background
1590 */
1591
1592 if (g_PaintDesktopVersion)
1593 {
1594 static WCHAR s_wszVersion[256] = {0};
1595 RECTL rect;
1596
1597 if (*s_wszVersion)
1598 {
1599 len = wcslen(s_wszVersion);
1600 }
1601 else
1602 {
1603 len = GetSystemVersionString(s_wszVersion);
1604 }
1605
1606 if (len)
1607 {
1608 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1609 {
1610 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1611 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1612 }
1613
1614 color_old = IntGdiSetTextColor(hDC, RGB(255,255,255));
1615 align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
1616 mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
1617
1618 GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
1619
1620 IntGdiSetBkMode(hDC, mode_old);
1621 IntGdiSetTextAlign(hDC, align_old);
1622 IntGdiSetTextColor(hDC, color_old);
1623 }
1624 }
1625
1626 RETURN(TRUE);
1627
1628 CLEANUP:
1629 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1630 UserLeave();
1631 END_CLEANUP;
1632 }
1633
1634
1635 /*
1636 * NtUserSwitchDesktop
1637 *
1638 * Sets the current input (interactive) desktop.
1639 *
1640 * Parameters
1641 * hDesktop
1642 * Handle to desktop.
1643 *
1644 * Return Value
1645 * Status
1646 *
1647 * Status
1648 * @unimplemented
1649 */
1650
1651 BOOL APIENTRY
1652 NtUserSwitchDesktop(HDESK hDesktop)
1653 {
1654 PDESKTOP DesktopObject;
1655 NTSTATUS Status;
1656 DECLARE_RETURN(BOOL);
1657
1658 UserEnterExclusive();
1659 DPRINT("Enter NtUserSwitchDesktop\n");
1660
1661 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1662
1663 Status = IntValidateDesktopHandle(
1664 hDesktop,
1665 UserMode,
1666 0,
1667 &DesktopObject);
1668
1669 if (!NT_SUCCESS(Status))
1670 {
1671 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1672 RETURN(FALSE);
1673 }
1674
1675 /*
1676 * Don't allow applications switch the desktop if it's locked, unless the caller
1677 * is the logon application itself
1678 */
1679 if((DesktopObject->rpwinstaParent->Flags & WSS_LOCKED) &&
1680 LogonProcess != NULL && LogonProcess != PsGetCurrentProcessWin32Process())
1681 {
1682 ObDereferenceObject(DesktopObject);
1683 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1684 RETURN(FALSE);
1685 }
1686
1687 if(DesktopObject->rpwinstaParent != InputWindowStation)
1688 {
1689 ObDereferenceObject(DesktopObject);
1690 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop);
1691 RETURN(FALSE);
1692 }
1693
1694 /* FIXME: Fail if the process is associated with a secured
1695 desktop such as Winlogon or Screen-Saver */
1696 /* FIXME: Connect to input device */
1697
1698 /* Set the active desktop in the desktop's window station. */
1699 InputWindowStation->ActiveDesktop = DesktopObject;
1700
1701 /* Set the global state. */
1702 InputDesktop = DesktopObject;
1703 InputDesktopHandle = hDesktop;
1704
1705 ObDereferenceObject(DesktopObject);
1706
1707 RETURN(TRUE);
1708
1709 CLEANUP:
1710 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1711 UserLeave();
1712 END_CLEANUP;
1713 }
1714
1715 /*
1716 * NtUserResolveDesktopForWOW
1717 *
1718 * Status
1719 * @unimplemented
1720 */
1721
1722 DWORD APIENTRY
1723 NtUserResolveDesktopForWOW(DWORD Unknown0)
1724 {
1725 UNIMPLEMENTED
1726 return 0;
1727 }
1728
1729 /*
1730 * NtUserGetThreadDesktop
1731 *
1732 * Status
1733 * @implemented
1734 */
1735
1736 HDESK APIENTRY
1737 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1738 {
1739 NTSTATUS Status;
1740 PETHREAD Thread;
1741 PDESKTOP DesktopObject;
1742 HDESK Ret, hThreadDesktop;
1743 OBJECT_HANDLE_INFORMATION HandleInformation;
1744 DECLARE_RETURN(HDESK);
1745
1746 UserEnterExclusive();
1747 DPRINT("Enter NtUserGetThreadDesktop\n");
1748
1749 if(!dwThreadId)
1750 {
1751 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1752 RETURN(0);
1753 }
1754
1755 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)dwThreadId, &Thread);
1756 if(!NT_SUCCESS(Status))
1757 {
1758 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1759 RETURN(0);
1760 }
1761
1762 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1763 {
1764 /* just return the handle, we queried the desktop handle of a thread running
1765 in the same context */
1766 Ret = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk;
1767 ObDereferenceObject(Thread);
1768 RETURN(Ret);
1769 }
1770
1771 /* get the desktop handle and the desktop of the thread */
1772 if(!(hThreadDesktop = ((PTHREADINFO)Thread->Tcb.Win32Thread)->hdesk) ||
1773 !(DesktopObject = ((PTHREADINFO)Thread->Tcb.Win32Thread)->rpdesk))
1774 {
1775 ObDereferenceObject(Thread);
1776 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1777 RETURN(NULL);
1778 }
1779
1780 /* we could just use DesktopObject instead of looking up the handle, but latter
1781 may be a bit safer (e.g. when the desktop is being destroyed */
1782 /* switch into the context of the thread we're trying to get the desktop from,
1783 so we can use the handle */
1784 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1785 Status = ObReferenceObjectByHandle(hThreadDesktop,
1786 GENERIC_ALL,
1787 ExDesktopObjectType,
1788 UserMode,
1789 (PVOID*)&DesktopObject,
1790 &HandleInformation);
1791 KeDetachProcess();
1792
1793 /* the handle couldn't be found, there's nothing to get... */
1794 if(!NT_SUCCESS(Status))
1795 {
1796 ObDereferenceObject(Thread);
1797 RETURN(NULL);
1798 }
1799
1800 /* lookup our handle table if we can find a handle to the desktop object,
1801 if not, create one */
1802 Ret = IntGetDesktopObjectHandle(DesktopObject);
1803
1804 /* all done, we got a valid handle to the desktop */
1805 ObDereferenceObject(DesktopObject);
1806 ObDereferenceObject(Thread);
1807 RETURN(Ret);
1808
1809 CLEANUP:
1810 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1811 UserLeave();
1812 END_CLEANUP;
1813 }
1814
1815 static NTSTATUS
1816 IntUnmapDesktopView(IN PDESKTOP DesktopObject)
1817 {
1818 PTHREADINFO ti;
1819 PPROCESSINFO CurrentWin32Process;
1820 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1821 NTSTATUS Status = STATUS_SUCCESS;
1822
1823 TRACE("DO %p\n");
1824
1825 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1826 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1827
1828 /* unmap if we're the last thread using the desktop */
1829 HeapMapping = *PrevLink;
1830 while (HeapMapping != NULL)
1831 {
1832 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1833 {
1834 if (--HeapMapping->Count == 0)
1835 {
1836 *PrevLink = HeapMapping->Next;
1837
1838 Status = MmUnmapViewOfSection(PsGetCurrentProcess(),
1839 HeapMapping->UserMapping);
1840
1841 ObDereferenceObject(DesktopObject);
1842
1843 UserHeapFree(HeapMapping);
1844 break;
1845 }
1846 }
1847
1848 PrevLink = &HeapMapping->Next;
1849 HeapMapping = HeapMapping->Next;
1850 }
1851
1852 ti = GetW32ThreadInfo();
1853 if (ti != NULL)
1854 {
1855 GetWin32ClientInfo()->pDeskInfo = NULL;
1856 }
1857 GetWin32ClientInfo()->ulClientDelta = 0;
1858
1859 return Status;
1860 }
1861
1862 static NTSTATUS
1863 IntMapDesktopView(IN PDESKTOP DesktopObject)
1864 {
1865 PTHREADINFO ti;
1866 PPROCESSINFO CurrentWin32Process;
1867 PW32HEAP_USER_MAPPING HeapMapping, *PrevLink;
1868 PVOID UserBase = NULL;
1869 SIZE_T ViewSize = 0;
1870 LARGE_INTEGER Offset;
1871 NTSTATUS Status;
1872
1873 CurrentWin32Process = PsGetCurrentProcessWin32Process();
1874 PrevLink = &CurrentWin32Process->HeapMappings.Next;
1875
1876 /* find out if another thread already mapped the desktop heap */
1877 HeapMapping = *PrevLink;
1878 while (HeapMapping != NULL)
1879 {
1880 if (HeapMapping->KernelMapping == (PVOID)DesktopObject->pheapDesktop)
1881 {
1882 HeapMapping->Count++;
1883 return STATUS_SUCCESS;
1884 }
1885
1886 PrevLink = &HeapMapping->Next;
1887 HeapMapping = HeapMapping->Next;
1888 }
1889
1890 /* we're the first, map the heap */
1891 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject->pheapDesktop);
1892 Offset.QuadPart = 0;
1893 Status = MmMapViewOfSection(DesktopObject->hsectionDesktop,
1894 PsGetCurrentProcess(),
1895 &UserBase,
1896 0,
1897 0,
1898 &Offset,
1899 &ViewSize,
1900 ViewUnmap,
1901 SEC_NO_CHANGE,
1902 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1903 if (!NT_SUCCESS(Status))
1904 {
1905 DPRINT1("Failed to map desktop\n");
1906 return Status;
1907 }
1908
1909 /* add the mapping */
1910 HeapMapping = UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING));
1911 if (HeapMapping == NULL)
1912 {
1913 MmUnmapViewOfSection(PsGetCurrentProcess(),
1914 UserBase);
1915 DPRINT1("UserHeapAlloc() failed!\n");
1916 return STATUS_NO_MEMORY;
1917 }
1918
1919 HeapMapping->Next = NULL;
1920 HeapMapping->KernelMapping = (PVOID)DesktopObject->pheapDesktop;
1921 HeapMapping->UserMapping = UserBase;
1922 HeapMapping->Limit = ViewSize;
1923 HeapMapping->Count = 1;
1924 *PrevLink = HeapMapping;
1925
1926 ObReferenceObject(DesktopObject);
1927
1928 /* create a W32THREADINFO structure if not already done, or update it */
1929 ti = GetW32ThreadInfo();
1930 GetWin32ClientInfo()->ulClientDelta = DesktopHeapGetUserDelta();
1931 if (ti != NULL)
1932 {
1933 if (GetWin32ClientInfo()->pDeskInfo == NULL)
1934 {
1935 GetWin32ClientInfo()->pDeskInfo =
1936 (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo -
1937 GetWin32ClientInfo()->ulClientDelta);
1938 }
1939 }
1940
1941 return STATUS_SUCCESS;
1942 }
1943
1944 BOOL
1945 IntSetThreadDesktop(IN PDESKTOP DesktopObject,
1946 IN BOOL FreeOnFailure)
1947 {
1948 PDESKTOP OldDesktop;
1949 PTHREADINFO W32Thread;
1950 NTSTATUS Status;
1951 BOOL MapHeap;
1952
1953 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject, FreeOnFailure);
1954 MapHeap = (PsGetCurrentProcess() != PsInitialSystemProcess);
1955 W32Thread = PsGetCurrentThreadWin32Thread();
1956
1957 if (W32Thread->rpdesk != DesktopObject)
1958 {
1959 OldDesktop = W32Thread->rpdesk;
1960
1961 if (!IsListEmpty(&W32Thread->WindowListHead))
1962 {
1963 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1964 SetLastWin32Error(ERROR_BUSY);
1965 return FALSE;
1966 }
1967
1968 W32Thread->rpdesk = DesktopObject;
1969
1970 if (MapHeap && DesktopObject != NULL)
1971 {
1972 Status = IntMapDesktopView(DesktopObject);
1973 if (!NT_SUCCESS(Status))
1974 {
1975 SetLastNtError(Status);
1976 return FALSE;
1977 }
1978 }
1979
1980 /* Hack for system threads */
1981 if (NtCurrentTeb())
1982 {
1983 PCLIENTINFO pci = GetWin32ClientInfo();
1984 pci->ulClientDelta = DesktopHeapGetUserDelta();
1985 if (DesktopObject)
1986 {
1987 pci->pDeskInfo = (PVOID)((ULONG_PTR)DesktopObject->pDeskInfo - pci->ulClientDelta);
1988 }
1989 }
1990
1991 if (OldDesktop != NULL &&
1992 !IntCheckProcessDesktopClasses(OldDesktop,
1993 FreeOnFailure))
1994 {
1995 DPRINT1("Failed to move process classes to shared heap!\n");
1996
1997 /* failed to move desktop classes to the shared heap,
1998 unmap the view and return the error */
1999 if (MapHeap && DesktopObject != NULL)
2000 IntUnmapDesktopView(DesktopObject);
2001
2002 return FALSE;
2003 }
2004
2005 /* Remove the thread from the old desktop's list */
2006 RemoveEntryList(&W32Thread->PtiLink);
2007
2008 if (DesktopObject != NULL)
2009 {
2010 ObReferenceObject(DesktopObject);
2011 /* Insert into new desktop's list */
2012 InsertTailList(&DesktopObject->PtiList, &W32Thread->PtiLink);
2013 }
2014
2015 if (OldDesktop != NULL)
2016 {
2017 if (MapHeap)
2018 {
2019 IntUnmapDesktopView(OldDesktop);
2020 }
2021
2022 ObDereferenceObject(OldDesktop);
2023 }
2024 }
2025
2026 return TRUE;
2027 }
2028
2029 /*
2030 * NtUserSetThreadDesktop
2031 *
2032 * Status
2033 * @implemented
2034 */
2035
2036 BOOL APIENTRY
2037 NtUserSetThreadDesktop(HDESK hDesktop)
2038 {
2039 PDESKTOP DesktopObject;
2040 NTSTATUS Status;
2041 DECLARE_RETURN(BOOL);
2042
2043 UserEnterExclusive();
2044 DPRINT("Enter NtUserSetThreadDesktop\n");
2045
2046 /* Validate the new desktop. */
2047 Status = IntValidateDesktopHandle(
2048 hDesktop,
2049 UserMode,
2050 0,
2051 &DesktopObject);
2052
2053 if (!NT_SUCCESS(Status))
2054 {
2055 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
2056 RETURN(FALSE);
2057 }
2058
2059 /* FIXME: Should check here to see if the thread has any windows. */
2060
2061 if (!IntSetThreadDesktop(DesktopObject,
2062 FALSE))
2063 {
2064 RETURN(FALSE);
2065 }
2066
2067 RETURN(TRUE);
2068
2069 CLEANUP:
2070 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
2071 UserLeave();
2072 END_CLEANUP;
2073 }
2074
2075 /* EOF */