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