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
;
81 DceFreeClassDCE(((PDCE
)Class
->Dce
)->hDC
);
85 IntFreeClassMenuName(Class
);
88 /* free the structure */
89 if (Class
->Desktop
!= NULL
)
91 DesktopHeapFree(Class
->Desktop
,
101 /* clean all process classes. all process windows must cleaned first!! */
102 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
105 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
109 /* free all local classes */
110 Class
= pi
->LocalClassList
;
111 while (Class
!= NULL
)
113 pi
->LocalClassList
= Class
->Next
;
115 ASSERT(Class
->Base
== Class
);
116 IntDestroyClass(Class
);
118 Class
= pi
->LocalClassList
;
121 /* free all global classes */
122 Class
= pi
->GlobalClassList
;
123 while (Class
!= NULL
)
125 pi
->GlobalClassList
= Class
->Next
;
127 ASSERT(Class
->Base
== Class
);
128 IntDestroyClass(Class
);
130 Class
= pi
->GlobalClassList
;
133 /* free all system classes */
134 Class
= pi
->SystemClassList
;
135 while (Class
!= NULL
)
137 pi
->SystemClassList
= Class
->Next
;
139 ASSERT(Class
->Base
== Class
);
140 IntDestroyClass(Class
);
142 Class
= pi
->SystemClassList
;
148 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
155 if (ClassName
->Length
!= 0)
157 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
158 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
160 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
167 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
171 AtomName
= ClassName
->Buffer
;
173 Status
= RtlAddAtomToAtomTable(gAtomTable
,
177 if (!NT_SUCCESS(Status
))
179 SetLastNtError(Status
);
187 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
189 return RtlDeleteAtomFromAtomTable(gAtomTable
,
194 UserFindCallProc(IN PWINDOWCLASS Class
,
200 CallProc
= Class
->CallProcList
;
201 while (CallProc
!= NULL
)
203 if (CallProc
->WndProc
== WndProc
&&
204 CallProc
->Unicode
== (UINT
)bUnicode
)
209 CallProc
= CallProc
->Next
;
216 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class
,
217 IN PCALLPROC CallProc
)
219 PWINDOWCLASS BaseClass
;
221 ASSERT(CallProc
->Next
== NULL
);
223 BaseClass
= Class
->Base
;
224 ASSERT(CallProc
->Next
== NULL
);
225 CallProc
->Next
= BaseClass
->CallProcList
;
226 BaseClass
->CallProcList
= CallProc
;
228 /* Update all clones */
229 Class
= Class
->Clone
;
230 while (Class
!= NULL
)
232 Class
->CallProcList
= BaseClass
->CallProcList
;
238 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
239 IN PUNICODE_STRING ClassName
)
241 RTL_ATOM Atom
= (RTL_ATOM
)0;
243 /* update the base class first */
246 if (!IntRegisterClassAtom(ClassName
,
252 IntDeregisterClassAtom(Class
->Atom
);
256 /* update the clones */
257 Class
= Class
->Clone
;
258 while (Class
!= NULL
)
269 IntGetClassWndProc(IN PWINDOWCLASS Class
,
270 IN PW32PROCESSINFO pi
,
273 ASSERT(UserIsEnteredExclusive() == TRUE
);
277 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
281 if (!Ansi
== Class
->Unicode
)
283 return Class
->WndProc
;
287 PWINDOWCLASS BaseClass
;
289 /* make sure the call procedures are located on the desktop
290 of the base class! */
291 BaseClass
= Class
->Base
;
294 if (Class
->CallProc
!= NULL
)
296 return GetCallProcHandle(Class
->CallProc
);
300 PCALLPROC NewCallProc
;
305 NewCallProc
= UserFindCallProc(Class
,
308 if (NewCallProc
== NULL
)
310 NewCallProc
= CreateCallProc(NULL
,
314 if (NewCallProc
== NULL
)
316 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
320 UserAddCallProcToClass(Class
,
324 Class
->CallProc
= NewCallProc
;
326 /* update the clones */
327 Class
= Class
->Clone
;
328 while (Class
!= NULL
)
330 Class
->CallProc
= NewCallProc
;
335 return GetCallProcHandle(NewCallProc
);
342 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
350 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
351 SetLastWin32Error(ERROR_ACCESS_DENIED
);
355 /* update the base class first */
358 /* resolve any callproc handle if possible */
359 if (IsCallProcHandle(WndProc
))
363 if (UserGetCallProcInfo((HANDLE
)WndProc
,
366 WndProc
= wpInfo
.WindowProc
;
367 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
371 Ret
= IntGetClassWndProc(Class
,
379 /* update the class info */
380 Class
->Unicode
= !Ansi
;
381 Class
->WndProc
= WndProc
;
383 /* update the clones */
384 Class
= Class
->Clone
;
385 while (Class
!= NULL
)
387 Class
->Unicode
= !Ansi
;
388 Class
->WndProc
= WndProc
;
397 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
398 IN OUT PWINDOWCLASS
*ClassLink
,
404 ASSERT(Desktop
!= NULL
);
405 ASSERT(BaseClass
->Base
== BaseClass
);
407 if (BaseClass
->Desktop
== Desktop
)
409 /* it is most likely that a window is created on the same
410 desktop as the window class. */
415 if (BaseClass
->Desktop
== NULL
)
417 ASSERT(BaseClass
->Windows
== 0);
418 ASSERT(BaseClass
->Clone
== NULL
);
420 /* Classes are also located in the shared heap when the class
421 was created before the thread attached to a desktop. As soon
422 as a window is created for such a class located on the shared
423 heap, the class is cloned into the desktop heap on which the
424 window is created. */
429 /* The user is asking for a class object on a different desktop,
431 Class
= BaseClass
->Clone
;
432 while (Class
!= NULL
)
434 if (Class
->Desktop
== Desktop
)
436 ASSERT(Class
->Base
== BaseClass
);
437 ASSERT(Class
->Clone
== NULL
);
447 /* The window is created on a different desktop, we need to
448 clone the class object to the desktop heap of the window! */
449 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
451 Class
= DesktopHeapAlloc(Desktop
,
455 /* simply clone the class */
460 /* update some pointers and link the class */
461 Class
->Desktop
= Desktop
;
464 if (BaseClass
->Desktop
== NULL
)
466 /* we don't really need the base class on the shared
467 heap anymore, delete it so the only class left is
468 the clone we just created, which now serves as the
470 ASSERT(BaseClass
->Clone
== NULL
);
471 ASSERT(Class
->Clone
== NULL
);
473 Class
->Next
= BaseClass
->Next
;
475 /* replace the base class */
476 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
479 /* destroy the obsolete copy on the shared heap */
480 BaseClass
->Base
= NULL
;
481 BaseClass
->Clone
= NULL
;
482 IntDestroyClass(BaseClass
);
486 /* link in the clone */
488 Class
->Base
= BaseClass
;
489 Class
->Next
= BaseClass
->Clone
;
490 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
496 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
504 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
505 IN OUT PWINDOWCLASS
*ClassLink
,
510 ASSERT(BaseClass
->Base
== BaseClass
);
512 Class
= IntGetClassForDesktop(BaseClass
,
524 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
525 IN OUT PWINDOWCLASS
*BaseClassLink
,
526 IN OUT PWINDOWCLASS
*CloneLink
)
528 PWINDOWCLASS Clone
, BaseClass
;
530 ASSERT(Class
->Base
!= Class
);
531 ASSERT(Class
->Base
->Clone
!= NULL
);
532 ASSERT(Class
->Desktop
!= NULL
);
533 ASSERT(Class
->Windows
!= 0);
534 ASSERT(Class
->Base
->Desktop
!= NULL
);
535 ASSERT(Class
->Base
->Windows
== 0);
537 /* unlink the clone */
538 *CloneLink
= Class
->Next
;
539 Class
->Clone
= Class
->Base
->Clone
;
541 BaseClass
= Class
->Base
;
543 /* update the class information to make it a base class */
545 Class
->Next
= (*BaseClassLink
)->Next
;
547 /* update all clones */
548 Clone
= Class
->Clone
;
549 while (Clone
!= NULL
)
551 ASSERT(Clone
->Clone
== NULL
);
555 Clone
->CallProc
= Class
->CallProc
;
560 /* link in the new base class */
561 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
566 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
568 IN PW32PROCESSINFO pi
)
570 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
572 BaseClass
= Class
->Base
;
574 if (--Class
->Windows
== 0)
576 if (BaseClass
== Class
)
578 ASSERT(Class
->Base
== Class
);
580 /* check if there are clones of the class on other desktops,
581 link the first clone in if possible. If there are no clones
582 then leave the class on the desktop heap. It will get moved
583 to the shared heap when the thread detaches. */
584 if (BaseClass
->Clone
!= NULL
)
586 if (BaseClass
->System
)
587 PrevLink
= &pi
->SystemClassList
;
588 else if (BaseClass
->Global
)
589 PrevLink
= &pi
->GlobalClassList
;
591 PrevLink
= &pi
->LocalClassList
;
593 CurrentClass
= *PrevLink
;
594 while (CurrentClass
!= BaseClass
)
596 ASSERT(CurrentClass
!= NULL
);
598 PrevLink
= &CurrentClass
->Next
;
599 CurrentClass
= CurrentClass
->Next
;
602 ASSERT(*PrevLink
== BaseClass
);
604 /* make the first clone become the new base class */
605 IntMakeCloneBaseClass(BaseClass
->Clone
,
609 /* destroy the class, there's still another clone of the class
610 that now serves as a base class. Make sure we don't destruct
611 resources shared by all classes (Base = NULL)! */
612 BaseClass
->Base
= NULL
;
613 BaseClass
->Clone
= NULL
;
614 IntDestroyClass(BaseClass
);
619 /* locate the cloned class and unlink it */
620 PrevLink
= &BaseClass
->Clone
;
621 CurrentClass
= BaseClass
->Clone
;
622 while (CurrentClass
!= Class
)
624 ASSERT(CurrentClass
!= NULL
);
626 PrevLink
= &CurrentClass
->Next
;
627 CurrentClass
= CurrentClass
->Next
;
630 ASSERT(CurrentClass
== Class
);
632 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
635 ASSERT(Class
->Base
== BaseClass
);
636 ASSERT(Class
->Clone
== NULL
);
638 /* the class was just a clone, we don't need it anymore */
639 IntDestroyClass(Class
);
645 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
646 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
648 PWINDOWCLASS NewClass
;
651 ASSERT(Class
->Base
== Class
);
652 ASSERT(Class
->Desktop
!= NULL
);
653 ASSERT(Class
->Windows
== 0);
654 ASSERT(Class
->Clone
== NULL
);
656 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
658 /* allocate the new base class on the shared heap */
659 NewClass
= UserHeapAlloc(ClassSize
);
660 if (NewClass
!= NULL
)
662 RtlCopyMemory(NewClass
,
666 NewClass
->Desktop
= NULL
;
667 NewClass
->Base
= NewClass
;
669 /* replace the class in the list */
670 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
672 *ClassLinkPtr
= &NewClass
->Next
;
674 /* free the obsolete class on the desktop heap */
676 IntDestroyClass(Class
);
684 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
685 IN OUT PWINDOWCLASS
*ClassList
,
686 IN BOOL FreeOnFailure
,
689 PWINDOWCLASS Class
, NextClass
, *Link
;
691 /* NOTE: We only need to check base classes! When classes are no longer needed
692 on a desktop, the clones will be freed automatically as soon as possible.
693 However, we need to move base classes to the shared heap, as soon as
694 the last desktop heap where a class is allocated on is about to be destroyed.
695 If we didn't move the class to the shared heap, the class would become
698 ASSERT(Desktop
!= NULL
);
702 while (Class
!= NULL
)
704 NextClass
= Class
->Next
;
706 ASSERT(Class
->Base
== Class
);
708 if (Class
->Desktop
== Desktop
&&
711 /* there shouldn't be any clones around anymore! */
712 ASSERT(Class
->Clone
== NULL
);
714 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
715 /* FIXME - We could move the class to another desktop heap if there's still desktops
716 mapped into the process... */
718 /* move the class to the shared heap */
719 if (IntMoveClassToSharedHeap(Class
,
722 ASSERT(*Link
== NextClass
);
726 ASSERT(NextClass
== Class
->Next
);
730 /* unlink the base class */
731 (void)InterlockedExchangePointer((PVOID
*)Link
,
734 /* we can free the old base class now */
736 IntDestroyClass(Class
);
753 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
754 IN BOOL FreeOnFailure
)
759 pi
= GetW32ProcessInfo();
763 /* check all local classes */
764 IntCheckDesktopClasses(Desktop
,
769 /* check all global classes */
770 IntCheckDesktopClasses(Desktop
,
771 &pi
->GlobalClassList
,
775 /* check all system classes */
776 IntCheckDesktopClasses(Desktop
,
777 &pi
->SystemClassList
,
783 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
784 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
791 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
792 IN PUNICODE_STRING ClassName
,
793 IN PUNICODE_STRING MenuName
,
797 IN PW32PROCESSINFO pi
)
800 PWINDOWCLASS Class
= NULL
;
802 PWSTR pszMenuName
= NULL
;
803 NTSTATUS Status
= STATUS_SUCCESS
;
805 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
806 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
808 if (!IntRegisterClassAtom(ClassName
,
811 DPRINT1("Failed to register class atom!\n");
815 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
816 if (MenuName
->Length
!= 0)
818 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
819 RtlUnicodeStringToAnsiSize(MenuName
));
820 if (pszMenuName
== NULL
)
826 Class
= DesktopHeapAlloc(Desktop
,
831 /* FIXME - the class was created before being connected
832 to a desktop. It is possible for the desktop window,
833 but should it be allowed for any other case? */
834 Class
= UserHeapAlloc(ClassSize
);
842 Class
->Desktop
= Desktop
;
846 if (dwFlags
& REGISTERCLASS_SYSTEM
)
848 dwFlags
&= ~REGISTERCLASS_ANSI
;
849 Class
->WndProcExtra
= wpExtra
;
850 Class
->System
= TRUE
;
855 PWSTR pszMenuNameBuffer
= pszMenuName
;
857 /* need to protect with SEH since accessing the WNDCLASSEX structure
858 and string buffers might raise an exception! We don't want to
860 Class
->WndProc
= lpwcx
->lpfnWndProc
;
861 Class
->Style
= lpwcx
->style
;
862 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
863 Class
->WndExtra
= lpwcx
->cbWndExtra
;
864 Class
->hInstance
= lpwcx
->hInstance
;
865 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
866 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
867 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
868 Class
->hbrBackground
= lpwcx
->hbrBackground
;
870 /* make a copy of the string */
871 if (pszMenuNameBuffer
!= NULL
)
873 Class
->MenuNameIsString
= TRUE
;
875 Class
->MenuName
= pszMenuNameBuffer
;
876 RtlCopyMemory(Class
->MenuName
,
879 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
881 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
884 Class
->MenuName
= MenuName
->Buffer
;
886 /* save an ansi copy of the string */
887 if (pszMenuNameBuffer
!= NULL
)
889 ANSI_STRING AnsiString
;
891 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
892 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
893 AnsiString
.Buffer
= Class
->AnsiMenuName
;
894 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("Failed to convert unicode menu name to ansi!\n");
901 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
906 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
908 if (!(dwFlags
& REGISTERCLASS_ANSI
))
909 Class
->Unicode
= TRUE
;
911 if (Class
->Style
& CS_GLOBALCLASS
)
912 Class
->Global
= TRUE
;
916 Status
= _SEH_GetExceptionCode();
920 if (!NT_SUCCESS(Status
))
922 DPRINT1("Failed creating the class: 0x%x\n", Status
);
924 SetLastNtError(Status
);
926 if (pszMenuName
!= NULL
)
927 UserHeapFree(pszMenuName
);
929 DesktopHeapFree(Desktop
,
933 IntDeregisterClassAtom(Atom
);
939 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
941 if (pszMenuName
!= NULL
)
942 UserHeapFree(pszMenuName
);
944 IntDeregisterClassAtom(Atom
);
946 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
953 IntFindClass(IN RTL_ATOM Atom
,
954 IN HINSTANCE hInstance
,
955 IN PWINDOWCLASS
*ClassList
,
956 OUT PWINDOWCLASS
**Link OPTIONAL
)
958 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
961 while (Class
!= NULL
)
963 if (Class
->Atom
== Atom
&&
964 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
967 ASSERT(Class
->Base
== Class
);
974 PrevLink
= &Class
->Next
;
982 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
987 if (ClassName
->Length
!= 0)
993 /* NOTE: Caller has to protect the call with SEH! */
995 if (ClassName
->Length
!= 0)
997 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
998 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1000 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1004 /* We need to make a local copy of the class name! The caller could
1005 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1006 We're protected by SEH, but the ranges that might be accessed were
1008 RtlCopyMemory(szBuf
,
1011 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1015 AtomName
= ClassName
->Buffer
;
1017 /* lookup the atom */
1018 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1021 if (NT_SUCCESS(Status
))
1027 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1029 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1033 SetLastNtError(Status
);
1039 ASSERT(IS_ATOM(ClassName
->Buffer
));
1040 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1048 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1049 IN HINSTANCE hInstance OPTIONAL
,
1050 IN PW32PROCESSINFO pi OPTIONAL
,
1051 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1052 OUT PWINDOWCLASS
**Link OPTIONAL
)
1054 RTL_ATOM Atom
= (RTL_ATOM
)0;
1056 ASSERT(BaseClass
!= NULL
);
1058 if (IntGetAtomFromStringOrAtom(ClassName
,
1060 Atom
!= (RTL_ATOM
)0)
1064 /* attempt to locate the class object */
1068 /* Step 1: try to find an exact match of locally registered classes */
1069 Class
= IntFindClass(Atom
,
1071 &pi
->LocalClassList
,
1078 /* Step 2: try to find any globally registered class. The hInstance
1079 is not relevant for global classes */
1080 Class
= IntFindClass(Atom
,
1082 &pi
->GlobalClassList
,
1089 /* Step 3: try to find any local class registered by user32 */
1090 Class
= IntFindClass(Atom
,
1092 &pi
->LocalClassList
,
1099 /* Step 4: try to find any global class registered by user32 */
1100 Class
= IntFindClass(Atom
,
1102 &pi
->GlobalClassList
,
1109 /* Step 5: try to find a system class */
1110 Class
= IntFindClass(Atom
,
1112 &pi
->SystemClassList
,
1116 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1128 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1129 IN PUNICODE_STRING ClassName
,
1130 IN PUNICODE_STRING MenuName
,
1131 IN HANDLE hMenu
, /* FIXME */
1139 RTL_ATOM Ret
= (RTL_ATOM
)0;
1141 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1143 ti
= GetW32ThreadInfo();
1144 if (ti
== NULL
|| !ti
->kpi
->RegisteredSysClasses
)
1146 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1152 /* try to find a previously registered class */
1153 ClassAtom
= IntGetClassAtom(ClassName
,
1158 if (ClassAtom
!= (RTL_ATOM
)0)
1160 if (lpwcx
->style
& CS_GLOBALCLASS
)
1162 // global classes shall not have same names as system classes
1163 if (Class
->Global
|| Class
->System
)
1165 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1166 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1170 else if ( !Class
->Global
&& !Class
->System
)
1172 // local class already exists
1173 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1174 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1179 Class
= IntCreateClass(lpwcx
,
1191 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1192 Class
->hMenu
= hMenu
;
1194 /* Register the class */
1196 List
= &pi
->SystemClassList
;
1197 else if (Class
->Global
)
1198 List
= &pi
->GlobalClassList
;
1200 List
= &pi
->LocalClassList
;
1202 Class
->Next
= *List
;
1203 (void)InterlockedExchangePointer((PVOID
*)List
,
1213 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1214 IN HINSTANCE hInstance
)
1221 pi
= GetW32ProcessInfo();
1224 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1228 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1230 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1231 ClassAtom
= IntGetClassAtom(ClassName
,
1236 if (ClassAtom
== (RTL_ATOM
)0)
1241 ASSERT(Class
!= NULL
);
1243 if (Class
->Windows
!= 0 ||
1244 Class
->Clone
!= NULL
)
1246 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1250 /* must be a base class! */
1251 ASSERT(Class
->Base
== Class
);
1253 /* unlink the class */
1254 *Link
= Class
->Next
;
1256 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1258 /* finally free the resources */
1259 IntDestroyClass(Class
);
1266 UserGetClassName(IN PWINDOWCLASS Class
,
1267 IN OUT PUNICODE_STRING ClassName
,
1270 NTSTATUS Status
= STATUS_SUCCESS
;
1271 WCHAR szStaticTemp
[32];
1272 PWSTR szTemp
= NULL
;
1273 ULONG BufLen
= sizeof(szStaticTemp
);
1276 /* Note: Accessing the buffer in ClassName may raise an exception! */
1282 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1283 UNICODE_STRING UnicodeClassName
;
1285 /* limit the size of the static buffer on the stack to the
1286 size of the buffer provided by the caller */
1287 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1289 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1292 /* find out how big the buffer needs to be */
1293 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1299 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1301 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1303 /* the buffer required exceeds the ansi buffer provided,
1304 pretend like we're using the ansi buffer and limit the
1305 size to the buffer size provided */
1306 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1309 /* allocate a temporary buffer that can hold the unicode class name */
1310 szTemp
= ExAllocatePool(PagedPool
,
1314 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1318 /* query the class name */
1319 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1327 szTemp
= szStaticTemp
;
1329 if (NT_SUCCESS(Status
))
1331 /* convert the atom name to ansi */
1333 RtlInitUnicodeString(&UnicodeClassName
,
1336 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1339 if (!NT_SUCCESS(Status
))
1341 SetLastNtError(Status
);
1346 Ret
= BufLen
/ sizeof(WCHAR
);
1350 BufLen
= ClassName
->MaximumLength
;
1352 /* query the atom name */
1353 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1360 if (!NT_SUCCESS(Status
))
1362 SetLastNtError(Status
);
1366 Ret
= BufLen
/ sizeof(WCHAR
);
1371 SetLastNtError(_SEH_GetExceptionCode());
1375 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1384 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1394 TRACE("GetClassLong(%d)\n", Index
);
1395 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1396 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1398 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1402 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1404 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1405 certain architectures, maybe using RtlCopyMemory is a
1406 better choice for those architectures! */
1408 TRACE("Result: %x\n", Ret
);
1414 case GCL_CBWNDEXTRA
:
1415 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1418 case GCL_CBCLSEXTRA
:
1419 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1422 case GCLP_HBRBACKGROUND
:
1423 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1427 /* FIXME - get handle from pointer to CURSOR object */
1428 Ret
= (ULONG_PTR
)Class
->hCursor
;
1432 /* FIXME - get handle from pointer to ICON object */
1433 Ret
= (ULONG_PTR
)Class
->hIcon
;
1437 /* FIXME - get handle from pointer to ICON object */
1438 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1442 Ret
= (ULONG_PTR
)Class
->hInstance
;
1446 /* NOTE: Returns pointer in kernel heap! */
1448 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1450 Ret
= (ULONG_PTR
)Class
->MenuName
;
1454 Ret
= (ULONG_PTR
)Class
->Style
;
1458 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1459 GetW32ProcessInfo(),
1464 Ret
= (ULONG_PTR
)Class
->Atom
;
1468 SetLastWin32Error(ERROR_INVALID_INDEX
);
1476 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1477 IN PUNICODE_STRING MenuName
)
1481 /* change the base class first */
1482 Class
= Class
->Base
;
1484 if (MenuName
->Length
!= 0)
1486 ANSI_STRING AnsiString
;
1489 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1491 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1492 AnsiString
.MaximumLength
);
1493 if (strBufW
!= NULL
)
1499 /* copy the unicode string */
1500 RtlCopyMemory(strBufW
,
1503 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1505 /* create an ansi copy of the string */
1506 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1507 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1510 if (!NT_SUCCESS(Status
))
1512 SetLastNtError(Status
);
1520 SetLastNtError(_SEH_GetExceptionCode());
1526 /* update the base class */
1527 IntFreeClassMenuName(Class
);
1528 Class
->MenuName
= strBufW
;
1529 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1530 Class
->MenuNameIsString
= TRUE
;
1532 /* update the clones */
1533 Class
= Class
->Clone
;
1534 while (Class
!= NULL
)
1536 Class
->MenuName
= strBufW
;
1537 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1538 Class
->MenuNameIsString
= TRUE
;
1540 Class
= Class
->Next
;
1545 DPRINT1("Failed to copy class menu name!\n");
1546 UserHeapFree(strBufW
);
1550 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1554 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1556 /* update the base class */
1557 IntFreeClassMenuName(Class
);
1558 Class
->MenuName
= MenuName
->Buffer
;
1559 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1560 Class
->MenuNameIsString
= FALSE
;
1562 /* update the clones */
1563 Class
= Class
->Clone
;
1564 while (Class
!= NULL
)
1566 Class
->MenuName
= MenuName
->Buffer
;
1567 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1568 Class
->MenuNameIsString
= FALSE
;
1570 Class
= Class
->Next
;
1580 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1582 IN ULONG_PTR NewLong
,
1587 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1589 /* change the information in the base class first, then update the clones */
1590 Class
= Class
->Base
;
1596 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1598 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1599 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1601 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1605 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1607 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1608 certain architectures, maybe using RtlCopyMemory is a
1609 better choice for those architectures! */
1613 /* update the clones */
1614 Class
= Class
->Clone
;
1615 while (Class
!= NULL
)
1617 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1618 Class
= Class
->Next
;
1626 case GCL_CBWNDEXTRA
:
1627 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1628 Class
->WndExtra
= (INT
)NewLong
;
1630 /* update the clones */
1631 Class
= Class
->Clone
;
1632 while (Class
!= NULL
)
1634 Class
->WndExtra
= (INT
)NewLong
;
1635 Class
= Class
->Next
;
1640 case GCL_CBCLSEXTRA
:
1641 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1644 case GCLP_HBRBACKGROUND
:
1645 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1646 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1648 /* update the clones */
1649 Class
= Class
->Clone
;
1650 while (Class
!= NULL
)
1652 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1653 Class
= Class
->Next
;
1658 /* FIXME - get handle from pointer to CURSOR object */
1659 Ret
= (ULONG_PTR
)Class
->hCursor
;
1660 Class
->hCursor
= (HANDLE
)NewLong
;
1662 /* update the clones */
1663 Class
= Class
->Clone
;
1664 while (Class
!= NULL
)
1666 Class
->hCursor
= (HANDLE
)NewLong
;
1667 Class
= Class
->Next
;
1672 /* FIXME - get handle from pointer to ICON object */
1673 Ret
= (ULONG_PTR
)Class
->hIcon
;
1674 Class
->hIcon
= (HANDLE
)NewLong
;
1676 /* update the clones */
1677 Class
= Class
->Clone
;
1678 while (Class
!= NULL
)
1680 Class
->hIcon
= (HANDLE
)NewLong
;
1681 Class
= Class
->Next
;
1686 /* FIXME - get handle from pointer to ICON object */
1687 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1688 Class
->hIconSm
= (HANDLE
)NewLong
;
1690 /* update the clones */
1691 Class
= Class
->Clone
;
1692 while (Class
!= NULL
)
1694 Class
->hIconSm
= (HANDLE
)NewLong
;
1695 Class
= Class
->Next
;
1700 Ret
= (ULONG_PTR
)Class
->hInstance
;
1701 Class
->hInstance
= (HINSTANCE
)NewLong
;
1703 /* update the clones */
1704 Class
= Class
->Clone
;
1705 while (Class
!= NULL
)
1707 Class
->hInstance
= (HINSTANCE
)NewLong
;
1708 Class
= Class
->Next
;
1714 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1716 if (!IntSetClassMenuName(Class
,
1719 DPRINT("Setting the class menu name failed!\n");
1722 /* FIXME - really return NULL? Wine does so... */
1727 Ret
= (ULONG_PTR
)Class
->Style
;
1728 Class
->Style
= (UINT
)NewLong
;
1730 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1731 move the class to the appropriate list? For now, we save
1732 the original value in Class->Global, so we can always
1733 locate the appropriate list */
1735 /* update the clones */
1736 Class
= Class
->Clone
;
1737 while (Class
!= NULL
)
1739 Class
->Style
= (UINT
)NewLong
;
1740 Class
= Class
->Next
;
1745 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1752 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1754 Ret
= (ULONG_PTR
)Class
->Atom
;
1755 if (!IntSetClassAtom(Class
,
1764 SetLastWin32Error(ERROR_INVALID_INDEX
);
1772 UserGetClassInfo(IN PWINDOWCLASS Class
,
1773 OUT PWNDCLASSEXW lpwcx
,
1775 HINSTANCE hInstance
)
1779 lpwcx
->style
= Class
->Style
;
1781 pi
= GetW32ProcessInfo();
1782 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1786 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1787 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1788 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1789 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1790 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1793 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1795 lpwcx
->lpszMenuName
= Class
->MenuName
;
1797 if (Class
->hInstance
== pi
->hModUser
)
1798 lpwcx
->hInstance
= NULL
;
1800 lpwcx
->hInstance
= Class
->hInstance
;
1802 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1804 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1810 UserRegisterSystemClasses(IN ULONG Count
,
1811 IN PREGISTER_SYSCLASS SystemClasses
)
1813 /* NOTE: This routine may raise exceptions! */
1815 UNICODE_STRING ClassName
, MenuName
;
1816 PW32PROCESSINFO pi
= GetW32ProcessInfo();
1821 if (pi
->RegisteredSysClasses
|| pi
->hModUser
== NULL
)
1824 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1826 for (i
= 0; i
!= Count
; i
++)
1828 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1829 if (ClassName
.Length
!= 0)
1831 ProbeForRead(ClassName
.Buffer
,
1836 wc
.cbSize
= sizeof(wc
);
1837 wc
.style
= SystemClasses
[i
].Style
;
1838 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1840 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1841 wc
.hInstance
= pi
->hModUser
;
1843 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1844 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1845 wc
.lpszMenuName
= NULL
;
1846 wc
.lpszClassName
= ClassName
.Buffer
;
1849 Class
= IntCreateClass(&wc
,
1852 SystemClasses
[i
].ProcA
,
1853 REGISTERCLASS_SYSTEM
,
1858 Class
->ClassId
= SystemClasses
[i
].ClassId
;
1860 ASSERT(Class
->System
);
1861 Class
->Next
= pi
->SystemClassList
;
1862 (void)InterlockedExchangePointer((PVOID
*)&pi
->SystemClassList
,
1867 WARN("!!! Registering system class failed!\n");
1873 pi
->RegisteredSysClasses
= TRUE
;
1877 /* SYSCALLS *****************************************************************/
1881 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1882 IN PUNICODE_STRING ClassName
,
1883 IN PUNICODE_STRING MenuName
,
1890 * Registers a new class with the window manager
1892 * lpwcx = Win32 extended window class structure
1893 * bUnicodeClass = Whether to send ANSI or unicode strings
1894 * to window procedures
1895 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1897 * Atom identifying the new class
1900 WNDCLASSEXW CapturedClassInfo
= {0};
1901 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1902 RTL_ATOM Ret
= (RTL_ATOM
)0;
1904 if (Flags
& ~REGISTERCLASS_ALL
)
1906 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1910 UserEnterExclusive();
1914 /* Probe the parameters and basic parameter checks */
1915 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1917 goto InvalidParameter
;
1921 sizeof(WNDCLASSEXW
),
1923 RtlCopyMemory(&CapturedClassInfo
,
1925 sizeof(WNDCLASSEXW
));
1927 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1928 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1930 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1931 CapturedClassInfo
.cbClsExtra
< 0 ||
1932 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1933 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1934 CapturedClassInfo
.cbWndExtra
< 0 ||
1935 CapturedClassInfo
.hInstance
== NULL
)
1937 goto InvalidParameter
;
1940 if (CapturedName
.Length
!= 0)
1942 ProbeForRead(CapturedName
.Buffer
,
1943 CapturedName
.Length
,
1948 if (!IS_ATOM(CapturedName
.Buffer
))
1950 goto InvalidParameter
;
1954 if (CapturedMenuName
.Length
!= 0)
1956 ProbeForRead(CapturedMenuName
.Buffer
,
1957 CapturedMenuName
.Length
,
1960 else if (CapturedMenuName
.Buffer
!= NULL
&&
1961 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1964 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1968 /* Register the class */
1969 Ret
= UserRegisterClass(&CapturedClassInfo
,
1972 hMenu
, /* FIXME - pass pointer */
1979 SetLastNtError(_SEH_GetExceptionCode());
1991 NtUserGetClassLong(IN HWND hWnd
,
1995 PWINDOW_OBJECT Window
;
1998 if (Offset
!= GCLP_WNDPROC
)
2004 UserEnterExclusive();
2007 Window
= UserGetWindowObject(hWnd
);
2010 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
2014 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
2016 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2028 NtUserSetClassLong(HWND hWnd
,
2030 ULONG_PTR dwNewLong
,
2034 PWINDOW_OBJECT Window
;
2037 UserEnterExclusive();
2039 pi
= GetW32ProcessInfo();
2043 Window
= UserGetWindowObject(hWnd
);
2046 if (Window
->ti
->kpi
!= pi
)
2048 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2054 UNICODE_STRING Value
;
2056 /* probe the parameters */
2057 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2059 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2060 if (Value
.Length
& 1)
2062 goto InvalidParameter
;
2065 if (Value
.Length
!= 0)
2067 ProbeForRead(Value
.Buffer
,
2073 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2075 goto InvalidParameter
;
2077 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2080 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2085 dwNewLong
= (ULONG_PTR
)&Value
;
2088 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2095 SetLastNtError(_SEH_GetExceptionCode());
2107 NtUserSetClassWord(DWORD Unknown0
,
2115 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2116 IN HINSTANCE hInstance
,
2119 UNICODE_STRING CapturedClassName
;
2122 UserEnterExclusive();
2126 /* probe the paramters */
2127 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2128 if (CapturedClassName
.Length
& 1)
2130 goto InvalidParameter
;
2133 if (CapturedClassName
.Length
!= 0)
2135 ProbeForRead(CapturedClassName
.Buffer
,
2136 CapturedClassName
.Length
,
2141 if (!IS_ATOM(CapturedClassName
.Buffer
))
2144 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2149 /* unregister the class */
2150 Ret
= UserUnregisterClass(&CapturedClassName
,
2155 SetLastNtError(_SEH_GetExceptionCode());
2164 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2167 HINSTANCE hInstance
,
2168 PUNICODE_STRING ClassName
,
2169 LPWNDCLASSEXW lpWndClassEx
,
2170 LPWSTR
*ppszMenuName
,
2173 UNICODE_STRING CapturedClassName
;
2179 /* NOTE: need exclusive lock because getting the wndproc might require the
2180 creation of a call procedure handle */
2181 UserEnterExclusive();
2183 pi
= GetW32ProcessInfo();
2186 ERR("GetW32ProcessInfo() returned NULL!\n");
2191 /* probe the paramters */
2192 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2194 if (CapturedClassName
.Length
== 0)
2195 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2197 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2199 if (CapturedClassName
.Length
& 1)
2201 goto InvalidParameter
;
2204 if (CapturedClassName
.Length
!= 0)
2206 ProbeForRead(CapturedClassName
.Buffer
,
2207 CapturedClassName
.Length
,
2212 if (!IS_ATOM(CapturedClassName
.Buffer
))
2214 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2215 goto InvalidParameter
;
2219 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2222 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2226 ProbeForWrite(lpWndClassEx
,
2227 sizeof(WNDCLASSEXW
),
2230 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2235 if (ClassAtom
!= (RTL_ATOM
)0)
2237 if (hInstance
== NULL
)
2238 hInstance
= pi
->hModUser
;
2240 Ret
= UserGetClassInfo(Class
,
2247 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2248 /* FIXME - handle Class->Desktop == NULL!!!!! */
2250 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2252 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2253 (PVOID
)Class
->AnsiMenuName
:
2254 (PVOID
)Class
->MenuName
);
2257 /* Undocumented behavior! Return the class atom as a BOOL! */
2258 Ret
= (BOOL
)ClassAtom
;
2262 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2266 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2278 NtUserGetClassName (IN HWND hWnd
,
2279 OUT PUNICODE_STRING ClassName
,
2282 PWINDOW_OBJECT Window
;
2283 UNICODE_STRING CapturedClassName
;
2288 Window
= UserGetWindowObject(hWnd
);
2293 ProbeForWriteUnicodeString(ClassName
);
2294 CapturedClassName
= *ClassName
;
2296 /* get the class name */
2297 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2303 /* update the Length field */
2304 ClassName
->Length
= CapturedClassName
.Length
;
2309 SetLastNtError(_SEH_GetExceptionCode());
2320 NtUserGetWOWClass(DWORD Unknown0
,