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);
58 ASSERT(Class
->Clone
== NULL
);
60 if (Class
->Base
== Class
)
62 PCALLPROC CallProc
, NextCallProc
;
64 /* Destroy allocated callproc handles */
65 CallProc
= Class
->CallProcList
;
66 while (CallProc
!= NULL
)
68 NextCallProc
= CallProc
->Next
;
70 CallProc
->Next
= NULL
;
74 CallProc
= NextCallProc
;
77 IntFreeClassMenuName(Class
);
80 /* free the structure */
81 if (Class
->Desktop
!= NULL
)
83 DesktopHeapFree(Class
->Desktop
,
93 /* clean all process classes. all process windows must cleaned first!! */
94 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
97 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
101 /* free all local classes */
102 Class
= pi
->LocalClassList
;
103 while (Class
!= NULL
)
105 pi
->LocalClassList
= Class
->Next
;
107 ASSERT(Class
->Base
== Class
);
108 IntDestroyClass(Class
);
110 Class
= pi
->LocalClassList
;
113 /* free all global classes */
114 Class
= pi
->GlobalClassList
;
115 while (Class
!= NULL
)
117 pi
->GlobalClassList
= Class
->Next
;
119 ASSERT(Class
->Base
== Class
);
120 IntDestroyClass(Class
);
122 Class
= pi
->GlobalClassList
;
125 /* free all system classes */
126 Class
= pi
->SystemClassList
;
127 while (Class
!= NULL
)
129 pi
->SystemClassList
= Class
->Next
;
131 ASSERT(Class
->Base
== Class
);
132 IntDestroyClass(Class
);
134 Class
= pi
->SystemClassList
;
140 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
147 if (ClassName
->Length
!= 0)
149 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
150 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
152 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
159 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
163 AtomName
= ClassName
->Buffer
;
165 Status
= RtlAddAtomToAtomTable(gAtomTable
,
169 if (!NT_SUCCESS(Status
))
171 SetLastNtError(Status
);
179 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
181 return RtlDeleteAtomFromAtomTable(gAtomTable
,
186 UserFindCallProc(IN PWINDOWCLASS Class
,
192 CallProc
= Class
->CallProcList
;
193 while (CallProc
!= NULL
)
195 if (CallProc
->WndProc
== WndProc
&&
196 CallProc
->Unicode
== (UINT
)bUnicode
)
201 CallProc
= CallProc
->Next
;
208 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class
,
209 IN PCALLPROC CallProc
)
211 PWINDOWCLASS BaseClass
;
213 ASSERT(CallProc
->Next
== NULL
);
215 BaseClass
= Class
->Base
;
216 ASSERT(CallProc
->Next
== NULL
);
217 CallProc
->Next
= BaseClass
->CallProcList
;
218 BaseClass
->CallProcList
= CallProc
;
220 /* Update all clones */
221 Class
= Class
->Clone
;
222 while (Class
!= NULL
)
224 Class
->CallProcList
= BaseClass
->CallProcList
;
230 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
231 IN PUNICODE_STRING ClassName
)
233 RTL_ATOM Atom
= (RTL_ATOM
)0;
235 /* update the base class first */
238 if (!IntRegisterClassAtom(ClassName
,
244 IntDeregisterClassAtom(Class
->Atom
);
248 /* update the clones */
249 Class
= Class
->Clone
;
250 while (Class
!= NULL
)
261 IntGetClassWndProc(IN PWINDOWCLASS Class
,
262 IN PW32PROCESSINFO pi
,
265 ASSERT(UserIsEnteredExclusive() == TRUE
);
269 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
273 if (!Ansi
== Class
->Unicode
)
275 return Class
->WndProc
;
279 PWINDOWCLASS BaseClass
;
281 /* make sure the call procedures are located on the desktop
282 of the base class! */
283 BaseClass
= Class
->Base
;
286 if (Class
->CallProc
!= NULL
)
288 return GetCallProcHandle(Class
->CallProc
);
292 PCALLPROC NewCallProc
;
297 NewCallProc
= UserFindCallProc(Class
,
300 if (NewCallProc
== NULL
)
302 NewCallProc
= CreateCallProc(NULL
,
306 if (NewCallProc
== NULL
)
308 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
312 UserAddCallProcToClass(Class
,
316 Class
->CallProc
= NewCallProc
;
318 /* update the clones */
319 Class
= Class
->Clone
;
320 while (Class
!= NULL
)
322 Class
->CallProc
= NewCallProc
;
327 return GetCallProcHandle(NewCallProc
);
334 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
342 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
343 SetLastWin32Error(ERROR_ACCESS_DENIED
);
347 /* update the base class first */
350 /* resolve any callproc handle if possible */
351 if (IsCallProcHandle(WndProc
))
355 if (UserGetCallProcInfo((HANDLE
)WndProc
,
358 WndProc
= wpInfo
.WindowProc
;
359 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
363 Ret
= IntGetClassWndProc(Class
,
371 /* update the class info */
372 Class
->Unicode
= !Ansi
;
373 Class
->WndProc
= WndProc
;
375 /* update the clones */
376 Class
= Class
->Clone
;
377 while (Class
!= NULL
)
379 Class
->Unicode
= !Ansi
;
380 Class
->WndProc
= WndProc
;
389 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
390 IN OUT PWINDOWCLASS
*ClassLink
,
396 ASSERT(Desktop
!= NULL
);
397 ASSERT(BaseClass
->Base
== BaseClass
);
399 if (BaseClass
->Desktop
== Desktop
)
401 /* it is most likely that a window is created on the same
402 desktop as the window class. */
407 if (BaseClass
->Desktop
== NULL
)
409 ASSERT(BaseClass
->Windows
== 0);
410 ASSERT(BaseClass
->Clone
== NULL
);
412 /* Classes are also located in the shared heap when the class
413 was created before the thread attached to a desktop. As soon
414 as a window is created for such a class located on the shared
415 heap, the class is cloned into the desktop heap on which the
416 window is created. */
421 /* The user is asking for a class object on a different desktop,
423 Class
= BaseClass
->Clone
;
424 while (Class
!= NULL
)
426 if (Class
->Desktop
== Desktop
)
428 ASSERT(Class
->Base
== BaseClass
);
429 ASSERT(Class
->Clone
== NULL
);
439 /* The window is created on a different desktop, we need to
440 clone the class object to the desktop heap of the window! */
441 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
443 Class
= DesktopHeapAlloc(Desktop
,
447 /* simply clone the class */
452 /* update some pointers and link the class */
453 Class
->Desktop
= Desktop
;
456 if (BaseClass
->Desktop
== NULL
)
458 /* we don't really need the base class on the shared
459 heap anymore, delete it so the only class left is
460 the clone we just created, which now serves as the
462 ASSERT(BaseClass
->Clone
== NULL
);
463 ASSERT(Class
->Clone
== NULL
);
465 Class
->Next
= BaseClass
->Next
;
467 /* replace the base class */
468 (void)InterlockedExchangePointer(ClassLink
,
471 /* destroy the obsolete copy on the shared heap */
472 BaseClass
->Base
= NULL
;
473 BaseClass
->Clone
= NULL
;
474 IntDestroyClass(BaseClass
);
478 /* link in the clone */
480 Class
->Base
= BaseClass
;
481 Class
->Next
= BaseClass
->Clone
;
482 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
488 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
496 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
497 IN OUT PWINDOWCLASS
*ClassLink
,
502 ASSERT(BaseClass
->Base
== BaseClass
);
504 Class
= IntGetClassForDesktop(BaseClass
,
516 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
517 IN OUT PWINDOWCLASS
*BaseClassLink
,
518 IN OUT PWINDOWCLASS
*CloneLink
)
520 PWINDOWCLASS Clone
, BaseClass
;
522 ASSERT(Class
->Base
!= Class
);
523 ASSERT(Class
->Base
->Clone
!= NULL
);
524 ASSERT(Class
->Desktop
!= NULL
);
525 ASSERT(Class
->Windows
!= 0);
526 ASSERT(Class
->Base
->Desktop
!= NULL
);
527 ASSERT(Class
->Base
->Windows
== 0);
529 /* unlink the clone */
530 *CloneLink
= Class
->Next
;
531 Class
->Clone
= Class
->Base
->Clone
;
533 BaseClass
= Class
->Base
;
535 /* update the class information to make it a base class */
537 Class
->Next
= (*BaseClassLink
)->Next
;
539 /* update all clones */
540 Clone
= Class
->Clone
;
541 while (Clone
!= NULL
)
543 ASSERT(Clone
->Clone
== NULL
);
547 Clone
->CallProc
= Class
->CallProc
;
552 /* link in the new base class */
553 (void)InterlockedExchangePointer(BaseClassLink
,
558 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
560 IN PW32PROCESSINFO pi
)
562 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
564 BaseClass
= Class
->Base
;
566 if (--Class
->Windows
== 0)
568 if (BaseClass
== Class
)
570 ASSERT(Class
->Base
== Class
);
572 /* check if there are clones of the class on other desktops,
573 link the first clone in if possible. If there are no clones
574 then leave the class on the desktop heap. It will get moved
575 to the shared heap when the thread detaches. */
576 if (BaseClass
->Clone
!= NULL
)
578 if (BaseClass
->System
)
579 PrevLink
= &pi
->SystemClassList
;
580 else if (BaseClass
->Global
)
581 PrevLink
= &pi
->GlobalClassList
;
583 PrevLink
= &pi
->LocalClassList
;
585 while (*PrevLink
!= BaseClass
)
587 ASSERT(*PrevLink
!= NULL
);
588 PrevLink
= &BaseClass
->Next
;
591 ASSERT(*PrevLink
== BaseClass
);
593 /* make the first clone become the new base class */
594 IntMakeCloneBaseClass(BaseClass
->Clone
,
598 /* destroy the class, there's still another clone of the class
599 that now serves as a base class. Make sure we don't destruct
600 resources shared by all classes (Base = NULL)! */
601 BaseClass
->Base
= NULL
;
602 BaseClass
->Clone
= NULL
;
603 IntDestroyClass(BaseClass
);
608 /* locate the cloned class and unlink it */
609 PrevLink
= &BaseClass
->Clone
;
610 CurrentClass
= BaseClass
->Clone
;
611 while (CurrentClass
!= Class
)
613 ASSERT(CurrentClass
!= NULL
);
615 PrevLink
= &CurrentClass
->Next
;
616 CurrentClass
= CurrentClass
->Next
;
619 ASSERT(CurrentClass
== Class
);
621 (void)InterlockedExchangePointer(PrevLink
,
624 ASSERT(Class
->Base
== BaseClass
);
625 ASSERT(Class
->Clone
== NULL
);
627 /* the class was just a clone, we don't need it anymore */
628 IntDestroyClass(Class
);
634 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
635 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
637 PWINDOWCLASS NewClass
;
640 ASSERT(Class
->Base
== Class
);
641 ASSERT(Class
->Desktop
!= NULL
);
642 ASSERT(Class
->Windows
== 0);
643 ASSERT(Class
->Clone
== NULL
);
645 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
647 /* allocate the new base class on the shared heap */
648 NewClass
= UserHeapAlloc(ClassSize
);
649 if (NewClass
!= NULL
)
651 RtlCopyMemory(NewClass
,
655 NewClass
->Desktop
= NULL
;
656 NewClass
->Base
= NewClass
;
658 /* replace the class in the list */
659 (void)InterlockedExchangePointer(*ClassLinkPtr
,
661 *ClassLinkPtr
= &NewClass
->Next
;
663 /* free the obsolete class on the desktop heap */
665 IntDestroyClass(Class
);
673 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
674 IN OUT PWINDOWCLASS
*ClassList
,
675 IN BOOL FreeOnFailure
,
678 PWINDOWCLASS Class
, NextClass
, *Link
;
680 /* NOTE: We only need to check base classes! When classes are no longer needed
681 on a desktop, the clones will be freed automatically as soon as possible.
682 However, we need to move base classes to the shared heap, as soon as
683 the last desktop heap where a class is allocated on is about to be destroyed.
684 If we didn't move the class to the shared heap, the class would become
687 ASSERT(Desktop
!= NULL
);
691 while (Class
!= NULL
)
693 NextClass
= Class
->Next
;
695 ASSERT(Class
->Base
== Class
);
697 if (Class
->Desktop
== Desktop
&&
700 /* there shouldn't be any clones around anymore! */
701 ASSERT(Class
->Clone
== NULL
);
703 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
704 /* FIXME - We could move the class to another desktop heap if there's still desktops
705 mapped into the process... */
707 /* move the class to the shared heap */
708 if (IntMoveClassToSharedHeap(Class
,
711 ASSERT(*Link
== NextClass
);
715 ASSERT(NextClass
== Class
->Next
);
719 /* unlink the base class */
720 (void)InterlockedExchangePointer(Link
,
723 /* we can free the old base class now */
725 IntDestroyClass(Class
);
742 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
743 IN BOOL FreeOnFailure
)
748 pi
= GetW32ProcessInfo();
752 /* check all local classes */
753 IntCheckDesktopClasses(Desktop
,
758 /* check all global classes */
759 IntCheckDesktopClasses(Desktop
,
760 &pi
->GlobalClassList
,
764 /* check all system classes */
765 IntCheckDesktopClasses(Desktop
,
766 &pi
->SystemClassList
,
772 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
773 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
780 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
781 IN PUNICODE_STRING ClassName
,
782 IN PUNICODE_STRING MenuName
,
786 IN PW32PROCESSINFO pi
)
789 PWINDOWCLASS Class
= NULL
;
791 PWSTR pszMenuName
= NULL
;
792 NTSTATUS Status
= STATUS_SUCCESS
;
794 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
795 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
797 if (!IntRegisterClassAtom(ClassName
,
800 DPRINT1("Failed to register class atom!\n");
804 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
805 if (MenuName
->Length
!= 0)
807 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
808 RtlUnicodeStringToAnsiSize(MenuName
));
809 if (pszMenuName
== NULL
)
815 Class
= DesktopHeapAlloc(Desktop
,
820 /* FIXME - the class was created before being connected
821 to a desktop. It is possible for the desktop window,
822 but should it be allowed for any other case? */
823 Class
= UserHeapAlloc(ClassSize
);
831 Class
->Desktop
= Desktop
;
835 if (dwFlags
& REGISTERCLASS_SYSTEM
)
837 dwFlags
&= ~REGISTERCLASS_ANSI
;
838 Class
->WndProcExtra
= wpExtra
;
839 Class
->System
= TRUE
;
844 PWSTR pszMenuNameBuffer
= pszMenuName
;
846 /* need to protect with SEH since accessing the WNDCLASSEX structure
847 and string buffers might raise an exception! We don't want to
849 Class
->WndProc
= lpwcx
->lpfnWndProc
;
850 Class
->Style
= lpwcx
->style
;
851 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
852 Class
->WndExtra
= lpwcx
->cbWndExtra
;
853 Class
->hInstance
= lpwcx
->hInstance
;
854 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
855 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
856 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
857 Class
->hbrBackground
= lpwcx
->hbrBackground
;
859 /* make a copy of the string */
860 if (pszMenuNameBuffer
!= NULL
)
862 Class
->MenuNameIsString
= TRUE
;
864 Class
->MenuName
= pszMenuNameBuffer
;
865 RtlCopyMemory(Class
->MenuName
,
868 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
870 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
873 Class
->MenuName
= MenuName
->Buffer
;
875 /* save an ansi copy of the string */
876 if (pszMenuNameBuffer
!= NULL
)
878 ANSI_STRING AnsiString
;
880 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
881 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
882 AnsiString
.Buffer
= Class
->AnsiMenuName
;
883 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
886 if (!NT_SUCCESS(Status
))
888 DPRINT1("Failed to convert unicode menu name to ansi!\n");
890 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
895 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
897 if (!(dwFlags
& REGISTERCLASS_ANSI
))
898 Class
->Unicode
= TRUE
;
900 if (Class
->Style
& CS_GLOBALCLASS
)
901 Class
->Global
= TRUE
;
905 Status
= _SEH_GetExceptionCode();
909 if (!NT_SUCCESS(Status
))
911 DPRINT1("Failed creating the class: 0x%x\n", Status
);
913 SetLastNtError(Status
);
915 if (pszMenuName
!= NULL
)
916 UserHeapFree(pszMenuName
);
918 DesktopHeapFree(Desktop
,
922 IntDeregisterClassAtom(Atom
);
928 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
930 if (pszMenuName
!= NULL
)
931 UserHeapFree(pszMenuName
);
933 IntDeregisterClassAtom(Atom
);
935 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
942 IntFindClass(IN RTL_ATOM Atom
,
943 IN HINSTANCE hInstance
,
944 IN PWINDOWCLASS
*ClassList
,
945 OUT PWINDOWCLASS
**Link OPTIONAL
)
947 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
950 while (Class
!= NULL
)
952 if (Class
->Atom
== Atom
&&
953 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
956 ASSERT(Class
->Base
== Class
);
963 PrevLink
= &Class
->Next
;
971 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
976 if (ClassName
->Length
!= 0)
982 /* NOTE: Caller has to protect the call with SEH! */
984 if (ClassName
->Length
!= 0)
986 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
987 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
989 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
993 /* We need to make a local copy of the class name! The caller could
994 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
995 We're protected by SEH, but the ranges that might be accessed were
1000 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1004 AtomName
= ClassName
->Buffer
;
1006 /* lookup the atom */
1007 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1010 if (NT_SUCCESS(Status
))
1016 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1018 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1022 SetLastNtError(Status
);
1028 ASSERT(IS_ATOM(ClassName
->Buffer
));
1029 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1037 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1038 IN HINSTANCE hInstance OPTIONAL
,
1039 IN PW32PROCESSINFO pi OPTIONAL
,
1040 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1041 OUT PWINDOWCLASS
**Link OPTIONAL
)
1043 RTL_ATOM Atom
= (RTL_ATOM
)0;
1045 if (IntGetAtomFromStringOrAtom(ClassName
,
1047 BaseClass
!= NULL
&& Atom
!= (RTL_ATOM
)0)
1051 /* attempt to locate the class object */
1055 /* Step 1: try to find an exact match of locally registered classes */
1056 Class
= IntFindClass(Atom
,
1058 &pi
->LocalClassList
,
1065 /* Step 2: try to find any globally registered class. The hInstance
1066 is not relevant for global classes */
1067 Class
= IntFindClass(Atom
,
1069 &pi
->GlobalClassList
,
1076 /* Step 3: try to find any local class registered by user32 */
1077 Class
= IntFindClass(Atom
,
1079 &pi
->LocalClassList
,
1086 /* Step 4: try to find any global class registered by user32 */
1087 Class
= IntFindClass(Atom
,
1089 &pi
->GlobalClassList
,
1096 /* Step 5: try to find a system class */
1097 Class
= IntFindClass(Atom
,
1099 &pi
->SystemClassList
,
1104 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1116 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1117 IN PUNICODE_STRING ClassName
,
1118 IN PUNICODE_STRING MenuName
,
1119 IN HANDLE hMenu
, /* FIXME */
1127 RTL_ATOM Ret
= (RTL_ATOM
)0;
1129 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1131 ti
= GetW32ThreadInfo();
1134 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1140 /* try to find a previously registered class */
1141 ClassAtom
= IntGetClassAtom(ClassName
,
1146 if (ClassAtom
!= (RTL_ATOM
)0)
1148 if (lpwcx
->style
& CS_GLOBALCLASS
)
1150 // global classes shall not have same names as system classes
1151 if (Class
->Global
|| Class
->System
)
1153 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1154 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1158 else if ( !Class
->Global
&& !Class
->System
)
1160 // local class already exists
1161 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1162 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1167 Class
= IntCreateClass(lpwcx
,
1179 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1180 Class
->hMenu
= hMenu
;
1182 /* Register the class */
1184 List
= &pi
->SystemClassList
;
1185 else if (Class
->Global
)
1186 List
= &pi
->GlobalClassList
;
1188 List
= &pi
->LocalClassList
;
1190 Class
->Next
= *List
;
1191 (void)InterlockedExchangePointer(List
,
1201 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1202 IN HINSTANCE hInstance
)
1209 pi
= GetW32ProcessInfo();
1212 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1216 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1218 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1219 ClassAtom
= IntGetClassAtom(ClassName
,
1224 if (ClassAtom
== (RTL_ATOM
)0)
1229 ASSERT(Class
!= NULL
);
1231 if (Class
->Windows
!= 0 ||
1232 Class
->Clone
!= NULL
)
1234 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1238 /* must be a base class! */
1239 ASSERT(Class
->Base
== Class
);
1241 /* unlink the class */
1242 *Link
= Class
->Next
;
1244 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1246 /* finally free the resources */
1247 IntDestroyClass(Class
);
1254 UserGetClassName(IN PWINDOWCLASS Class
,
1255 IN OUT PUNICODE_STRING ClassName
,
1258 NTSTATUS Status
= STATUS_SUCCESS
;
1259 WCHAR szStaticTemp
[32];
1260 PWSTR szTemp
= NULL
;
1261 ULONG BufLen
= sizeof(szStaticTemp
);
1264 /* Note: Accessing the buffer in ClassName may raise an exception! */
1270 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1271 UNICODE_STRING UnicodeClassName
;
1273 /* limit the size of the static buffer on the stack to the
1274 size of the buffer provided by the caller */
1275 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1277 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1280 /* find out how big the buffer needs to be */
1281 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1287 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1289 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1291 /* the buffer required exceeds the ansi buffer provided,
1292 pretend like we're using the ansi buffer and limit the
1293 size to the buffer size provided */
1294 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1297 /* allocate a temporary buffer that can hold the unicode class name */
1298 szTemp
= ExAllocatePool(PagedPool
,
1302 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1306 /* query the class name */
1307 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1315 szTemp
= szStaticTemp
;
1317 if (NT_SUCCESS(Status
))
1319 /* convert the atom name to ansi */
1321 RtlInitUnicodeString(&UnicodeClassName
,
1324 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1327 if (!NT_SUCCESS(Status
))
1329 SetLastNtError(Status
);
1334 Ret
= BufLen
/ sizeof(WCHAR
);
1338 BufLen
= ClassName
->MaximumLength
;
1340 /* query the atom name */
1341 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1348 if (!NT_SUCCESS(Status
))
1350 SetLastNtError(Status
);
1354 Ret
= BufLen
/ sizeof(WCHAR
);
1359 SetLastNtError(_SEH_GetExceptionCode());
1363 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1372 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1382 TRACE("GetClassLong(%d)\n", Index
);
1383 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1384 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1386 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1390 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1392 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1393 certain architectures, maybe using RtlCopyMemory is a
1394 better choice for those architectures! */
1396 TRACE("Result: %x\n", Ret
);
1402 case GCL_CBWNDEXTRA
:
1403 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1406 case GCL_CBCLSEXTRA
:
1407 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1410 case GCLP_HBRBACKGROUND
:
1411 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1415 /* FIXME - get handle from pointer to CURSOR object */
1416 Ret
= (ULONG_PTR
)Class
->hCursor
;
1420 /* FIXME - get handle from pointer to ICON object */
1421 Ret
= (ULONG_PTR
)Class
->hIcon
;
1425 /* FIXME - get handle from pointer to ICON object */
1426 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1430 Ret
= (ULONG_PTR
)Class
->hInstance
;
1434 /* NOTE: Returns pointer in kernel heap! */
1436 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1438 Ret
= (ULONG_PTR
)Class
->MenuName
;
1442 Ret
= (ULONG_PTR
)Class
->Style
;
1446 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1447 GetW32ProcessInfo(),
1452 Ret
= (ULONG_PTR
)Class
->Atom
;
1456 SetLastWin32Error(ERROR_INVALID_INDEX
);
1464 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1465 IN PUNICODE_STRING MenuName
)
1469 /* change the base class first */
1470 Class
= Class
->Base
;
1472 if (MenuName
->Length
!= 0)
1474 ANSI_STRING AnsiString
;
1477 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1479 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1480 AnsiString
.MaximumLength
);
1481 if (strBufW
!= NULL
)
1487 /* copy the unicode string */
1488 RtlCopyMemory(strBufW
,
1491 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1493 /* create an ansi copy of the string */
1494 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1495 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1498 if (!NT_SUCCESS(Status
))
1500 SetLastNtError(Status
);
1508 SetLastNtError(_SEH_GetExceptionCode());
1514 /* update the base class */
1515 IntFreeClassMenuName(Class
);
1516 Class
->MenuName
= strBufW
;
1517 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1518 Class
->MenuNameIsString
= TRUE
;
1520 /* update the clones */
1521 Class
= Class
->Clone
;
1522 while (Class
!= NULL
)
1524 Class
->MenuName
= strBufW
;
1525 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1526 Class
->MenuNameIsString
= TRUE
;
1528 Class
= Class
->Next
;
1533 DPRINT1("Failed to copy class menu name!\n");
1534 UserHeapFree(strBufW
);
1538 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1542 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1544 /* update the base class */
1545 IntFreeClassMenuName(Class
);
1546 Class
->MenuName
= MenuName
->Buffer
;
1547 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1548 Class
->MenuNameIsString
= FALSE
;
1550 /* update the clones */
1551 Class
= Class
->Clone
;
1552 while (Class
!= NULL
)
1554 Class
->MenuName
= MenuName
->Buffer
;
1555 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1556 Class
->MenuNameIsString
= FALSE
;
1558 Class
= Class
->Next
;
1568 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1570 IN ULONG_PTR NewLong
,
1575 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1577 /* change the information in the base class first, then update the clones */
1578 Class
= Class
->Base
;
1584 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1586 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1587 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1589 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1593 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1595 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1596 certain architectures, maybe using RtlCopyMemory is a
1597 better choice for those architectures! */
1601 /* update the clones */
1602 Class
= Class
->Clone
;
1603 while (Class
!= NULL
)
1605 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1606 Class
= Class
->Next
;
1614 case GCL_CBWNDEXTRA
:
1615 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1616 Class
->WndExtra
= (INT
)NewLong
;
1618 /* update the clones */
1619 Class
= Class
->Clone
;
1620 while (Class
!= NULL
)
1622 Class
->WndExtra
= (INT
)NewLong
;
1623 Class
= Class
->Next
;
1628 case GCL_CBCLSEXTRA
:
1629 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1632 case GCLP_HBRBACKGROUND
:
1633 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1634 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1636 /* update the clones */
1637 Class
= Class
->Clone
;
1638 while (Class
!= NULL
)
1640 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1641 Class
= Class
->Next
;
1646 /* FIXME - get handle from pointer to CURSOR object */
1647 Ret
= (ULONG_PTR
)Class
->hCursor
;
1648 Class
->hCursor
= (HANDLE
)NewLong
;
1650 /* update the clones */
1651 Class
= Class
->Clone
;
1652 while (Class
!= NULL
)
1654 Class
->hCursor
= (HANDLE
)NewLong
;
1655 Class
= Class
->Next
;
1660 /* FIXME - get handle from pointer to ICON object */
1661 Ret
= (ULONG_PTR
)Class
->hIcon
;
1662 Class
->hIcon
= (HANDLE
)NewLong
;
1664 /* update the clones */
1665 Class
= Class
->Clone
;
1666 while (Class
!= NULL
)
1668 Class
->hIcon
= (HANDLE
)NewLong
;
1669 Class
= Class
->Next
;
1674 /* FIXME - get handle from pointer to ICON object */
1675 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1676 Class
->hIconSm
= (HANDLE
)NewLong
;
1678 /* update the clones */
1679 Class
= Class
->Clone
;
1680 while (Class
!= NULL
)
1682 Class
->hIconSm
= (HANDLE
)NewLong
;
1683 Class
= Class
->Next
;
1688 Ret
= (ULONG_PTR
)Class
->hInstance
;
1689 Class
->hInstance
= (HINSTANCE
)NewLong
;
1691 /* update the clones */
1692 Class
= Class
->Clone
;
1693 while (Class
!= NULL
)
1695 Class
->hInstance
= (HINSTANCE
)NewLong
;
1696 Class
= Class
->Next
;
1702 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1704 if (!IntSetClassMenuName(Class
,
1707 DPRINT("Setting the class menu name failed!\n");
1710 /* FIXME - really return NULL? Wine does so... */
1715 Ret
= (ULONG_PTR
)Class
->Style
;
1716 Class
->Style
= (UINT
)NewLong
;
1718 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1719 move the class to the appropriate list? For now, we save
1720 the original value in Class->Global, so we can always
1721 locate the appropriate list */
1723 /* update the clones */
1724 Class
= Class
->Clone
;
1725 while (Class
!= NULL
)
1727 Class
->Style
= (UINT
)NewLong
;
1728 Class
= Class
->Next
;
1733 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1740 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1742 Ret
= (ULONG_PTR
)Class
->Atom
;
1743 if (!IntSetClassAtom(Class
,
1752 SetLastWin32Error(ERROR_INVALID_INDEX
);
1760 UserGetClassInfo(IN PWINDOWCLASS Class
,
1761 OUT PWNDCLASSEXW lpwcx
,
1763 HINSTANCE hInstance
)
1767 lpwcx
->style
= Class
->Style
;
1769 pi
= GetW32ProcessInfo();
1770 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1774 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1775 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1776 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1777 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1778 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1781 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1783 lpwcx
->lpszMenuName
= Class
->MenuName
;
1785 if (Class
->hInstance
== pi
->hModUser
)
1786 lpwcx
->hInstance
= NULL
;
1788 lpwcx
->hInstance
= Class
->hInstance
;
1790 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1792 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1797 /* SYSCALLS *****************************************************************/
1801 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1802 IN PUNICODE_STRING ClassName
,
1803 IN PUNICODE_STRING MenuName
,
1810 * Registers a new class with the window manager
1812 * lpwcx = Win32 extended window class structure
1813 * bUnicodeClass = Whether to send ANSI or unicode strings
1814 * to window procedures
1815 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1817 * Atom identifying the new class
1820 WNDCLASSEXW CapturedClassInfo
= {0};
1821 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1822 RTL_ATOM Ret
= (RTL_ATOM
)0;
1824 if (Flags
& ~REGISTERCLASS_ALL
)
1826 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1830 UserEnterExclusive();
1834 /* Probe the parameters and basic parameter checks */
1835 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1837 goto InvalidParameter
;
1841 sizeof(WNDCLASSEXW
),
1843 RtlCopyMemory(&CapturedClassInfo
,
1845 sizeof(WNDCLASSEXW
));
1847 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1848 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1850 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1851 CapturedClassInfo
.cbClsExtra
< 0 ||
1852 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1853 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1854 CapturedClassInfo
.cbWndExtra
< 0 ||
1855 CapturedClassInfo
.hInstance
== NULL
)
1857 goto InvalidParameter
;
1860 if (CapturedName
.Length
!= 0)
1862 ProbeForRead(CapturedName
.Buffer
,
1863 CapturedName
.Length
,
1868 if (!IS_ATOM(CapturedName
.Buffer
))
1870 goto InvalidParameter
;
1874 if (CapturedMenuName
.Length
!= 0)
1876 ProbeForRead(CapturedMenuName
.Buffer
,
1877 CapturedMenuName
.Length
,
1880 else if (CapturedMenuName
.Buffer
!= NULL
&&
1881 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1884 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1888 /* Register the class */
1889 Ret
= UserRegisterClass(&CapturedClassInfo
,
1892 hMenu
, /* FIXME - pass pointer */
1899 SetLastNtError(_SEH_GetExceptionCode());
1911 NtUserGetClassLong(IN HWND hWnd
,
1915 PWINDOW_OBJECT Window
;
1918 if (Offset
!= GCLP_WNDPROC
)
1924 UserEnterExclusive();
1927 Window
= UserGetWindowObject(hWnd
);
1930 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
1934 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
1936 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
1948 NtUserSetClassLong(HWND hWnd
,
1950 ULONG_PTR dwNewLong
,
1954 PWINDOW_OBJECT Window
;
1957 UserEnterExclusive();
1959 pi
= GetW32ProcessInfo();
1963 Window
= UserGetWindowObject(hWnd
);
1966 if (Window
->ti
->kpi
!= pi
)
1968 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1974 UNICODE_STRING Value
;
1976 /* probe the parameters */
1977 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
1979 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
1980 if (Value
.Length
& 1)
1982 goto InvalidParameter
;
1985 if (Value
.Length
!= 0)
1987 ProbeForRead(Value
.Buffer
,
1993 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
1995 goto InvalidParameter
;
1997 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2000 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2005 dwNewLong
= (ULONG_PTR
)&Value
;
2008 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2015 SetLastNtError(_SEH_GetExceptionCode());
2027 NtUserSetClassWord(DWORD Unknown0
,
2035 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2036 IN HINSTANCE hInstance
)
2038 UNICODE_STRING CapturedClassName
;
2041 UserEnterExclusive();
2045 /* probe the paramters */
2046 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2047 if (CapturedClassName
.Length
& 1)
2049 goto InvalidParameter
;
2052 if (CapturedClassName
.Length
!= 0)
2054 ProbeForRead(CapturedClassName
.Buffer
,
2055 CapturedClassName
.Length
,
2060 if (!IS_ATOM(CapturedClassName
.Buffer
))
2063 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2068 /* unregister the class */
2069 Ret
= UserUnregisterClass(&CapturedClassName
,
2074 SetLastNtError(_SEH_GetExceptionCode());
2083 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2086 HINSTANCE hInstance
,
2087 PUNICODE_STRING ClassName
,
2088 LPWNDCLASSEXW lpWndClassEx
,
2091 UNICODE_STRING CapturedClassName
;
2097 /* NOTE: need exclusive lock because getting the wndproc might require the
2098 creation of a call procedure handle */
2099 UserEnterExclusive();
2101 pi
= GetW32ProcessInfo();
2104 ERR("GetW32ProcessInfo() returned NULL!\n");
2109 /* probe the paramters */
2110 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2112 if (CapturedClassName
.Length
== 0)
2113 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2115 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2117 if (CapturedClassName
.Length
& 1)
2119 goto InvalidParameter
;
2122 if (CapturedClassName
.Length
!= 0)
2124 ProbeForRead(CapturedClassName
.Buffer
,
2125 CapturedClassName
.Length
,
2130 if (!IS_ATOM(CapturedClassName
.Buffer
))
2132 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2133 goto InvalidParameter
;
2137 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2140 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2144 ProbeForWrite(lpWndClassEx
,
2145 sizeof(WNDCLASSEXW
),
2148 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2153 if (ClassAtom
!= (RTL_ATOM
)0)
2155 if (hInstance
== NULL
)
2156 hInstance
= pi
->hModUser
;
2158 Ret
= UserGetClassInfo(Class
,
2165 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2166 /* FIXME - handle Class->Desktop == NULL!!!!! */
2168 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2170 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2171 (PVOID
)Class
->AnsiMenuName
:
2172 (PVOID
)Class
->MenuName
);
2175 /* Undocumented behavior! Return the class atom as a BOOL! */
2176 Ret
= (BOOL
)ClassAtom
;
2181 if (CapturedClassName
.Length
== 0)
2182 WARN("Tried to get information of a non-existing class atom 0x%p\n", CapturedClassName
.Buffer
);
2184 WARN("Tried to get information of a non-existing class \"%wZ\"\n", &CapturedClassName
);
2185 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2190 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2202 NtUserGetClassName (IN HWND hWnd
,
2203 OUT PUNICODE_STRING ClassName
,
2206 PWINDOW_OBJECT Window
;
2207 UNICODE_STRING CapturedClassName
;
2212 Window
= UserGetWindowObject(hWnd
);
2217 ProbeForWriteUnicodeString(ClassName
);
2218 CapturedClassName
= *ClassName
;
2220 /* get the class name */
2221 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2227 /* update the Length field */
2228 ClassName
->Length
= CapturedClassName
.Length
;
2233 SetLastNtError(_SEH_GetExceptionCode());
2244 NtUserGetWOWClass(DWORD Unknown0
,