2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2006 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
27 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
39 /* WINDOWCLASS ***************************************************************/
42 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class
)
44 /* free the menu name, if it was changed and allocated */
45 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
47 UserHeapFree(Class
->MenuName
);
48 Class
->MenuName
= NULL
;
49 Class
->AnsiMenuName
= NULL
;
54 IntDestroyClass(IN OUT PWINDOWCLASS Class
)
56 /* there shouldn't be any clones anymore */
57 //ASSERT(Class->Windows == 0);
60 DPRINT1("FIXME: W3Seek's Class Patch is broken!\n");
63 ASSERT(Class
->Clone
== NULL
);
65 if (Class
->Base
== Class
)
67 /* destruct resources shared with clones */
68 if (!Class
->System
&& Class
->CallProc
!= NULL
)
70 DestroyCallProc(Class
->GlobalCallProc
? NULL
: Class
->Desktop
,
74 if (Class
->CallProc2
!= NULL
)
76 DestroyCallProc(Class
->GlobalCallProc2
? NULL
: Class
->Desktop
,
80 IntFreeClassMenuName(Class
);
83 /* free the structure */
84 if (Class
->Desktop
!= NULL
)
86 DesktopHeapFree(Class
->Desktop
,
96 /* clean all process classes. all process windows must cleaned first!! */
97 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
100 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
104 /* free all local classes */
105 Class
= pi
->LocalClassList
;
106 while (Class
!= NULL
)
108 pi
->LocalClassList
= Class
->Next
;
110 ASSERT(Class
->Base
== Class
);
111 IntDestroyClass(Class
);
113 Class
= pi
->LocalClassList
;
116 /* free all global classes */
117 Class
= pi
->GlobalClassList
;
118 while (Class
!= NULL
)
120 pi
->GlobalClassList
= Class
->Next
;
122 ASSERT(Class
->Base
== Class
);
123 IntDestroyClass(Class
);
125 Class
= pi
->GlobalClassList
;
128 /* free all system classes */
129 Class
= pi
->SystemClassList
;
130 while (Class
!= NULL
)
132 pi
->SystemClassList
= Class
->Next
;
134 ASSERT(Class
->Base
== Class
);
135 IntDestroyClass(Class
);
137 Class
= pi
->SystemClassList
;
143 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
150 if (ClassName
->Length
!= 0)
152 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
153 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
155 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
162 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
166 AtomName
= ClassName
->Buffer
;
168 Status
= RtlAddAtomToAtomTable(gAtomTable
,
172 if (!NT_SUCCESS(Status
))
174 SetLastNtError(Status
);
182 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
184 return RtlDeleteAtomFromAtomTable(gAtomTable
,
189 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
190 IN PUNICODE_STRING ClassName
)
192 RTL_ATOM Atom
= (RTL_ATOM
)0;
194 /* update the base class first */
197 if (!IntRegisterClassAtom(ClassName
,
203 IntDeregisterClassAtom(Class
->Atom
);
207 /* update the clones */
208 Class
= Class
->Clone
;
209 while (Class
!= NULL
)
220 IntGetClassWndProc(IN PWINDOWCLASS Class
,
221 IN PW32PROCESSINFO pi
,
223 IN BOOL UseCallProc2
)
225 ASSERT(UserIsEnteredExclusive() == TRUE
);
229 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
233 if (!Ansi
== Class
->Unicode
)
235 return Class
->WndProc
;
239 PCALLPROC
*CallProcPtr
;
240 PWINDOWCLASS BaseClass
;
242 /* make sure the call procedures are located on the desktop
243 of the base class! */
244 BaseClass
= Class
->Base
;
247 CallProcPtr
= (UseCallProc2
? &Class
->CallProc2
: &Class
->CallProc
);
249 if (*CallProcPtr
!= NULL
)
251 return GetCallProcHandle(*CallProcPtr
);
255 PCALLPROC NewCallProc
;
260 NewCallProc
= CreateCallProc(Class
->Desktop
,
264 if (NewCallProc
== NULL
)
266 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
270 *CallProcPtr
= NewCallProc
;
272 if (Class
->Desktop
== NULL
)
275 Class
->GlobalCallProc2
= TRUE
;
277 Class
->GlobalCallProc
= TRUE
;
280 /* update the clones */
281 Class
= Class
->Clone
;
282 while (Class
!= NULL
)
286 Class
->CallProc2
= NewCallProc
;
287 Class
->GlobalCallProc2
= BaseClass
->GlobalCallProc2
;
291 Class
->CallProc
= NewCallProc
;
292 Class
->GlobalCallProc
= BaseClass
->GlobalCallProc
;
298 return GetCallProcHandle(NewCallProc
);
305 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
313 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
314 SetLastWin32Error(ERROR_ACCESS_DENIED
);
318 /* update the base class first */
321 /* resolve any callproc handle if possible */
322 if (IsCallProcHandle(WndProc
))
326 if (UserGetCallProcInfo((HANDLE
)WndProc
,
329 WndProc
= wpInfo
.WindowProc
;
330 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
334 Ret
= IntGetClassWndProc(Class
,
343 /* update the class info */
344 Class
->Unicode
= !Ansi
;
345 Class
->WndProc
= WndProc
;
346 if (Class
->CallProc
!= NULL
)
348 Class
->CallProc
->WndProc
= WndProc
;
349 Class
->CallProc
->Unicode
= !Ansi
;
352 /* update the clones */
353 Class
= Class
->Clone
;
354 while (Class
!= NULL
)
356 Class
->Unicode
= !Ansi
;
357 Class
->WndProc
= WndProc
;
366 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
367 IN OUT PWINDOWCLASS
*ClassLink
,
373 ASSERT(Desktop
!= NULL
);
374 ASSERT(BaseClass
->Base
== BaseClass
);
376 if (BaseClass
->Desktop
== Desktop
)
378 /* it is most likely that a window is created on the same
379 desktop as the window class. */
384 if (BaseClass
->Desktop
== NULL
)
386 ASSERT(BaseClass
->Windows
== 0);
387 ASSERT(BaseClass
->Clone
== NULL
);
389 /* Classes are also located in the shared heap when the class
390 was created before the thread attached to a desktop. As soon
391 as a window is created for such a class located on the shared
392 heap, the class is cloned into the desktop heap on which the
393 window is created. */
398 /* The user is asking for a class object on a different desktop,
400 Class
= BaseClass
->Clone
;
401 while (Class
!= NULL
)
403 if (Class
->Desktop
== Desktop
)
405 ASSERT(Class
->Base
== BaseClass
);
406 ASSERT(Class
->Clone
== NULL
);
416 /* The window is created on a different desktop, we need to
417 clone the class object to the desktop heap of the window! */
418 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
420 Class
= DesktopHeapAlloc(Desktop
,
424 /* simply clone the class */
429 /* update some pointers and link the class */
430 Class
->Desktop
= Desktop
;
433 if (BaseClass
->Desktop
== NULL
)
435 /* we don't really need the base class on the shared
436 heap anymore, delete it so the only class left is
437 the clone we just created, which now serves as the
439 ASSERT(BaseClass
->Clone
== NULL
);
440 ASSERT(Class
->Clone
== NULL
);
442 Class
->Next
= BaseClass
->Next
;
444 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
)
445 Class
->GlobalCallProc
= TRUE
;
446 if (BaseClass
->CallProc2
!= NULL
)
447 Class
->GlobalCallProc2
= TRUE
;
449 /* replace the base class */
450 (void)InterlockedExchangePointer(ClassLink
,
453 /* destroy the obsolete copy on the shared heap */
454 BaseClass
->Base
= NULL
;
455 BaseClass
->Clone
= NULL
;
456 IntDestroyClass(BaseClass
);
460 /* link in the clone */
462 Class
->Base
= BaseClass
;
463 Class
->Next
= BaseClass
->Clone
;
464 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
470 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
478 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
479 IN OUT PWINDOWCLASS
*ClassLink
,
484 ASSERT(BaseClass
->Base
== BaseClass
);
486 Class
= IntGetClassForDesktop(BaseClass
,
498 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
499 IN OUT PWINDOWCLASS
*BaseClassLink
,
500 IN OUT PWINDOWCLASS
*CloneLink
)
502 PWINDOWCLASS Clone
, BaseClass
;
505 ASSERT(Class
->Base
!= Class
);
506 ASSERT(Class
->Base
->Clone
!= NULL
);
507 ASSERT(Class
->Desktop
!= NULL
);
508 ASSERT(Class
->Windows
!= 0);
509 ASSERT(Class
->Base
->Desktop
!= NULL
);
510 ASSERT(Class
->Base
->Windows
== 0);
512 /* unlink the clone */
513 *CloneLink
= Class
->Next
;
514 Class
->Clone
= Class
->Base
->Clone
;
516 BaseClass
= Class
->Base
;
518 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
&&
519 !BaseClass
->GlobalCallProc
)
521 /* we need to move the allocated call procedure */
522 CallProc
= BaseClass
->CallProc
;
523 Class
->CallProc
= CloneCallProc(Class
->Desktop
,
525 DestroyCallProc(BaseClass
->Desktop
,
529 if (BaseClass
->CallProc2
!= NULL
&&
530 !BaseClass
->GlobalCallProc2
)
532 /* we need to move the allocated call procedure */
533 CallProc
= BaseClass
->CallProc2
;
534 Class
->CallProc2
= CloneCallProc(Class
->Desktop
,
536 DestroyCallProc(BaseClass
->Desktop
,
540 /* update the class information to make it a base class */
542 Class
->Next
= (*BaseClassLink
)->Next
;
544 /* update all clones */
545 Clone
= Class
->Clone
;
546 while (Clone
!= NULL
)
548 ASSERT(Clone
->Clone
== NULL
);
552 Clone
->CallProc
= Class
->CallProc
;
553 Clone
->CallProc2
= Class
->CallProc2
;
558 /* link in the new base class */
559 (void)InterlockedExchangePointer(BaseClassLink
,
564 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
566 IN PW32PROCESSINFO pi
)
568 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
570 BaseClass
= Class
->Base
;
572 if (--Class
->Windows
== 0)
574 if (BaseClass
== Class
)
576 ASSERT(Class
->Base
== Class
);
578 /* check if there are clones of the class on other desktops,
579 link the first clone in if possible. If there are no clones
580 then leave the class on the desktop heap. It will get moved
581 to the shared heap when the thread detaches. */
582 if (BaseClass
->Clone
!= NULL
)
584 if (BaseClass
->System
)
585 PrevLink
= &pi
->SystemClassList
;
586 else if (BaseClass
->Global
)
587 PrevLink
= &pi
->GlobalClassList
;
589 PrevLink
= &pi
->LocalClassList
;
591 while (*PrevLink
!= BaseClass
)
593 ASSERT(*PrevLink
!= NULL
);
594 PrevLink
= &BaseClass
->Next
;
597 ASSERT(*PrevLink
== BaseClass
);
599 /* make the first clone become the new base class */
600 IntMakeCloneBaseClass(BaseClass
->Clone
,
604 /* destroy the class, there's still another clone of the class
605 that now serves as a base class. Make sure we don't destruct
606 resources shared by all classes (Base = NULL)! */
607 BaseClass
->Base
= NULL
;
608 BaseClass
->Clone
= NULL
;
609 IntDestroyClass(BaseClass
);
614 /* locate the cloned class and unlink it */
615 PrevLink
= &BaseClass
->Clone
;
616 CurrentClass
= BaseClass
->Clone
;
617 while (CurrentClass
!= Class
)
619 ASSERT(CurrentClass
!= NULL
);
621 PrevLink
= &CurrentClass
->Next
;
622 CurrentClass
= CurrentClass
->Next
;
625 ASSERT(CurrentClass
== Class
);
627 (void)InterlockedExchangePointer(PrevLink
,
630 ASSERT(Class
->Base
== BaseClass
);
631 ASSERT(Class
->Clone
== NULL
);
633 /* the class was just a clone, we don't need it anymore */
634 IntDestroyClass(Class
);
640 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
641 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
643 PWINDOWCLASS NewClass
;
647 ASSERT(Class
->Base
== Class
);
648 ASSERT(Class
->Desktop
!= NULL
);
649 ASSERT(Class
->Windows
== 0);
650 ASSERT(Class
->Clone
== NULL
);
652 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
654 /* allocate the new base class on the shared heap */
655 NewClass
= UserHeapAlloc(ClassSize
);
656 if (NewClass
!= NULL
)
658 RtlCopyMemory(NewClass
,
662 NewClass
->Desktop
= NULL
;
663 NewClass
->Base
= NewClass
;
665 if (!NewClass
->System
&& NewClass
->CallProc
!= NULL
&&
666 !NewClass
->GlobalCallProc
)
668 /* we need to move the allocated call procedure to the shared heap */
669 CallProc
= NewClass
->CallProc
;
670 NewClass
->CallProc
= CloneCallProc(NULL
,
672 DestroyCallProc(Class
->Desktop
,
675 NewClass
->GlobalCallProc
= TRUE
;
678 if (NewClass
->CallProc2
!= NULL
&&
679 !NewClass
->GlobalCallProc2
)
681 /* we need to move the allocated call procedure to the shared heap */
682 CallProc
= NewClass
->CallProc2
;
683 NewClass
->CallProc2
= CloneCallProc(NULL
,
685 DestroyCallProc(Class
->Desktop
,
688 NewClass
->GlobalCallProc2
= TRUE
;
691 /* replace the class in the list */
692 (void)InterlockedExchangePointer(*ClassLinkPtr
,
694 *ClassLinkPtr
= &NewClass
->Next
;
696 /* free the obsolete class on the desktop heap */
698 IntDestroyClass(Class
);
706 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
707 IN OUT PWINDOWCLASS
*ClassList
,
708 IN BOOL FreeOnFailure
,
711 PWINDOWCLASS Class
, NextClass
, *Link
;
713 /* NOTE: We only need to check base classes! When classes are no longer needed
714 on a desktop, the clones will be freed automatically as soon as possible.
715 However, we need to move base classes to the shared heap, as soon as
716 the last desktop heap where a class is allocated on is about to be destroyed.
717 If we didn't move the class to the shared heap, the class would become
720 ASSERT(Desktop
!= NULL
);
724 while (Class
!= NULL
)
726 NextClass
= Class
->Next
;
728 ASSERT(Class
->Base
== Class
);
730 if (Class
->Desktop
== Desktop
&&
733 /* there shouldn't be any clones around anymore! */
734 ASSERT(Class
->Clone
== NULL
);
736 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
737 /* FIXME - We could move the class to another desktop heap if there's still desktops
738 mapped into the process... */
740 /* move the class to the shared heap */
741 if (IntMoveClassToSharedHeap(Class
,
744 ASSERT(*Link
== NextClass
);
748 ASSERT(NextClass
== Class
->Next
);
752 /* unlink the base class */
753 (void)InterlockedExchangePointer(Link
,
756 /* we can free the old base class now */
758 IntDestroyClass(Class
);
775 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
776 IN BOOL FreeOnFailure
)
781 pi
= GetW32ProcessInfo();
785 /* check all local classes */
786 IntCheckDesktopClasses(Desktop
,
791 /* check all global classes */
792 IntCheckDesktopClasses(Desktop
,
793 &pi
->GlobalClassList
,
797 /* check all system classes */
798 IntCheckDesktopClasses(Desktop
,
799 &pi
->SystemClassList
,
805 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
806 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
813 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
814 IN PUNICODE_STRING ClassName
,
815 IN PUNICODE_STRING MenuName
,
819 IN PW32PROCESSINFO pi
)
822 PWINDOWCLASS Class
= NULL
;
824 PWSTR pszMenuName
= NULL
;
825 NTSTATUS Status
= STATUS_SUCCESS
;
827 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
828 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
830 if (!IntRegisterClassAtom(ClassName
,
833 DPRINT1("Failed to register class atom!\n");
837 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
838 if (MenuName
->Length
!= 0)
840 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
841 RtlUnicodeStringToAnsiSize(MenuName
));
842 if (pszMenuName
== NULL
)
848 Class
= DesktopHeapAlloc(Desktop
,
853 /* FIXME - the class was created before being connected
854 to a desktop. It is possible for the desktop window,
855 but should it be allowed for any other case? */
856 Class
= UserHeapAlloc(ClassSize
);
864 Class
->Desktop
= Desktop
;
868 if (dwFlags
& REGISTERCLASS_SYSTEM
)
870 dwFlags
&= ~REGISTERCLASS_ANSI
;
871 Class
->WndProcExtra
= wpExtra
;
872 Class
->System
= TRUE
;
877 PWSTR pszMenuNameBuffer
= pszMenuName
;
879 /* need to protect with SEH since accessing the WNDCLASSEX structure
880 and string buffers might raise an exception! We don't want to
882 Class
->WndProc
= lpwcx
->lpfnWndProc
;
883 Class
->Style
= lpwcx
->style
;
884 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
885 Class
->WndExtra
= lpwcx
->cbWndExtra
;
886 Class
->hInstance
= lpwcx
->hInstance
;
887 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
888 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
889 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
890 Class
->hbrBackground
= lpwcx
->hbrBackground
;
892 /* make a copy of the string */
893 if (pszMenuNameBuffer
!= NULL
)
895 Class
->MenuNameIsString
= TRUE
;
897 Class
->MenuName
= pszMenuNameBuffer
;
898 RtlCopyMemory(Class
->MenuName
,
901 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
903 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
906 Class
->MenuName
= MenuName
->Buffer
;
908 /* save an ansi copy of the string */
909 if (pszMenuNameBuffer
!= NULL
)
911 ANSI_STRING AnsiString
;
913 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
914 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
915 AnsiString
.Buffer
= Class
->AnsiMenuName
;
916 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
919 if (!NT_SUCCESS(Status
))
921 DPRINT1("Failed to convert unicode menu name to ansi!\n");
923 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
928 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
930 if (!(dwFlags
& REGISTERCLASS_ANSI
))
931 Class
->Unicode
= TRUE
;
933 if (Class
->Style
& CS_GLOBALCLASS
)
934 Class
->Global
= TRUE
;
938 Status
= _SEH_GetExceptionCode();
942 if (!NT_SUCCESS(Status
))
944 DPRINT1("Failed creating the class: 0x%x\n", Status
);
946 SetLastNtError(Status
);
948 if (pszMenuName
!= NULL
)
949 UserHeapFree(pszMenuName
);
951 DesktopHeapFree(Desktop
,
955 IntDeregisterClassAtom(Atom
);
961 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
963 if (pszMenuName
!= NULL
)
964 UserHeapFree(pszMenuName
);
966 IntDeregisterClassAtom(Atom
);
968 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
975 IntFindClass(IN RTL_ATOM Atom
,
976 IN HINSTANCE hInstance
,
977 IN PWINDOWCLASS
*ClassList
,
978 OUT PWINDOWCLASS
**Link OPTIONAL
)
980 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
983 while (Class
!= NULL
)
985 if (Class
->Atom
== Atom
&&
986 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
989 ASSERT(Class
->Base
== Class
);
996 PrevLink
= &Class
->Next
;
1004 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1009 if (ClassName
->Length
!= 0)
1015 /* NOTE: Caller has to protect the call with SEH! */
1017 if (ClassName
->Length
!= 0)
1019 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1020 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1022 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1026 /* We need to make a local copy of the class name! The caller could
1027 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1028 We're protected by SEH, but the ranges that might be accessed were
1030 RtlCopyMemory(szBuf
,
1033 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1037 AtomName
= ClassName
->Buffer
;
1039 /* lookup the atom */
1040 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1043 if (NT_SUCCESS(Status
))
1049 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1051 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1055 SetLastNtError(Status
);
1061 ASSERT(IS_ATOM(ClassName
->Buffer
));
1062 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1070 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1071 IN HINSTANCE hInstance OPTIONAL
,
1072 IN PW32PROCESSINFO pi OPTIONAL
,
1073 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1074 OUT PWINDOWCLASS
**Link OPTIONAL
)
1076 RTL_ATOM Atom
= (RTL_ATOM
)0;
1078 if (IntGetAtomFromStringOrAtom(ClassName
,
1080 BaseClass
!= NULL
&& Atom
!= (RTL_ATOM
)0)
1084 /* attempt to locate the class object */
1088 /* Step 1: try to find an exact match of locally registered classes */
1089 Class
= IntFindClass(Atom
,
1091 &pi
->LocalClassList
,
1098 /* Step 2: try to find any globally registered class. The hInstance
1099 is not relevant for global classes */
1100 Class
= IntFindClass(Atom
,
1102 &pi
->GlobalClassList
,
1109 /* Step 3: try to find any local class registered by user32 */
1110 Class
= IntFindClass(Atom
,
1112 &pi
->LocalClassList
,
1119 /* Step 4: try to find any global class registered by user32 */
1120 Class
= IntFindClass(Atom
,
1122 &pi
->GlobalClassList
,
1129 /* Step 5: try to find a system class */
1130 Class
= IntFindClass(Atom
,
1132 &pi
->SystemClassList
,
1137 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1149 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1150 IN PUNICODE_STRING ClassName
,
1151 IN PUNICODE_STRING MenuName
,
1152 IN HANDLE hMenu
, /* FIXME */
1160 RTL_ATOM Ret
= (RTL_ATOM
)0;
1162 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1164 ti
= GetW32ThreadInfo();
1167 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1173 /* try to find a previously registered class */
1174 ClassAtom
= IntGetClassAtom(ClassName
,
1179 if (ClassAtom
!= (RTL_ATOM
)0)
1181 if (lpwcx
->style
& CS_GLOBALCLASS
)
1183 // global classes shall not have same names as system classes
1184 if (Class
->Global
|| Class
->System
)
1186 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1187 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1191 else if ( !Class
->Global
&& !Class
->System
)
1193 // local class already exists
1194 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1195 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1200 Class
= IntCreateClass(lpwcx
,
1212 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1213 Class
->hMenu
= hMenu
;
1215 /* Register the class */
1217 List
= &pi
->SystemClassList
;
1218 else if (Class
->Global
)
1219 List
= &pi
->GlobalClassList
;
1221 List
= &pi
->LocalClassList
;
1223 Class
->Next
= *List
;
1224 (void)InterlockedExchangePointer(List
,
1234 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1235 IN HINSTANCE hInstance
)
1242 pi
= GetW32ProcessInfo();
1245 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1249 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1250 ClassAtom
= IntGetClassAtom(ClassName
,
1255 if (ClassAtom
== (RTL_ATOM
)0)
1260 ASSERT(Class
!= NULL
);
1262 if (Class
->Windows
!= 0 ||
1263 Class
->Clone
!= NULL
)
1265 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1269 /* must be a base class! */
1270 ASSERT(Class
->Base
== Class
);
1272 /* unlink the class */
1273 *Link
= Class
->Next
;
1275 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1277 /* finally free the resources */
1278 IntDestroyClass(Class
);
1285 UserGetClassName(IN PWINDOWCLASS Class
,
1286 IN OUT PUNICODE_STRING ClassName
,
1289 NTSTATUS Status
= STATUS_SUCCESS
;
1290 WCHAR szStaticTemp
[32];
1291 PWSTR szTemp
= NULL
;
1292 ULONG BufLen
= sizeof(szStaticTemp
);
1295 /* Note: Accessing the buffer in ClassName may raise an exception! */
1301 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1302 UNICODE_STRING UnicodeClassName
;
1304 /* limit the size of the static buffer on the stack to the
1305 size of the buffer provided by the caller */
1306 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1308 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1311 /* find out how big the buffer needs to be */
1312 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1318 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1320 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1322 /* the buffer required exceeds the ansi buffer provided,
1323 pretend like we're using the ansi buffer and limit the
1324 size to the buffer size provided */
1325 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1328 /* allocate a temporary buffer that can hold the unicode class name */
1329 szTemp
= ExAllocatePool(PagedPool
,
1333 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1337 /* query the class name */
1338 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1346 szTemp
= szStaticTemp
;
1348 if (NT_SUCCESS(Status
))
1350 /* convert the atom name to ansi */
1352 RtlInitUnicodeString(&UnicodeClassName
,
1355 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1358 if (!NT_SUCCESS(Status
))
1360 SetLastNtError(Status
);
1365 Ret
= BufLen
/ sizeof(WCHAR
);
1369 BufLen
= ClassName
->MaximumLength
;
1371 /* query the atom name */
1372 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1379 if (!NT_SUCCESS(Status
))
1381 SetLastNtError(Status
);
1385 Ret
= BufLen
/ sizeof(WCHAR
);
1390 SetLastNtError(_SEH_GetExceptionCode());
1394 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1403 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1413 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1414 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1416 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1420 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1422 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1423 certain architectures, maybe using RtlCopyMemory is a
1424 better choice for those architectures! */
1430 case GCL_CBWNDEXTRA
:
1431 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1434 case GCL_CBCLSEXTRA
:
1435 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1438 case GCLP_HBRBACKGROUND
:
1439 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1443 /* FIXME - get handle from pointer to CURSOR object */
1444 Ret
= (ULONG_PTR
)Class
->hCursor
;
1448 /* FIXME - get handle from pointer to ICON object */
1449 Ret
= (ULONG_PTR
)Class
->hIcon
;
1453 /* FIXME - get handle from pointer to ICON object */
1454 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1458 Ret
= (ULONG_PTR
)Class
->hInstance
;
1462 /* NOTE: Returns pointer in kernel heap! */
1464 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1466 Ret
= (ULONG_PTR
)Class
->MenuName
;
1470 Ret
= (ULONG_PTR
)Class
->Style
;
1474 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1475 GetW32ProcessInfo(),
1481 Ret
= (ULONG_PTR
)Class
->Atom
;
1485 SetLastWin32Error(ERROR_INVALID_INDEX
);
1493 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1494 IN PUNICODE_STRING MenuName
)
1498 /* change the base class first */
1499 Class
= Class
->Base
;
1501 if (MenuName
->Length
!= 0)
1503 ANSI_STRING AnsiString
;
1506 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1508 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1509 AnsiString
.MaximumLength
);
1510 if (strBufW
!= NULL
)
1516 /* copy the unicode string */
1517 RtlCopyMemory(strBufW
,
1520 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1522 /* create an ansi copy of the string */
1523 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1524 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1527 if (!NT_SUCCESS(Status
))
1529 SetLastNtError(Status
);
1537 SetLastNtError(_SEH_GetExceptionCode());
1543 /* update the base class */
1544 IntFreeClassMenuName(Class
);
1545 Class
->MenuName
= strBufW
;
1546 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1547 Class
->MenuNameIsString
= TRUE
;
1549 /* update the clones */
1550 Class
= Class
->Clone
;
1551 while (Class
!= NULL
)
1553 Class
->MenuName
= strBufW
;
1554 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1555 Class
->MenuNameIsString
= TRUE
;
1557 Class
= Class
->Next
;
1562 DPRINT1("Failed to copy class menu name!\n");
1563 UserHeapFree(strBufW
);
1567 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1571 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1573 /* update the base class */
1574 IntFreeClassMenuName(Class
);
1575 Class
->MenuName
= MenuName
->Buffer
;
1576 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1577 Class
->MenuNameIsString
= FALSE
;
1579 /* update the clones */
1580 Class
= Class
->Clone
;
1581 while (Class
!= NULL
)
1583 Class
->MenuName
= MenuName
->Buffer
;
1584 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1585 Class
->MenuNameIsString
= FALSE
;
1587 Class
= Class
->Next
;
1597 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1599 IN ULONG_PTR NewLong
,
1604 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1606 /* change the information in the base class first, then update the clones */
1607 Class
= Class
->Base
;
1613 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1614 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1616 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1620 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1622 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1623 certain architectures, maybe using RtlCopyMemory is a
1624 better choice for those architectures! */
1628 /* update the clones */
1629 Class
= Class
->Clone
;
1630 while (Class
!= NULL
)
1632 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1633 Class
= Class
->Next
;
1641 case GCL_CBWNDEXTRA
:
1642 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1643 Class
->WndExtra
= (INT
)NewLong
;
1645 /* update the clones */
1646 Class
= Class
->Clone
;
1647 while (Class
!= NULL
)
1649 Class
->WndExtra
= (INT
)NewLong
;
1650 Class
= Class
->Next
;
1655 case GCL_CBCLSEXTRA
:
1656 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1659 case GCLP_HBRBACKGROUND
:
1660 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1661 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1663 /* update the clones */
1664 Class
= Class
->Clone
;
1665 while (Class
!= NULL
)
1667 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1668 Class
= Class
->Next
;
1673 /* FIXME - get handle from pointer to CURSOR object */
1674 Ret
= (ULONG_PTR
)Class
->hCursor
;
1675 Class
->hCursor
= (HANDLE
)NewLong
;
1677 /* update the clones */
1678 Class
= Class
->Clone
;
1679 while (Class
!= NULL
)
1681 Class
->hCursor
= (HANDLE
)NewLong
;
1682 Class
= Class
->Next
;
1687 /* FIXME - get handle from pointer to ICON object */
1688 Ret
= (ULONG_PTR
)Class
->hIcon
;
1689 Class
->hIcon
= (HANDLE
)NewLong
;
1691 /* update the clones */
1692 Class
= Class
->Clone
;
1693 while (Class
!= NULL
)
1695 Class
->hIcon
= (HANDLE
)NewLong
;
1696 Class
= Class
->Next
;
1701 /* FIXME - get handle from pointer to ICON object */
1702 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1703 Class
->hIconSm
= (HANDLE
)NewLong
;
1705 /* update the clones */
1706 Class
= Class
->Clone
;
1707 while (Class
!= NULL
)
1709 Class
->hIconSm
= (HANDLE
)NewLong
;
1710 Class
= Class
->Next
;
1715 Ret
= (ULONG_PTR
)Class
->hInstance
;
1716 Class
->hInstance
= (HINSTANCE
)NewLong
;
1718 /* update the clones */
1719 Class
= Class
->Clone
;
1720 while (Class
!= NULL
)
1722 Class
->hInstance
= (HINSTANCE
)NewLong
;
1723 Class
= Class
->Next
;
1729 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1731 if (!IntSetClassMenuName(Class
,
1734 DPRINT("Setting the class menu name failed!\n");
1737 /* FIXME - really return NULL? Wine does so... */
1742 Ret
= (ULONG_PTR
)Class
->Style
;
1743 Class
->Style
= (UINT
)NewLong
;
1745 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1746 move the class to the appropriate list? For now, we save
1747 the original value in Class->Global, so we can always
1748 locate the appropriate list */
1750 /* update the clones */
1751 Class
= Class
->Clone
;
1752 while (Class
!= NULL
)
1754 Class
->Style
= (UINT
)NewLong
;
1755 Class
= Class
->Next
;
1760 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1767 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1769 Ret
= (ULONG_PTR
)Class
->Atom
;
1770 if (!IntSetClassAtom(Class
,
1779 SetLastWin32Error(ERROR_INVALID_INDEX
);
1787 UserGetClassInfo(IN PWINDOWCLASS Class
,
1788 OUT PWNDCLASSEXW lpwcx
,
1790 HINSTANCE hInstance
)
1794 lpwcx
->style
= Class
->Style
;
1796 pi
= GetW32ProcessInfo();
1797 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1802 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1803 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1804 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1805 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1806 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1809 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1811 lpwcx
->lpszMenuName
= Class
->MenuName
;
1813 if (Class
->hInstance
== pi
->hModUser
)
1814 lpwcx
->hInstance
= NULL
;
1816 lpwcx
->hInstance
= Class
->hInstance
;
1818 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1820 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1825 /* SYSCALLS *****************************************************************/
1829 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1830 IN PUNICODE_STRING ClassName
,
1831 IN PUNICODE_STRING MenuName
,
1838 * Registers a new class with the window manager
1840 * lpwcx = Win32 extended window class structure
1841 * bUnicodeClass = Whether to send ANSI or unicode strings
1842 * to window procedures
1843 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1845 * Atom identifying the new class
1848 WNDCLASSEXW CapturedClassInfo
= {0};
1849 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1850 RTL_ATOM Ret
= (RTL_ATOM
)0;
1852 if (Flags
& ~REGISTERCLASS_ALL
)
1854 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1858 UserEnterExclusive();
1862 /* Probe the parameters and basic parameter checks */
1863 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1865 goto InvalidParameter
;
1869 sizeof(WNDCLASSEXW
),
1871 RtlCopyMemory(&CapturedClassInfo
,
1873 sizeof(WNDCLASSEXW
));
1875 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1876 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1878 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1879 CapturedClassInfo
.cbClsExtra
< 0 ||
1880 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1881 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1882 CapturedClassInfo
.cbWndExtra
< 0 ||
1883 CapturedClassInfo
.hInstance
== NULL
)
1885 goto InvalidParameter
;
1888 if (CapturedName
.Length
!= 0)
1890 ProbeForRead(CapturedName
.Buffer
,
1891 CapturedName
.Length
,
1896 if (!IS_ATOM(CapturedName
.Buffer
))
1898 goto InvalidParameter
;
1902 if (CapturedMenuName
.Length
!= 0)
1904 ProbeForRead(CapturedMenuName
.Buffer
,
1905 CapturedMenuName
.Length
,
1908 else if (CapturedMenuName
.Buffer
!= NULL
&&
1909 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1912 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1916 /* Register the class */
1917 Ret
= UserRegisterClass(&CapturedClassInfo
,
1920 hMenu
, /* FIXME - pass pointer */
1927 SetLastNtError(_SEH_GetExceptionCode());
1939 NtUserGetClassLong(IN HWND hWnd
,
1943 PWINDOW_OBJECT Window
;
1946 if (Offset
!= GCLP_WNDPROC
)
1952 UserEnterExclusive();
1955 Window
= UserGetWindowObject(hWnd
);
1958 Ret
= UserGetClassLongPtr(Window
->Class
,
1962 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Class
->MenuNameIsString
)
1964 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
1976 NtUserSetClassLong(HWND hWnd
,
1978 ULONG_PTR dwNewLong
,
1982 PWINDOW_OBJECT Window
;
1985 UserEnterExclusive();
1987 pi
= GetW32ProcessInfo();
1991 Window
= UserGetWindowObject(hWnd
);
1994 if (Window
->ti
->kpi
!= pi
)
1996 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2002 UNICODE_STRING Value
;
2004 /* probe the parameters */
2005 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2007 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2008 if (Value
.Length
& 1)
2010 goto InvalidParameter
;
2013 if (Value
.Length
!= 0)
2015 ProbeForRead(Value
.Buffer
,
2021 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2023 goto InvalidParameter
;
2025 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2028 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2033 dwNewLong
= (ULONG_PTR
)&Value
;
2036 Ret
= UserSetClassLongPtr(Window
->Class
,
2043 SetLastNtError(_SEH_GetExceptionCode());
2055 NtUserSetClassWord(DWORD Unknown0
,
2063 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2064 IN HINSTANCE hInstance
)
2066 UNICODE_STRING CapturedClassName
;
2069 UserEnterExclusive();
2073 /* probe the paramters */
2074 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2075 if (CapturedClassName
.Length
& 1)
2077 goto InvalidParameter
;
2080 if (CapturedClassName
.Length
!= 0)
2082 ProbeForRead(CapturedClassName
.Buffer
,
2083 CapturedClassName
.Length
,
2088 if (!IS_ATOM(CapturedClassName
.Buffer
))
2091 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2096 /* unregister the class */
2097 Ret
= UserUnregisterClass(&CapturedClassName
,
2102 SetLastNtError(_SEH_GetExceptionCode());
2111 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2114 HINSTANCE hInstance
,
2115 PUNICODE_STRING ClassName
,
2116 LPWNDCLASSEXW lpWndClassEx
,
2119 UNICODE_STRING CapturedClassName
;
2125 /* NOTE: need exclusive lock because getting the wndproc might require the
2126 creation of a call procedure handle */
2127 UserEnterExclusive();
2129 pi
= GetW32ProcessInfo();
2132 ERR("GetW32ProcessInfo() returned NULL!\n");
2137 /* probe the paramters */
2138 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2140 if (CapturedClassName
.Length
== 0)
2141 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2143 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2145 if (CapturedClassName
.Length
& 1)
2147 goto InvalidParameter
;
2150 if (CapturedClassName
.Length
!= 0)
2152 ProbeForRead(CapturedClassName
.Buffer
,
2153 CapturedClassName
.Length
,
2158 if (!IS_ATOM(CapturedClassName
.Buffer
))
2160 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2161 goto InvalidParameter
;
2165 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2168 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2172 ProbeForWrite(lpWndClassEx
,
2173 sizeof(WNDCLASSEXW
),
2176 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2181 if (ClassAtom
!= (RTL_ATOM
)0)
2183 if (hInstance
== NULL
)
2184 hInstance
= pi
->hModUser
;
2186 Ret
= UserGetClassInfo(Class
,
2193 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2194 /* FIXME - handle Class->Desktop == NULL!!!!! */
2196 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2198 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2199 (PVOID
)Class
->AnsiMenuName
:
2200 (PVOID
)Class
->MenuName
);
2203 /* Undocumented behavior! Return the class atom as a BOOL! */
2204 Ret
= (BOOL
)ClassAtom
;
2209 if (CapturedClassName
.Length
== 0)
2210 WARN("Tried to get information of a non-existing class atom 0x%p\n", CapturedClassName
.Buffer
);
2212 WARN("Tried to get information of a non-existing class \"%wZ\"\n", &CapturedClassName
);
2213 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2218 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2230 NtUserGetClassName (IN HWND hWnd
,
2231 OUT PUNICODE_STRING ClassName
,
2234 PWINDOW_OBJECT Window
;
2235 UNICODE_STRING CapturedClassName
;
2240 Window
= UserGetWindowObject(hWnd
);
2245 ProbeForWriteUnicodeString(ClassName
);
2246 CapturedClassName
= *ClassName
;
2248 /* get the class name */
2249 Ret
= UserGetClassName(Window
->Class
,
2255 /* update the Length field */
2256 ClassName
->Length
= CapturedClassName
.Length
;
2261 SetLastNtError(_SEH_GetExceptionCode());
2272 NtUserGetWOWClass(DWORD Unknown0
,