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 ***************************************************************/
41 #define REGISTERCLASS_SYSTEM 0x4
44 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class
)
46 /* free the menu name, if it was changed and allocated */
47 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
49 UserHeapFree(Class
->MenuName
);
50 Class
->MenuName
= NULL
;
51 Class
->AnsiMenuName
= NULL
;
56 IntDestroyClass(IN OUT PWINDOWCLASS Class
)
58 /* there shouldn't be any clones anymore */
59 ASSERT(Class
->Windows
== 0);
60 ASSERT(Class
->Clone
== NULL
);
62 if (Class
->Base
== Class
)
64 PCALLPROC CallProc
, NextCallProc
;
66 /* Destroy allocated callproc handles */
67 CallProc
= Class
->CallProcList
;
68 while (CallProc
!= NULL
)
70 NextCallProc
= CallProc
->Next
;
72 CallProc
->Next
= NULL
;
76 CallProc
= NextCallProc
;
79 IntFreeClassMenuName(Class
);
82 /* free the structure */
83 if (Class
->Desktop
!= NULL
)
85 DesktopHeapFree(Class
->Desktop
,
95 /* clean all process classes. all process windows must cleaned first!! */
96 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
99 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
103 /* free all local classes */
104 Class
= pi
->LocalClassList
;
105 while (Class
!= NULL
)
107 pi
->LocalClassList
= Class
->Next
;
109 ASSERT(Class
->Base
== Class
);
110 IntDestroyClass(Class
);
112 Class
= pi
->LocalClassList
;
115 /* free all global classes */
116 Class
= pi
->GlobalClassList
;
117 while (Class
!= NULL
)
119 pi
->GlobalClassList
= Class
->Next
;
121 ASSERT(Class
->Base
== Class
);
122 IntDestroyClass(Class
);
124 Class
= pi
->GlobalClassList
;
127 /* free all system classes */
128 Class
= pi
->SystemClassList
;
129 while (Class
!= NULL
)
131 pi
->SystemClassList
= Class
->Next
;
133 ASSERT(Class
->Base
== Class
);
134 IntDestroyClass(Class
);
136 Class
= pi
->SystemClassList
;
142 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
149 if (ClassName
->Length
!= 0)
151 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
152 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
154 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
161 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
165 AtomName
= ClassName
->Buffer
;
167 Status
= RtlAddAtomToAtomTable(gAtomTable
,
171 if (!NT_SUCCESS(Status
))
173 SetLastNtError(Status
);
181 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
183 return RtlDeleteAtomFromAtomTable(gAtomTable
,
188 UserFindCallProc(IN PWINDOWCLASS Class
,
194 CallProc
= Class
->CallProcList
;
195 while (CallProc
!= NULL
)
197 if (CallProc
->WndProc
== WndProc
&&
198 CallProc
->Unicode
== (UINT
)bUnicode
)
203 CallProc
= CallProc
->Next
;
210 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class
,
211 IN PCALLPROC CallProc
)
213 PWINDOWCLASS BaseClass
;
215 ASSERT(CallProc
->Next
== NULL
);
217 BaseClass
= Class
->Base
;
218 ASSERT(CallProc
->Next
== NULL
);
219 CallProc
->Next
= BaseClass
->CallProcList
;
220 BaseClass
->CallProcList
= CallProc
;
222 /* Update all clones */
223 Class
= Class
->Clone
;
224 while (Class
!= NULL
)
226 Class
->CallProcList
= BaseClass
->CallProcList
;
232 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
233 IN PUNICODE_STRING ClassName
)
235 RTL_ATOM Atom
= (RTL_ATOM
)0;
237 /* update the base class first */
240 if (!IntRegisterClassAtom(ClassName
,
246 IntDeregisterClassAtom(Class
->Atom
);
250 /* update the clones */
251 Class
= Class
->Clone
;
252 while (Class
!= NULL
)
263 IntGetClassWndProc(IN PWINDOWCLASS Class
,
264 IN PW32PROCESSINFO pi
,
267 ASSERT(UserIsEnteredExclusive() == TRUE
);
271 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
275 if (!Ansi
== Class
->Unicode
)
277 return Class
->WndProc
;
281 PWINDOWCLASS BaseClass
;
283 /* make sure the call procedures are located on the desktop
284 of the base class! */
285 BaseClass
= Class
->Base
;
288 if (Class
->CallProc
!= NULL
)
290 return GetCallProcHandle(Class
->CallProc
);
294 PCALLPROC NewCallProc
;
299 NewCallProc
= UserFindCallProc(Class
,
302 if (NewCallProc
== NULL
)
304 NewCallProc
= CreateCallProc(NULL
,
308 if (NewCallProc
== NULL
)
310 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
314 UserAddCallProcToClass(Class
,
318 Class
->CallProc
= NewCallProc
;
320 /* update the clones */
321 Class
= Class
->Clone
;
322 while (Class
!= NULL
)
324 Class
->CallProc
= NewCallProc
;
329 return GetCallProcHandle(NewCallProc
);
336 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
344 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
345 SetLastWin32Error(ERROR_ACCESS_DENIED
);
349 /* update the base class first */
352 /* resolve any callproc handle if possible */
353 if (IsCallProcHandle(WndProc
))
357 if (UserGetCallProcInfo((HANDLE
)WndProc
,
360 WndProc
= wpInfo
.WindowProc
;
361 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
365 Ret
= IntGetClassWndProc(Class
,
373 /* update the class info */
374 Class
->Unicode
= !Ansi
;
375 Class
->WndProc
= WndProc
;
377 /* update the clones */
378 Class
= Class
->Clone
;
379 while (Class
!= NULL
)
381 Class
->Unicode
= !Ansi
;
382 Class
->WndProc
= WndProc
;
391 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
392 IN OUT PWINDOWCLASS
*ClassLink
,
398 ASSERT(Desktop
!= NULL
);
399 ASSERT(BaseClass
->Base
== BaseClass
);
401 if (BaseClass
->Desktop
== Desktop
)
403 /* it is most likely that a window is created on the same
404 desktop as the window class. */
409 if (BaseClass
->Desktop
== NULL
)
411 ASSERT(BaseClass
->Windows
== 0);
412 ASSERT(BaseClass
->Clone
== NULL
);
414 /* Classes are also located in the shared heap when the class
415 was created before the thread attached to a desktop. As soon
416 as a window is created for such a class located on the shared
417 heap, the class is cloned into the desktop heap on which the
418 window is created. */
423 /* The user is asking for a class object on a different desktop,
425 Class
= BaseClass
->Clone
;
426 while (Class
!= NULL
)
428 if (Class
->Desktop
== Desktop
)
430 ASSERT(Class
->Base
== BaseClass
);
431 ASSERT(Class
->Clone
== NULL
);
441 /* The window is created on a different desktop, we need to
442 clone the class object to the desktop heap of the window! */
443 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
445 Class
= DesktopHeapAlloc(Desktop
,
449 /* simply clone the class */
454 /* update some pointers and link the class */
455 Class
->Desktop
= Desktop
;
458 if (BaseClass
->Desktop
== NULL
)
460 /* we don't really need the base class on the shared
461 heap anymore, delete it so the only class left is
462 the clone we just created, which now serves as the
464 ASSERT(BaseClass
->Clone
== NULL
);
465 ASSERT(Class
->Clone
== NULL
);
467 Class
->Next
= BaseClass
->Next
;
469 /* replace the base class */
470 (void)InterlockedExchangePointer(ClassLink
,
473 /* destroy the obsolete copy on the shared heap */
474 BaseClass
->Base
= NULL
;
475 BaseClass
->Clone
= NULL
;
476 IntDestroyClass(BaseClass
);
480 /* link in the clone */
482 Class
->Base
= BaseClass
;
483 Class
->Next
= BaseClass
->Clone
;
484 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
490 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
498 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
499 IN OUT PWINDOWCLASS
*ClassLink
,
504 ASSERT(BaseClass
->Base
== BaseClass
);
506 Class
= IntGetClassForDesktop(BaseClass
,
518 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
519 IN OUT PWINDOWCLASS
*BaseClassLink
,
520 IN OUT PWINDOWCLASS
*CloneLink
)
522 PWINDOWCLASS Clone
, BaseClass
;
524 ASSERT(Class
->Base
!= Class
);
525 ASSERT(Class
->Base
->Clone
!= NULL
);
526 ASSERT(Class
->Desktop
!= NULL
);
527 ASSERT(Class
->Windows
!= 0);
528 ASSERT(Class
->Base
->Desktop
!= NULL
);
529 ASSERT(Class
->Base
->Windows
== 0);
531 /* unlink the clone */
532 *CloneLink
= Class
->Next
;
533 Class
->Clone
= Class
->Base
->Clone
;
535 BaseClass
= Class
->Base
;
537 /* update the class information to make it a base class */
539 Class
->Next
= (*BaseClassLink
)->Next
;
541 /* update all clones */
542 Clone
= Class
->Clone
;
543 while (Clone
!= NULL
)
545 ASSERT(Clone
->Clone
== NULL
);
549 Clone
->CallProc
= Class
->CallProc
;
554 /* link in the new base class */
555 (void)InterlockedExchangePointer(BaseClassLink
,
560 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
562 IN PW32PROCESSINFO pi
)
564 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
566 BaseClass
= Class
->Base
;
568 if (--Class
->Windows
== 0)
570 if (BaseClass
== Class
)
572 ASSERT(Class
->Base
== Class
);
574 /* check if there are clones of the class on other desktops,
575 link the first clone in if possible. If there are no clones
576 then leave the class on the desktop heap. It will get moved
577 to the shared heap when the thread detaches. */
578 if (BaseClass
->Clone
!= NULL
)
580 if (BaseClass
->System
)
581 PrevLink
= &pi
->SystemClassList
;
582 else if (BaseClass
->Global
)
583 PrevLink
= &pi
->GlobalClassList
;
585 PrevLink
= &pi
->LocalClassList
;
587 while (*PrevLink
!= BaseClass
)
589 ASSERT(*PrevLink
!= NULL
);
590 PrevLink
= &BaseClass
->Next
;
593 ASSERT(*PrevLink
== BaseClass
);
595 /* make the first clone become the new base class */
596 IntMakeCloneBaseClass(BaseClass
->Clone
,
600 /* destroy the class, there's still another clone of the class
601 that now serves as a base class. Make sure we don't destruct
602 resources shared by all classes (Base = NULL)! */
603 BaseClass
->Base
= NULL
;
604 BaseClass
->Clone
= NULL
;
605 IntDestroyClass(BaseClass
);
610 /* locate the cloned class and unlink it */
611 PrevLink
= &BaseClass
->Clone
;
612 CurrentClass
= BaseClass
->Clone
;
613 while (CurrentClass
!= Class
)
615 ASSERT(CurrentClass
!= NULL
);
617 PrevLink
= &CurrentClass
->Next
;
618 CurrentClass
= CurrentClass
->Next
;
621 ASSERT(CurrentClass
== Class
);
623 (void)InterlockedExchangePointer(PrevLink
,
626 ASSERT(Class
->Base
== BaseClass
);
627 ASSERT(Class
->Clone
== NULL
);
629 /* the class was just a clone, we don't need it anymore */
630 IntDestroyClass(Class
);
636 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
637 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
639 PWINDOWCLASS NewClass
;
642 ASSERT(Class
->Base
== Class
);
643 ASSERT(Class
->Desktop
!= NULL
);
644 ASSERT(Class
->Windows
== 0);
645 ASSERT(Class
->Clone
== NULL
);
647 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
649 /* allocate the new base class on the shared heap */
650 NewClass
= UserHeapAlloc(ClassSize
);
651 if (NewClass
!= NULL
)
653 RtlCopyMemory(NewClass
,
657 NewClass
->Desktop
= NULL
;
658 NewClass
->Base
= NewClass
;
660 /* replace the class in the list */
661 (void)InterlockedExchangePointer(*ClassLinkPtr
,
663 *ClassLinkPtr
= &NewClass
->Next
;
665 /* free the obsolete class on the desktop heap */
667 IntDestroyClass(Class
);
675 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
676 IN OUT PWINDOWCLASS
*ClassList
,
677 IN BOOL FreeOnFailure
,
680 PWINDOWCLASS Class
, NextClass
, *Link
;
682 /* NOTE: We only need to check base classes! When classes are no longer needed
683 on a desktop, the clones will be freed automatically as soon as possible.
684 However, we need to move base classes to the shared heap, as soon as
685 the last desktop heap where a class is allocated on is about to be destroyed.
686 If we didn't move the class to the shared heap, the class would become
689 ASSERT(Desktop
!= NULL
);
693 while (Class
!= NULL
)
695 NextClass
= Class
->Next
;
697 ASSERT(Class
->Base
== Class
);
699 if (Class
->Desktop
== Desktop
&&
702 /* there shouldn't be any clones around anymore! */
703 ASSERT(Class
->Clone
== NULL
);
705 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
706 /* FIXME - We could move the class to another desktop heap if there's still desktops
707 mapped into the process... */
709 /* move the class to the shared heap */
710 if (IntMoveClassToSharedHeap(Class
,
713 ASSERT(*Link
== NextClass
);
717 ASSERT(NextClass
== Class
->Next
);
721 /* unlink the base class */
722 (void)InterlockedExchangePointer(Link
,
725 /* we can free the old base class now */
727 IntDestroyClass(Class
);
744 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
745 IN BOOL FreeOnFailure
)
750 pi
= GetW32ProcessInfo();
754 /* check all local classes */
755 IntCheckDesktopClasses(Desktop
,
760 /* check all global classes */
761 IntCheckDesktopClasses(Desktop
,
762 &pi
->GlobalClassList
,
766 /* check all system classes */
767 IntCheckDesktopClasses(Desktop
,
768 &pi
->SystemClassList
,
774 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
775 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
782 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
783 IN PUNICODE_STRING ClassName
,
784 IN PUNICODE_STRING MenuName
,
788 IN PW32PROCESSINFO pi
)
791 PWINDOWCLASS Class
= NULL
;
793 PWSTR pszMenuName
= NULL
;
794 NTSTATUS Status
= STATUS_SUCCESS
;
796 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
797 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
799 if (!IntRegisterClassAtom(ClassName
,
802 DPRINT1("Failed to register class atom!\n");
806 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
807 if (MenuName
->Length
!= 0)
809 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
810 RtlUnicodeStringToAnsiSize(MenuName
));
811 if (pszMenuName
== NULL
)
817 Class
= DesktopHeapAlloc(Desktop
,
822 /* FIXME - the class was created before being connected
823 to a desktop. It is possible for the desktop window,
824 but should it be allowed for any other case? */
825 Class
= UserHeapAlloc(ClassSize
);
833 Class
->Desktop
= Desktop
;
837 if (dwFlags
& REGISTERCLASS_SYSTEM
)
839 dwFlags
&= ~REGISTERCLASS_ANSI
;
840 Class
->WndProcExtra
= wpExtra
;
841 Class
->System
= TRUE
;
846 PWSTR pszMenuNameBuffer
= pszMenuName
;
848 /* need to protect with SEH since accessing the WNDCLASSEX structure
849 and string buffers might raise an exception! We don't want to
851 Class
->WndProc
= lpwcx
->lpfnWndProc
;
852 Class
->Style
= lpwcx
->style
;
853 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
854 Class
->WndExtra
= lpwcx
->cbWndExtra
;
855 Class
->hInstance
= lpwcx
->hInstance
;
856 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
857 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
858 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
859 Class
->hbrBackground
= lpwcx
->hbrBackground
;
861 /* make a copy of the string */
862 if (pszMenuNameBuffer
!= NULL
)
864 Class
->MenuNameIsString
= TRUE
;
866 Class
->MenuName
= pszMenuNameBuffer
;
867 RtlCopyMemory(Class
->MenuName
,
870 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
872 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
875 Class
->MenuName
= MenuName
->Buffer
;
877 /* save an ansi copy of the string */
878 if (pszMenuNameBuffer
!= NULL
)
880 ANSI_STRING AnsiString
;
882 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
883 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
884 AnsiString
.Buffer
= Class
->AnsiMenuName
;
885 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
888 if (!NT_SUCCESS(Status
))
890 DPRINT1("Failed to convert unicode menu name to ansi!\n");
892 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
897 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
899 if (!(dwFlags
& REGISTERCLASS_ANSI
))
900 Class
->Unicode
= TRUE
;
902 if (Class
->Style
& CS_GLOBALCLASS
)
903 Class
->Global
= TRUE
;
907 Status
= _SEH_GetExceptionCode();
911 if (!NT_SUCCESS(Status
))
913 DPRINT1("Failed creating the class: 0x%x\n", Status
);
915 SetLastNtError(Status
);
917 if (pszMenuName
!= NULL
)
918 UserHeapFree(pszMenuName
);
920 DesktopHeapFree(Desktop
,
924 IntDeregisterClassAtom(Atom
);
930 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
932 if (pszMenuName
!= NULL
)
933 UserHeapFree(pszMenuName
);
935 IntDeregisterClassAtom(Atom
);
937 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
944 IntFindClass(IN RTL_ATOM Atom
,
945 IN HINSTANCE hInstance
,
946 IN PWINDOWCLASS
*ClassList
,
947 OUT PWINDOWCLASS
**Link OPTIONAL
)
949 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
952 while (Class
!= NULL
)
954 if (Class
->Atom
== Atom
&&
955 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
958 ASSERT(Class
->Base
== Class
);
965 PrevLink
= &Class
->Next
;
973 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
978 if (ClassName
->Length
!= 0)
984 /* NOTE: Caller has to protect the call with SEH! */
986 if (ClassName
->Length
!= 0)
988 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
989 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
991 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
995 /* We need to make a local copy of the class name! The caller could
996 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
997 We're protected by SEH, but the ranges that might be accessed were
1002 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1006 AtomName
= ClassName
->Buffer
;
1008 /* lookup the atom */
1009 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1012 if (NT_SUCCESS(Status
))
1018 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1020 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1024 SetLastNtError(Status
);
1030 ASSERT(IS_ATOM(ClassName
->Buffer
));
1031 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1039 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1040 IN HINSTANCE hInstance OPTIONAL
,
1041 IN PW32PROCESSINFO pi OPTIONAL
,
1042 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1043 OUT PWINDOWCLASS
**Link OPTIONAL
)
1045 RTL_ATOM Atom
= (RTL_ATOM
)0;
1047 ASSERT(BaseClass
!= NULL
);
1049 if (IntGetAtomFromStringOrAtom(ClassName
,
1051 Atom
!= (RTL_ATOM
)0)
1055 /* attempt to locate the class object */
1059 /* Step 1: try to find an exact match of locally registered classes */
1060 Class
= IntFindClass(Atom
,
1062 &pi
->LocalClassList
,
1069 /* Step 2: try to find any globally registered class. The hInstance
1070 is not relevant for global classes */
1071 Class
= IntFindClass(Atom
,
1073 &pi
->GlobalClassList
,
1080 /* Step 3: try to find any local class registered by user32 */
1081 Class
= IntFindClass(Atom
,
1083 &pi
->LocalClassList
,
1090 /* Step 4: try to find any global class registered by user32 */
1091 Class
= IntFindClass(Atom
,
1093 &pi
->GlobalClassList
,
1100 /* Step 5: try to find a system class */
1101 Class
= IntFindClass(Atom
,
1103 &pi
->SystemClassList
,
1107 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1119 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1120 IN PUNICODE_STRING ClassName
,
1121 IN PUNICODE_STRING MenuName
,
1122 IN HANDLE hMenu
, /* FIXME */
1130 RTL_ATOM Ret
= (RTL_ATOM
)0;
1132 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1134 ti
= GetW32ThreadInfo();
1135 if (ti
== NULL
|| !ti
->kpi
->RegisteredSysClasses
)
1137 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1143 /* try to find a previously registered class */
1144 ClassAtom
= IntGetClassAtom(ClassName
,
1149 if (ClassAtom
!= (RTL_ATOM
)0)
1151 if (lpwcx
->style
& CS_GLOBALCLASS
)
1153 // global classes shall not have same names as system classes
1154 if (Class
->Global
|| Class
->System
)
1156 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1157 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1161 else if ( !Class
->Global
&& !Class
->System
)
1163 // local class already exists
1164 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1165 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1170 Class
= IntCreateClass(lpwcx
,
1182 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1183 Class
->hMenu
= hMenu
;
1185 /* Register the class */
1187 List
= &pi
->SystemClassList
;
1188 else if (Class
->Global
)
1189 List
= &pi
->GlobalClassList
;
1191 List
= &pi
->LocalClassList
;
1193 Class
->Next
= *List
;
1194 (void)InterlockedExchangePointer(List
,
1204 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1205 IN HINSTANCE hInstance
)
1212 pi
= GetW32ProcessInfo();
1215 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1219 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1221 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1222 ClassAtom
= IntGetClassAtom(ClassName
,
1227 if (ClassAtom
== (RTL_ATOM
)0)
1232 ASSERT(Class
!= NULL
);
1234 if (Class
->Windows
!= 0 ||
1235 Class
->Clone
!= NULL
)
1237 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1241 /* must be a base class! */
1242 ASSERT(Class
->Base
== Class
);
1244 /* unlink the class */
1245 *Link
= Class
->Next
;
1247 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1249 /* finally free the resources */
1250 IntDestroyClass(Class
);
1257 UserGetClassName(IN PWINDOWCLASS Class
,
1258 IN OUT PUNICODE_STRING ClassName
,
1261 NTSTATUS Status
= STATUS_SUCCESS
;
1262 WCHAR szStaticTemp
[32];
1263 PWSTR szTemp
= NULL
;
1264 ULONG BufLen
= sizeof(szStaticTemp
);
1267 /* Note: Accessing the buffer in ClassName may raise an exception! */
1273 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1274 UNICODE_STRING UnicodeClassName
;
1276 /* limit the size of the static buffer on the stack to the
1277 size of the buffer provided by the caller */
1278 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1280 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1283 /* find out how big the buffer needs to be */
1284 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1290 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1292 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1294 /* the buffer required exceeds the ansi buffer provided,
1295 pretend like we're using the ansi buffer and limit the
1296 size to the buffer size provided */
1297 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1300 /* allocate a temporary buffer that can hold the unicode class name */
1301 szTemp
= ExAllocatePool(PagedPool
,
1305 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1309 /* query the class name */
1310 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1318 szTemp
= szStaticTemp
;
1320 if (NT_SUCCESS(Status
))
1322 /* convert the atom name to ansi */
1324 RtlInitUnicodeString(&UnicodeClassName
,
1327 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1330 if (!NT_SUCCESS(Status
))
1332 SetLastNtError(Status
);
1337 Ret
= BufLen
/ sizeof(WCHAR
);
1341 BufLen
= ClassName
->MaximumLength
;
1343 /* query the atom name */
1344 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1351 if (!NT_SUCCESS(Status
))
1353 SetLastNtError(Status
);
1357 Ret
= BufLen
/ sizeof(WCHAR
);
1362 SetLastNtError(_SEH_GetExceptionCode());
1366 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1375 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1385 TRACE("GetClassLong(%d)\n", Index
);
1386 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1387 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1389 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1393 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1395 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1396 certain architectures, maybe using RtlCopyMemory is a
1397 better choice for those architectures! */
1399 TRACE("Result: %x\n", Ret
);
1405 case GCL_CBWNDEXTRA
:
1406 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1409 case GCL_CBCLSEXTRA
:
1410 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1413 case GCLP_HBRBACKGROUND
:
1414 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1418 /* FIXME - get handle from pointer to CURSOR object */
1419 Ret
= (ULONG_PTR
)Class
->hCursor
;
1423 /* FIXME - get handle from pointer to ICON object */
1424 Ret
= (ULONG_PTR
)Class
->hIcon
;
1428 /* FIXME - get handle from pointer to ICON object */
1429 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1433 Ret
= (ULONG_PTR
)Class
->hInstance
;
1437 /* NOTE: Returns pointer in kernel heap! */
1439 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1441 Ret
= (ULONG_PTR
)Class
->MenuName
;
1445 Ret
= (ULONG_PTR
)Class
->Style
;
1449 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1450 GetW32ProcessInfo(),
1455 Ret
= (ULONG_PTR
)Class
->Atom
;
1459 SetLastWin32Error(ERROR_INVALID_INDEX
);
1467 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1468 IN PUNICODE_STRING MenuName
)
1472 /* change the base class first */
1473 Class
= Class
->Base
;
1475 if (MenuName
->Length
!= 0)
1477 ANSI_STRING AnsiString
;
1480 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1482 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1483 AnsiString
.MaximumLength
);
1484 if (strBufW
!= NULL
)
1490 /* copy the unicode string */
1491 RtlCopyMemory(strBufW
,
1494 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1496 /* create an ansi copy of the string */
1497 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1498 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1501 if (!NT_SUCCESS(Status
))
1503 SetLastNtError(Status
);
1511 SetLastNtError(_SEH_GetExceptionCode());
1517 /* update the base class */
1518 IntFreeClassMenuName(Class
);
1519 Class
->MenuName
= strBufW
;
1520 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1521 Class
->MenuNameIsString
= TRUE
;
1523 /* update the clones */
1524 Class
= Class
->Clone
;
1525 while (Class
!= NULL
)
1527 Class
->MenuName
= strBufW
;
1528 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1529 Class
->MenuNameIsString
= TRUE
;
1531 Class
= Class
->Next
;
1536 DPRINT1("Failed to copy class menu name!\n");
1537 UserHeapFree(strBufW
);
1541 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1545 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1547 /* update the base class */
1548 IntFreeClassMenuName(Class
);
1549 Class
->MenuName
= MenuName
->Buffer
;
1550 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1551 Class
->MenuNameIsString
= FALSE
;
1553 /* update the clones */
1554 Class
= Class
->Clone
;
1555 while (Class
!= NULL
)
1557 Class
->MenuName
= MenuName
->Buffer
;
1558 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1559 Class
->MenuNameIsString
= FALSE
;
1561 Class
= Class
->Next
;
1571 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1573 IN ULONG_PTR NewLong
,
1578 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1580 /* change the information in the base class first, then update the clones */
1581 Class
= Class
->Base
;
1587 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1589 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1590 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1592 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1596 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1598 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1599 certain architectures, maybe using RtlCopyMemory is a
1600 better choice for those architectures! */
1604 /* update the clones */
1605 Class
= Class
->Clone
;
1606 while (Class
!= NULL
)
1608 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1609 Class
= Class
->Next
;
1617 case GCL_CBWNDEXTRA
:
1618 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1619 Class
->WndExtra
= (INT
)NewLong
;
1621 /* update the clones */
1622 Class
= Class
->Clone
;
1623 while (Class
!= NULL
)
1625 Class
->WndExtra
= (INT
)NewLong
;
1626 Class
= Class
->Next
;
1631 case GCL_CBCLSEXTRA
:
1632 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1635 case GCLP_HBRBACKGROUND
:
1636 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1637 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1639 /* update the clones */
1640 Class
= Class
->Clone
;
1641 while (Class
!= NULL
)
1643 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1644 Class
= Class
->Next
;
1649 /* FIXME - get handle from pointer to CURSOR object */
1650 Ret
= (ULONG_PTR
)Class
->hCursor
;
1651 Class
->hCursor
= (HANDLE
)NewLong
;
1653 /* update the clones */
1654 Class
= Class
->Clone
;
1655 while (Class
!= NULL
)
1657 Class
->hCursor
= (HANDLE
)NewLong
;
1658 Class
= Class
->Next
;
1663 /* FIXME - get handle from pointer to ICON object */
1664 Ret
= (ULONG_PTR
)Class
->hIcon
;
1665 Class
->hIcon
= (HANDLE
)NewLong
;
1667 /* update the clones */
1668 Class
= Class
->Clone
;
1669 while (Class
!= NULL
)
1671 Class
->hIcon
= (HANDLE
)NewLong
;
1672 Class
= Class
->Next
;
1677 /* FIXME - get handle from pointer to ICON object */
1678 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1679 Class
->hIconSm
= (HANDLE
)NewLong
;
1681 /* update the clones */
1682 Class
= Class
->Clone
;
1683 while (Class
!= NULL
)
1685 Class
->hIconSm
= (HANDLE
)NewLong
;
1686 Class
= Class
->Next
;
1691 Ret
= (ULONG_PTR
)Class
->hInstance
;
1692 Class
->hInstance
= (HINSTANCE
)NewLong
;
1694 /* update the clones */
1695 Class
= Class
->Clone
;
1696 while (Class
!= NULL
)
1698 Class
->hInstance
= (HINSTANCE
)NewLong
;
1699 Class
= Class
->Next
;
1705 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1707 if (!IntSetClassMenuName(Class
,
1710 DPRINT("Setting the class menu name failed!\n");
1713 /* FIXME - really return NULL? Wine does so... */
1718 Ret
= (ULONG_PTR
)Class
->Style
;
1719 Class
->Style
= (UINT
)NewLong
;
1721 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1722 move the class to the appropriate list? For now, we save
1723 the original value in Class->Global, so we can always
1724 locate the appropriate list */
1726 /* update the clones */
1727 Class
= Class
->Clone
;
1728 while (Class
!= NULL
)
1730 Class
->Style
= (UINT
)NewLong
;
1731 Class
= Class
->Next
;
1736 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1743 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1745 Ret
= (ULONG_PTR
)Class
->Atom
;
1746 if (!IntSetClassAtom(Class
,
1755 SetLastWin32Error(ERROR_INVALID_INDEX
);
1763 UserGetClassInfo(IN PWINDOWCLASS Class
,
1764 OUT PWNDCLASSEXW lpwcx
,
1766 HINSTANCE hInstance
)
1770 lpwcx
->style
= Class
->Style
;
1772 pi
= GetW32ProcessInfo();
1773 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1777 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1778 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1779 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1780 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1781 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1784 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1786 lpwcx
->lpszMenuName
= Class
->MenuName
;
1788 if (Class
->hInstance
== pi
->hModUser
)
1789 lpwcx
->hInstance
= NULL
;
1791 lpwcx
->hInstance
= Class
->hInstance
;
1793 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1795 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1801 UserRegisterSystemClasses(IN ULONG Count
,
1802 IN PREGISTER_SYSCLASS SystemClasses
)
1804 /* NOTE: This routine may raise exceptions! */
1806 UNICODE_STRING ClassName
, MenuName
;
1807 PW32PROCESSINFO pi
= GetW32ProcessInfo();
1812 if (pi
->RegisteredSysClasses
|| pi
->hModUser
== NULL
)
1815 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1817 for (i
= 0; i
!= Count
; i
++)
1819 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1820 if (ClassName
.Length
!= 0)
1822 ProbeForRead(ClassName
.Buffer
,
1827 wc
.cbSize
= sizeof(wc
);
1828 wc
.style
= SystemClasses
[i
].Style
;
1829 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1831 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1832 wc
.hInstance
= pi
->hModUser
;
1834 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1835 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1836 wc
.lpszMenuName
= NULL
;
1837 wc
.lpszClassName
= ClassName
.Buffer
;
1840 Class
= IntCreateClass(&wc
,
1843 SystemClasses
[i
].ProcA
,
1844 REGISTERCLASS_SYSTEM
,
1849 Class
->ClassId
= SystemClasses
[i
].ClassId
;
1851 ASSERT(Class
->System
);
1852 Class
->Next
= pi
->SystemClassList
;
1853 (void)InterlockedExchangePointer(&pi
->SystemClassList
,
1858 WARN("!!! Registering system class failed!\n");
1864 pi
->RegisteredSysClasses
= TRUE
;
1868 /* SYSCALLS *****************************************************************/
1872 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1873 IN PUNICODE_STRING ClassName
,
1874 IN PUNICODE_STRING MenuName
,
1881 * Registers a new class with the window manager
1883 * lpwcx = Win32 extended window class structure
1884 * bUnicodeClass = Whether to send ANSI or unicode strings
1885 * to window procedures
1886 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1888 * Atom identifying the new class
1891 WNDCLASSEXW CapturedClassInfo
= {0};
1892 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1893 RTL_ATOM Ret
= (RTL_ATOM
)0;
1895 if (Flags
& ~REGISTERCLASS_ALL
)
1897 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1901 UserEnterExclusive();
1905 /* Probe the parameters and basic parameter checks */
1906 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1908 goto InvalidParameter
;
1912 sizeof(WNDCLASSEXW
),
1914 RtlCopyMemory(&CapturedClassInfo
,
1916 sizeof(WNDCLASSEXW
));
1918 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1919 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1921 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1922 CapturedClassInfo
.cbClsExtra
< 0 ||
1923 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1924 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1925 CapturedClassInfo
.cbWndExtra
< 0 ||
1926 CapturedClassInfo
.hInstance
== NULL
)
1928 goto InvalidParameter
;
1931 if (CapturedName
.Length
!= 0)
1933 ProbeForRead(CapturedName
.Buffer
,
1934 CapturedName
.Length
,
1939 if (!IS_ATOM(CapturedName
.Buffer
))
1941 goto InvalidParameter
;
1945 if (CapturedMenuName
.Length
!= 0)
1947 ProbeForRead(CapturedMenuName
.Buffer
,
1948 CapturedMenuName
.Length
,
1951 else if (CapturedMenuName
.Buffer
!= NULL
&&
1952 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1955 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1959 /* Register the class */
1960 Ret
= UserRegisterClass(&CapturedClassInfo
,
1963 hMenu
, /* FIXME - pass pointer */
1970 SetLastNtError(_SEH_GetExceptionCode());
1982 NtUserGetClassLong(IN HWND hWnd
,
1986 PWINDOW_OBJECT Window
;
1989 if (Offset
!= GCLP_WNDPROC
)
1995 UserEnterExclusive();
1998 Window
= UserGetWindowObject(hWnd
);
2001 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
2005 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
2007 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2019 NtUserSetClassLong(HWND hWnd
,
2021 ULONG_PTR dwNewLong
,
2025 PWINDOW_OBJECT Window
;
2028 UserEnterExclusive();
2030 pi
= GetW32ProcessInfo();
2034 Window
= UserGetWindowObject(hWnd
);
2037 if (Window
->ti
->kpi
!= pi
)
2039 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2045 UNICODE_STRING Value
;
2047 /* probe the parameters */
2048 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2050 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2051 if (Value
.Length
& 1)
2053 goto InvalidParameter
;
2056 if (Value
.Length
!= 0)
2058 ProbeForRead(Value
.Buffer
,
2064 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2066 goto InvalidParameter
;
2068 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2071 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2076 dwNewLong
= (ULONG_PTR
)&Value
;
2079 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2086 SetLastNtError(_SEH_GetExceptionCode());
2098 NtUserSetClassWord(DWORD Unknown0
,
2106 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2107 IN HINSTANCE hInstance
,
2110 UNICODE_STRING CapturedClassName
;
2113 UserEnterExclusive();
2117 /* probe the paramters */
2118 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2119 if (CapturedClassName
.Length
& 1)
2121 goto InvalidParameter
;
2124 if (CapturedClassName
.Length
!= 0)
2126 ProbeForRead(CapturedClassName
.Buffer
,
2127 CapturedClassName
.Length
,
2132 if (!IS_ATOM(CapturedClassName
.Buffer
))
2135 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2140 /* unregister the class */
2141 Ret
= UserUnregisterClass(&CapturedClassName
,
2146 SetLastNtError(_SEH_GetExceptionCode());
2155 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2158 HINSTANCE hInstance
,
2159 PUNICODE_STRING ClassName
,
2160 LPWNDCLASSEXW lpWndClassEx
,
2161 LPWSTR
*ppszMenuName
,
2164 UNICODE_STRING CapturedClassName
;
2170 /* NOTE: need exclusive lock because getting the wndproc might require the
2171 creation of a call procedure handle */
2172 UserEnterExclusive();
2174 pi
= GetW32ProcessInfo();
2177 ERR("GetW32ProcessInfo() returned NULL!\n");
2182 /* probe the paramters */
2183 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2185 if (CapturedClassName
.Length
== 0)
2186 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2188 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2190 if (CapturedClassName
.Length
& 1)
2192 goto InvalidParameter
;
2195 if (CapturedClassName
.Length
!= 0)
2197 ProbeForRead(CapturedClassName
.Buffer
,
2198 CapturedClassName
.Length
,
2203 if (!IS_ATOM(CapturedClassName
.Buffer
))
2205 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2206 goto InvalidParameter
;
2210 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2213 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2217 ProbeForWrite(lpWndClassEx
,
2218 sizeof(WNDCLASSEXW
),
2221 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2226 if (ClassAtom
!= (RTL_ATOM
)0)
2228 if (hInstance
== NULL
)
2229 hInstance
= pi
->hModUser
;
2231 Ret
= UserGetClassInfo(Class
,
2238 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2239 /* FIXME - handle Class->Desktop == NULL!!!!! */
2241 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2243 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2244 (PVOID
)Class
->AnsiMenuName
:
2245 (PVOID
)Class
->MenuName
);
2248 /* Undocumented behavior! Return the class atom as a BOOL! */
2249 Ret
= (BOOL
)ClassAtom
;
2253 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2257 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2269 NtUserGetClassName (IN HWND hWnd
,
2270 OUT PUNICODE_STRING ClassName
,
2273 PWINDOW_OBJECT Window
;
2274 UNICODE_STRING CapturedClassName
;
2279 Window
= UserGetWindowObject(hWnd
);
2284 ProbeForWriteUnicodeString(ClassName
);
2285 CapturedClassName
= *ClassName
;
2287 /* get the class name */
2288 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2294 /* update the Length field */
2295 ClassName
->Length
= CapturedClassName
.Length
;
2300 SetLastNtError(_SEH_GetExceptionCode());
2311 NtUserGetWOWClass(DWORD Unknown0
,