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 /* destruct resources shared with clones */
63 if (!Class
->System
&& Class
->CallProc
!= NULL
)
65 DestroyCallProc(Class
->GlobalCallProc
? NULL
: Class
->Desktop
,
69 if (Class
->CallProc2
!= NULL
)
71 DestroyCallProc(Class
->GlobalCallProc2
? NULL
: Class
->Desktop
,
75 IntFreeClassMenuName(Class
);
78 /* free the structure */
79 if (Class
->Desktop
!= NULL
)
81 DesktopHeapFree(Class
->Desktop
,
91 /* clean all process classes. all process windows must cleaned first!! */
92 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
95 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
99 /* free all local classes */
100 Class
= pi
->LocalClassList
;
101 while (Class
!= NULL
)
103 pi
->LocalClassList
= Class
->Next
;
105 ASSERT(Class
->Base
== Class
);
106 IntDestroyClass(Class
);
108 Class
= pi
->LocalClassList
;
111 /* free all global classes */
112 Class
= pi
->GlobalClassList
;
113 while (Class
!= NULL
)
115 pi
->GlobalClassList
= Class
->Next
;
117 ASSERT(Class
->Base
== Class
);
118 IntDestroyClass(Class
);
120 Class
= pi
->GlobalClassList
;
123 /* free all system classes */
124 Class
= pi
->SystemClassList
;
125 while (Class
!= NULL
)
127 pi
->SystemClassList
= Class
->Next
;
129 ASSERT(Class
->Base
== Class
);
130 IntDestroyClass(Class
);
132 Class
= pi
->SystemClassList
;
138 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
145 if (ClassName
->Length
!= 0)
147 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
148 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
150 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
157 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
161 AtomName
= ClassName
->Buffer
;
163 Status
= RtlAddAtomToAtomTable(gAtomTable
,
167 if (!NT_SUCCESS(Status
))
169 SetLastNtError(Status
);
177 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
179 return RtlDeleteAtomFromAtomTable(gAtomTable
,
184 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
185 IN PUNICODE_STRING ClassName
)
187 RTL_ATOM Atom
= (RTL_ATOM
)0;
189 /* update the base class first */
192 if (!IntRegisterClassAtom(ClassName
,
198 IntDeregisterClassAtom(Class
->Atom
);
202 /* update the clones */
203 Class
= Class
->Clone
;
204 while (Class
!= NULL
)
215 IntGetClassWndProc(IN PWINDOWCLASS Class
,
216 IN PW32PROCESSINFO pi
,
218 IN BOOL UseCallProc2
)
220 ASSERT(UserIsEnteredExclusive() == TRUE
);
224 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
228 if (!Ansi
== Class
->Unicode
)
230 return Class
->WndProc
;
234 PCALLPROC
*CallProcPtr
;
235 PWINDOWCLASS BaseClass
;
237 /* make sure the call procedures are located on the desktop
238 of the base class! */
239 BaseClass
= Class
->Base
;
242 CallProcPtr
= (UseCallProc2
? &Class
->CallProc2
: &Class
->CallProc
);
244 if (*CallProcPtr
!= NULL
)
246 return GetCallProcHandle(*CallProcPtr
);
250 PCALLPROC NewCallProc
;
255 NewCallProc
= CreateCallProc(Class
->Desktop
,
259 if (NewCallProc
== NULL
)
261 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
265 *CallProcPtr
= NewCallProc
;
267 if (Class
->Desktop
== NULL
)
270 Class
->GlobalCallProc2
= TRUE
;
272 Class
->GlobalCallProc
= TRUE
;
275 /* update the clones */
276 Class
= Class
->Clone
;
277 while (Class
!= NULL
)
281 Class
->CallProc2
= NewCallProc
;
282 Class
->GlobalCallProc2
= BaseClass
->GlobalCallProc2
;
286 Class
->CallProc
= NewCallProc
;
287 Class
->GlobalCallProc
= BaseClass
->GlobalCallProc
;
293 return GetCallProcHandle(NewCallProc
);
300 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
308 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
309 SetLastWin32Error(ERROR_ACCESS_DENIED
);
313 /* update the base class first */
316 /* resolve any callproc handle if possible */
317 if (IsCallProcHandle(WndProc
))
321 if (UserGetCallProcInfo((HANDLE
)WndProc
,
324 WndProc
= wpInfo
.WindowProc
;
325 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
329 Ret
= IntGetClassWndProc(Class
,
338 /* update the class info */
339 Class
->Unicode
= !Ansi
;
340 Class
->WndProc
= WndProc
;
341 if (Class
->CallProc
!= NULL
)
343 Class
->CallProc
->WndProc
= WndProc
;
344 Class
->CallProc
->Unicode
= !Ansi
;
347 /* update the clones */
348 Class
= Class
->Clone
;
349 while (Class
!= NULL
)
351 Class
->Unicode
= !Ansi
;
352 Class
->WndProc
= WndProc
;
361 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
362 IN OUT PWINDOWCLASS
*ClassLink
,
368 ASSERT(Desktop
!= NULL
);
369 ASSERT(BaseClass
->Base
== BaseClass
);
371 if (BaseClass
->Desktop
== Desktop
)
373 /* it is most likely that a window is created on the same
374 desktop as the window class. */
379 if (BaseClass
->Desktop
== NULL
)
381 ASSERT(BaseClass
->Windows
== 0);
382 ASSERT(BaseClass
->Clone
== NULL
);
384 /* Classes are also located in the shared heap when the class
385 was created before the thread attached to a desktop. As soon
386 as a window is created for such a class located on the shared
387 heap, the class is cloned into the desktop heap on which the
388 window is created. */
393 /* The user is asking for a class object on a different desktop,
395 Class
= BaseClass
->Clone
;
396 while (Class
!= NULL
)
398 if (Class
->Desktop
== Desktop
)
400 ASSERT(Class
->Base
== BaseClass
);
401 ASSERT(Class
->Clone
== NULL
);
411 /* The window is created on a different desktop, we need to
412 clone the class object to the desktop heap of the window! */
413 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
415 Class
= DesktopHeapAlloc(Desktop
,
419 /* simply clone the class */
424 /* update some pointers and link the class */
425 Class
->Desktop
= Desktop
;
428 if (BaseClass
->Desktop
== NULL
)
430 /* we don't really need the base class on the shared
431 heap anymore, delete it so the only class left is
432 the clone we just created, which now serves as the
434 ASSERT(BaseClass
->Clone
== NULL
);
435 ASSERT(Class
->Clone
== NULL
);
437 Class
->Next
= BaseClass
->Next
;
439 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
)
440 Class
->GlobalCallProc
= TRUE
;
441 if (BaseClass
->CallProc2
!= NULL
)
442 Class
->GlobalCallProc2
= TRUE
;
444 /* replace the base class */
445 (void)InterlockedExchangePointer(ClassLink
,
448 /* destroy the obsolete copy on the shared heap */
449 BaseClass
->Base
= NULL
;
450 BaseClass
->Clone
= NULL
;
451 IntDestroyClass(BaseClass
);
455 /* link in the clone */
457 Class
->Base
= BaseClass
;
458 Class
->Next
= BaseClass
->Clone
;
459 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
465 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
473 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
474 IN OUT PWINDOWCLASS
*ClassLink
,
479 ASSERT(BaseClass
->Base
== BaseClass
);
481 Class
= IntGetClassForDesktop(BaseClass
,
493 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
494 IN OUT PWINDOWCLASS
*BaseClassLink
,
495 IN OUT PWINDOWCLASS
*CloneLink
)
497 PWINDOWCLASS Clone
, BaseClass
;
500 ASSERT(Class
->Base
!= Class
);
501 ASSERT(Class
->Base
->Clone
!= NULL
);
502 ASSERT(Class
->Desktop
!= NULL
);
503 ASSERT(Class
->Windows
!= 0);
504 ASSERT(Class
->Base
->Desktop
!= NULL
);
505 ASSERT(Class
->Base
->Windows
== 0);
507 /* unlink the clone */
508 *CloneLink
= Class
->Next
;
509 Class
->Clone
= Class
->Base
->Clone
;
511 BaseClass
= Class
->Base
;
513 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
&&
514 !BaseClass
->GlobalCallProc
)
516 /* we need to move the allocated call procedure */
517 CallProc
= BaseClass
->CallProc
;
518 Class
->CallProc
= CloneCallProc(Class
->Desktop
,
520 DestroyCallProc(BaseClass
->Desktop
,
524 if (BaseClass
->CallProc2
!= NULL
&&
525 !BaseClass
->GlobalCallProc2
)
527 /* we need to move the allocated call procedure */
528 CallProc
= BaseClass
->CallProc2
;
529 Class
->CallProc2
= CloneCallProc(Class
->Desktop
,
531 DestroyCallProc(BaseClass
->Desktop
,
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
;
548 Clone
->CallProc2
= Class
->CallProc2
;
553 /* link in the new base class */
554 (void)InterlockedExchangePointer(BaseClassLink
,
559 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
561 IN PW32PROCESSINFO pi
)
563 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
565 BaseClass
= Class
->Base
;
567 if (--Class
->Windows
== 0)
569 if (BaseClass
== Class
)
571 ASSERT(Class
->Base
== Class
);
573 /* check if there are clones of the class on other desktops,
574 link the first clone in if possible. If there are no clones
575 then leave the class on the desktop heap. It will get moved
576 to the shared heap when the thread detaches. */
577 if (BaseClass
->Clone
!= NULL
)
579 if (BaseClass
->System
)
580 PrevLink
= &pi
->SystemClassList
;
581 else if (BaseClass
->Global
)
582 PrevLink
= &pi
->GlobalClassList
;
584 PrevLink
= &pi
->LocalClassList
;
586 while (*PrevLink
!= BaseClass
)
588 ASSERT(*PrevLink
!= NULL
);
589 PrevLink
= &BaseClass
->Next
;
592 ASSERT(*PrevLink
== BaseClass
);
594 /* make the first clone become the new base class */
595 IntMakeCloneBaseClass(BaseClass
->Clone
,
599 /* destroy the class, there's still another clone of the class
600 that now serves as a base class. Make sure we don't destruct
601 resources shared by all classes (Base = NULL)! */
602 BaseClass
->Base
= NULL
;
603 BaseClass
->Clone
= NULL
;
604 IntDestroyClass(BaseClass
);
609 /* locate the cloned class and unlink it */
610 PrevLink
= &BaseClass
->Clone
;
611 CurrentClass
= BaseClass
->Clone
;
612 while (CurrentClass
!= Class
)
614 ASSERT(CurrentClass
!= NULL
);
616 PrevLink
= &CurrentClass
->Next
;
617 CurrentClass
= CurrentClass
->Next
;
620 ASSERT(CurrentClass
== Class
);
622 (void)InterlockedExchangePointer(PrevLink
,
625 ASSERT(Class
->Base
== BaseClass
);
626 ASSERT(Class
->Clone
== NULL
);
628 /* the class was just a clone, we don't need it anymore */
629 IntDestroyClass(Class
);
635 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
636 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
638 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 if (!NewClass
->System
&& NewClass
->CallProc
!= NULL
&&
661 !NewClass
->GlobalCallProc
)
663 /* we need to move the allocated call procedure to the shared heap */
664 CallProc
= NewClass
->CallProc
;
665 NewClass
->CallProc
= CloneCallProc(NULL
,
667 DestroyCallProc(Class
->Desktop
,
670 NewClass
->GlobalCallProc
= TRUE
;
673 if (NewClass
->CallProc2
!= NULL
&&
674 !NewClass
->GlobalCallProc2
)
676 /* we need to move the allocated call procedure to the shared heap */
677 CallProc
= NewClass
->CallProc2
;
678 NewClass
->CallProc2
= CloneCallProc(NULL
,
680 DestroyCallProc(Class
->Desktop
,
683 NewClass
->GlobalCallProc2
= TRUE
;
686 /* replace the class in the list */
687 (void)InterlockedExchangePointer(*ClassLinkPtr
,
689 *ClassLinkPtr
= &NewClass
->Next
;
691 /* free the obsolete class on the desktop heap */
693 IntDestroyClass(Class
);
701 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
702 IN OUT PWINDOWCLASS
*ClassList
,
703 IN BOOL FreeOnFailure
,
706 PWINDOWCLASS Class
, NextClass
, *Link
;
708 /* NOTE: We only need to check base classes! When classes are no longer needed
709 on a desktop, the clones will be freed automatically as soon as possible.
710 However, we need to move base classes to the shared heap, as soon as
711 the last desktop heap where a class is allocated on is about to be destroyed.
712 If we didn't move the class to the shared heap, the class would become
715 ASSERT(Desktop
!= NULL
);
719 while (Class
!= NULL
)
721 NextClass
= Class
->Next
;
723 ASSERT(Class
->Base
== Class
);
725 if (Class
->Desktop
== Desktop
&&
728 /* there shouldn't be any clones around anymore! */
729 ASSERT(Class
->Clone
== NULL
);
731 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
732 /* FIXME - We could move the class to another desktop heap if there's still desktops
733 mapped into the process... */
735 /* move the class to the shared heap */
736 if (IntMoveClassToSharedHeap(Class
,
739 ASSERT(*Link
== NextClass
);
743 ASSERT(NextClass
== Class
->Next
);
747 /* unlink the base class */
748 (void)InterlockedExchangePointer(Link
,
751 /* we can free the old base class now */
753 IntDestroyClass(Class
);
770 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
771 IN BOOL FreeOnFailure
)
776 pi
= GetW32ProcessInfo();
780 /* check all local classes */
781 IntCheckDesktopClasses(Desktop
,
786 /* check all global classes */
787 IntCheckDesktopClasses(Desktop
,
788 &pi
->GlobalClassList
,
792 /* check all system classes */
793 IntCheckDesktopClasses(Desktop
,
794 &pi
->SystemClassList
,
800 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
801 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
808 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
809 IN PUNICODE_STRING ClassName
,
810 IN PUNICODE_STRING MenuName
,
814 IN PW32PROCESSINFO pi
)
817 PWINDOWCLASS Class
= NULL
;
819 PWSTR pszMenuName
= NULL
;
820 NTSTATUS Status
= STATUS_SUCCESS
;
822 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
823 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
825 if (!IntRegisterClassAtom(ClassName
,
828 DPRINT1("Failed to register class atom!\n");
832 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
833 if (MenuName
->Length
!= 0)
835 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
836 RtlUnicodeStringToAnsiSize(MenuName
));
837 if (pszMenuName
== NULL
)
843 Class
= DesktopHeapAlloc(Desktop
,
848 /* FIXME - the class was created before being connected
849 to a desktop. It is possible for the desktop window,
850 but should it be allowed for any other case? */
851 Class
= UserHeapAlloc(ClassSize
);
859 Class
->Desktop
= Desktop
;
863 if (dwFlags
& REGISTERCLASS_SYSTEM
)
865 dwFlags
&= ~REGISTERCLASS_ANSI
;
866 Class
->WndProcExtra
= wpExtra
;
867 Class
->System
= TRUE
;
872 PWSTR pszMenuNameBuffer
= pszMenuName
;
874 /* need to protect with SEH since accessing the WNDCLASSEX structure
875 and string buffers might raise an exception! We don't want to
877 Class
->WndProc
= lpwcx
->lpfnWndProc
;
878 Class
->Style
= lpwcx
->style
;
879 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
880 Class
->WndExtra
= lpwcx
->cbWndExtra
;
881 Class
->hInstance
= lpwcx
->hInstance
;
882 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
883 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
884 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
885 Class
->hbrBackground
= lpwcx
->hbrBackground
;
887 /* make a copy of the string */
888 if (pszMenuNameBuffer
!= NULL
)
890 Class
->MenuNameIsString
= TRUE
;
892 Class
->MenuName
= pszMenuNameBuffer
;
893 RtlCopyMemory(Class
->MenuName
,
896 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
898 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
901 Class
->MenuName
= MenuName
->Buffer
;
903 /* save an ansi copy of the string */
904 if (pszMenuNameBuffer
!= NULL
)
906 ANSI_STRING AnsiString
;
908 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
909 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
910 AnsiString
.Buffer
= Class
->AnsiMenuName
;
911 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
914 if (!NT_SUCCESS(Status
))
916 DPRINT1("Failed to convert unicode menu name to ansi!\n");
918 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
923 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
925 if (!(dwFlags
& REGISTERCLASS_ANSI
))
926 Class
->Unicode
= TRUE
;
928 if (Class
->Style
& CS_GLOBALCLASS
)
929 Class
->Global
= TRUE
;
933 Status
= _SEH_GetExceptionCode();
937 if (!NT_SUCCESS(Status
))
939 DPRINT1("Failed creating the class: 0x%x\n", Status
);
941 SetLastNtError(Status
);
943 if (pszMenuName
!= NULL
)
944 UserHeapFree(pszMenuName
);
946 DesktopHeapFree(Desktop
,
950 IntDeregisterClassAtom(Atom
);
956 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
958 if (pszMenuName
!= NULL
)
959 UserHeapFree(pszMenuName
);
961 IntDeregisterClassAtom(Atom
);
963 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
970 IntFindClass(IN RTL_ATOM Atom
,
971 IN HINSTANCE hInstance
,
972 IN PWINDOWCLASS
*ClassList
,
973 OUT PWINDOWCLASS
**Link OPTIONAL
)
975 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
978 while (Class
!= NULL
)
980 if (Class
->Atom
== Atom
&&
981 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
984 ASSERT(Class
->Base
== Class
);
991 PrevLink
= &Class
->Next
;
999 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1004 if (ClassName
->Length
!= 0)
1010 /* NOTE: Caller has to protect the call with SEH! */
1012 if (ClassName
->Length
!= 0)
1014 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1015 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1017 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1021 /* We need to make a local copy of the class name! The caller could
1022 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1023 We're protected by SEH, but the ranges that might be accessed were
1025 RtlCopyMemory(szBuf
,
1028 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1032 AtomName
= ClassName
->Buffer
;
1034 /* lookup the atom */
1035 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1038 if (NT_SUCCESS(Status
))
1044 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1046 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1050 SetLastNtError(Status
);
1056 ASSERT(IS_ATOM(ClassName
->Buffer
));
1057 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1065 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1066 IN HINSTANCE hInstance OPTIONAL
,
1067 IN PW32PROCESSINFO pi OPTIONAL
,
1068 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1069 OUT PWINDOWCLASS
**Link OPTIONAL
)
1071 RTL_ATOM Atom
= (RTL_ATOM
)0;
1073 if (IntGetAtomFromStringOrAtom(ClassName
,
1075 BaseClass
!= NULL
&& Atom
!= (RTL_ATOM
)0)
1079 /* attempt to locate the class object */
1083 /* Step 1: try to find an exact match of locally registered classes */
1084 Class
= IntFindClass(Atom
,
1086 &pi
->LocalClassList
,
1093 /* Step 2: try to find any globally registered class. The hInstance
1094 is not relevant for global classes */
1095 Class
= IntFindClass(Atom
,
1097 &pi
->GlobalClassList
,
1104 /* Step 3: try to find any local class registered by user32 */
1105 Class
= IntFindClass(Atom
,
1107 &pi
->LocalClassList
,
1114 /* Step 4: try to find any global class registered by user32 */
1115 Class
= IntFindClass(Atom
,
1117 &pi
->GlobalClassList
,
1124 /* Step 5: try to find a system class */
1125 Class
= IntFindClass(Atom
,
1127 &pi
->SystemClassList
,
1132 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1144 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1145 IN PUNICODE_STRING ClassName
,
1146 IN PUNICODE_STRING MenuName
,
1147 IN HANDLE hMenu
, /* FIXME */
1155 RTL_ATOM Ret
= (RTL_ATOM
)0;
1157 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1159 ti
= GetW32ThreadInfo();
1162 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1168 /* try to find a previously registered class */
1169 ClassAtom
= IntGetClassAtom(ClassName
,
1174 if (ClassAtom
!= (RTL_ATOM
)0)
1176 if (lpwcx
->style
& CS_GLOBALCLASS
)
1178 // global classes shall not have same names as system classes
1179 if (Class
->Global
|| Class
->System
)
1181 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1182 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1186 else if ( !Class
->Global
&& !Class
->System
)
1188 // local class already exists
1189 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1190 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1195 Class
= IntCreateClass(lpwcx
,
1207 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1208 Class
->hMenu
= hMenu
;
1210 /* Register the class */
1212 List
= &pi
->SystemClassList
;
1213 else if (Class
->Global
)
1214 List
= &pi
->GlobalClassList
;
1216 List
= &pi
->LocalClassList
;
1218 Class
->Next
= *List
;
1219 (void)InterlockedExchangePointer(List
,
1229 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1230 IN HINSTANCE hInstance
)
1237 pi
= GetW32ProcessInfo();
1240 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1244 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1246 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1247 ClassAtom
= IntGetClassAtom(ClassName
,
1252 if (ClassAtom
== (RTL_ATOM
)0)
1257 ASSERT(Class
!= NULL
);
1259 if (Class
->Windows
!= 0 ||
1260 Class
->Clone
!= NULL
)
1262 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1266 /* must be a base class! */
1267 ASSERT(Class
->Base
== Class
);
1269 /* unlink the class */
1270 *Link
= Class
->Next
;
1272 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1274 /* finally free the resources */
1275 IntDestroyClass(Class
);
1282 UserGetClassName(IN PWINDOWCLASS Class
,
1283 IN OUT PUNICODE_STRING ClassName
,
1286 NTSTATUS Status
= STATUS_SUCCESS
;
1287 WCHAR szStaticTemp
[32];
1288 PWSTR szTemp
= NULL
;
1289 ULONG BufLen
= sizeof(szStaticTemp
);
1292 /* Note: Accessing the buffer in ClassName may raise an exception! */
1298 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1299 UNICODE_STRING UnicodeClassName
;
1301 /* limit the size of the static buffer on the stack to the
1302 size of the buffer provided by the caller */
1303 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1305 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1308 /* find out how big the buffer needs to be */
1309 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1315 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1317 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1319 /* the buffer required exceeds the ansi buffer provided,
1320 pretend like we're using the ansi buffer and limit the
1321 size to the buffer size provided */
1322 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1325 /* allocate a temporary buffer that can hold the unicode class name */
1326 szTemp
= ExAllocatePool(PagedPool
,
1330 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1334 /* query the class name */
1335 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1343 szTemp
= szStaticTemp
;
1345 if (NT_SUCCESS(Status
))
1347 /* convert the atom name to ansi */
1349 RtlInitUnicodeString(&UnicodeClassName
,
1352 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1355 if (!NT_SUCCESS(Status
))
1357 SetLastNtError(Status
);
1362 Ret
= BufLen
/ sizeof(WCHAR
);
1366 BufLen
= ClassName
->MaximumLength
;
1368 /* query the atom name */
1369 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1376 if (!NT_SUCCESS(Status
))
1378 SetLastNtError(Status
);
1382 Ret
= BufLen
/ sizeof(WCHAR
);
1387 SetLastNtError(_SEH_GetExceptionCode());
1391 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1400 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1410 TRACE("GetClassLong(%d)\n", Index
);
1411 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1412 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1414 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1418 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1420 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1421 certain architectures, maybe using RtlCopyMemory is a
1422 better choice for those architectures! */
1424 TRACE("Result: %x\n", Ret
);
1430 case GCL_CBWNDEXTRA
:
1431 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1434 case GCL_CBCLSEXTRA
:
1435 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1438 case GCLP_HBRBACKGROUND
:
1439 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1443 /* FIXME - get handle from pointer to CURSOR object */
1444 Ret
= (ULONG_PTR
)Class
->hCursor
;
1448 /* FIXME - get handle from pointer to ICON object */
1449 Ret
= (ULONG_PTR
)Class
->hIcon
;
1453 /* FIXME - get handle from pointer to ICON object */
1454 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1458 Ret
= (ULONG_PTR
)Class
->hInstance
;
1462 /* NOTE: Returns pointer in kernel heap! */
1464 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1466 Ret
= (ULONG_PTR
)Class
->MenuName
;
1470 Ret
= (ULONG_PTR
)Class
->Style
;
1474 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1475 GetW32ProcessInfo(),
1481 Ret
= (ULONG_PTR
)Class
->Atom
;
1485 SetLastWin32Error(ERROR_INVALID_INDEX
);
1493 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1494 IN PUNICODE_STRING MenuName
)
1498 /* change the base class first */
1499 Class
= Class
->Base
;
1501 if (MenuName
->Length
!= 0)
1503 ANSI_STRING AnsiString
;
1506 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1508 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1509 AnsiString
.MaximumLength
);
1510 if (strBufW
!= NULL
)
1516 /* copy the unicode string */
1517 RtlCopyMemory(strBufW
,
1520 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1522 /* create an ansi copy of the string */
1523 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1524 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1527 if (!NT_SUCCESS(Status
))
1529 SetLastNtError(Status
);
1537 SetLastNtError(_SEH_GetExceptionCode());
1543 /* update the base class */
1544 IntFreeClassMenuName(Class
);
1545 Class
->MenuName
= strBufW
;
1546 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1547 Class
->MenuNameIsString
= TRUE
;
1549 /* update the clones */
1550 Class
= Class
->Clone
;
1551 while (Class
!= NULL
)
1553 Class
->MenuName
= strBufW
;
1554 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1555 Class
->MenuNameIsString
= TRUE
;
1557 Class
= Class
->Next
;
1562 DPRINT1("Failed to copy class menu name!\n");
1563 UserHeapFree(strBufW
);
1567 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1571 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1573 /* update the base class */
1574 IntFreeClassMenuName(Class
);
1575 Class
->MenuName
= MenuName
->Buffer
;
1576 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1577 Class
->MenuNameIsString
= FALSE
;
1579 /* update the clones */
1580 Class
= Class
->Clone
;
1581 while (Class
!= NULL
)
1583 Class
->MenuName
= MenuName
->Buffer
;
1584 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1585 Class
->MenuNameIsString
= FALSE
;
1587 Class
= Class
->Next
;
1597 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1599 IN ULONG_PTR NewLong
,
1604 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1606 /* change the information in the base class first, then update the clones */
1607 Class
= Class
->Base
;
1613 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1615 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1616 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1618 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1622 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1624 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1625 certain architectures, maybe using RtlCopyMemory is a
1626 better choice for those architectures! */
1630 /* update the clones */
1631 Class
= Class
->Clone
;
1632 while (Class
!= NULL
)
1634 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1635 Class
= Class
->Next
;
1643 case GCL_CBWNDEXTRA
:
1644 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1645 Class
->WndExtra
= (INT
)NewLong
;
1647 /* update the clones */
1648 Class
= Class
->Clone
;
1649 while (Class
!= NULL
)
1651 Class
->WndExtra
= (INT
)NewLong
;
1652 Class
= Class
->Next
;
1657 case GCL_CBCLSEXTRA
:
1658 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1661 case GCLP_HBRBACKGROUND
:
1662 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1663 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1665 /* update the clones */
1666 Class
= Class
->Clone
;
1667 while (Class
!= NULL
)
1669 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1670 Class
= Class
->Next
;
1675 /* FIXME - get handle from pointer to CURSOR object */
1676 Ret
= (ULONG_PTR
)Class
->hCursor
;
1677 Class
->hCursor
= (HANDLE
)NewLong
;
1679 /* update the clones */
1680 Class
= Class
->Clone
;
1681 while (Class
!= NULL
)
1683 Class
->hCursor
= (HANDLE
)NewLong
;
1684 Class
= Class
->Next
;
1689 /* FIXME - get handle from pointer to ICON object */
1690 Ret
= (ULONG_PTR
)Class
->hIcon
;
1691 Class
->hIcon
= (HANDLE
)NewLong
;
1693 /* update the clones */
1694 Class
= Class
->Clone
;
1695 while (Class
!= NULL
)
1697 Class
->hIcon
= (HANDLE
)NewLong
;
1698 Class
= Class
->Next
;
1703 /* FIXME - get handle from pointer to ICON object */
1704 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1705 Class
->hIconSm
= (HANDLE
)NewLong
;
1707 /* update the clones */
1708 Class
= Class
->Clone
;
1709 while (Class
!= NULL
)
1711 Class
->hIconSm
= (HANDLE
)NewLong
;
1712 Class
= Class
->Next
;
1717 Ret
= (ULONG_PTR
)Class
->hInstance
;
1718 Class
->hInstance
= (HINSTANCE
)NewLong
;
1720 /* update the clones */
1721 Class
= Class
->Clone
;
1722 while (Class
!= NULL
)
1724 Class
->hInstance
= (HINSTANCE
)NewLong
;
1725 Class
= Class
->Next
;
1731 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1733 if (!IntSetClassMenuName(Class
,
1736 DPRINT("Setting the class menu name failed!\n");
1739 /* FIXME - really return NULL? Wine does so... */
1744 Ret
= (ULONG_PTR
)Class
->Style
;
1745 Class
->Style
= (UINT
)NewLong
;
1747 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1748 move the class to the appropriate list? For now, we save
1749 the original value in Class->Global, so we can always
1750 locate the appropriate list */
1752 /* update the clones */
1753 Class
= Class
->Clone
;
1754 while (Class
!= NULL
)
1756 Class
->Style
= (UINT
)NewLong
;
1757 Class
= Class
->Next
;
1762 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1769 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1771 Ret
= (ULONG_PTR
)Class
->Atom
;
1772 if (!IntSetClassAtom(Class
,
1781 SetLastWin32Error(ERROR_INVALID_INDEX
);
1789 UserGetClassInfo(IN PWINDOWCLASS Class
,
1790 OUT PWNDCLASSEXW lpwcx
,
1792 HINSTANCE hInstance
)
1796 lpwcx
->style
= Class
->Style
;
1798 pi
= GetW32ProcessInfo();
1799 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1804 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1805 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1806 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1807 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1808 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1811 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1813 lpwcx
->lpszMenuName
= Class
->MenuName
;
1815 if (Class
->hInstance
== pi
->hModUser
)
1816 lpwcx
->hInstance
= NULL
;
1818 lpwcx
->hInstance
= Class
->hInstance
;
1820 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1822 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1827 /* SYSCALLS *****************************************************************/
1831 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1832 IN PUNICODE_STRING ClassName
,
1833 IN PUNICODE_STRING MenuName
,
1840 * Registers a new class with the window manager
1842 * lpwcx = Win32 extended window class structure
1843 * bUnicodeClass = Whether to send ANSI or unicode strings
1844 * to window procedures
1845 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1847 * Atom identifying the new class
1850 WNDCLASSEXW CapturedClassInfo
= {0};
1851 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1852 RTL_ATOM Ret
= (RTL_ATOM
)0;
1854 if (Flags
& ~REGISTERCLASS_ALL
)
1856 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1860 UserEnterExclusive();
1864 /* Probe the parameters and basic parameter checks */
1865 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1867 goto InvalidParameter
;
1871 sizeof(WNDCLASSEXW
),
1873 RtlCopyMemory(&CapturedClassInfo
,
1875 sizeof(WNDCLASSEXW
));
1877 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1878 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1880 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1881 CapturedClassInfo
.cbClsExtra
< 0 ||
1882 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1883 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1884 CapturedClassInfo
.cbWndExtra
< 0 ||
1885 CapturedClassInfo
.hInstance
== NULL
)
1887 goto InvalidParameter
;
1890 if (CapturedName
.Length
!= 0)
1892 ProbeForRead(CapturedName
.Buffer
,
1893 CapturedName
.Length
,
1898 if (!IS_ATOM(CapturedName
.Buffer
))
1900 goto InvalidParameter
;
1904 if (CapturedMenuName
.Length
!= 0)
1906 ProbeForRead(CapturedMenuName
.Buffer
,
1907 CapturedMenuName
.Length
,
1910 else if (CapturedMenuName
.Buffer
!= NULL
&&
1911 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1914 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1918 /* Register the class */
1919 Ret
= UserRegisterClass(&CapturedClassInfo
,
1922 hMenu
, /* FIXME - pass pointer */
1929 SetLastNtError(_SEH_GetExceptionCode());
1941 NtUserGetClassLong(IN HWND hWnd
,
1945 PWINDOW_OBJECT Window
;
1948 if (Offset
!= GCLP_WNDPROC
)
1954 UserEnterExclusive();
1957 Window
= UserGetWindowObject(hWnd
);
1960 Ret
= UserGetClassLongPtr(Window
->Class
,
1964 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Class
->MenuNameIsString
)
1966 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
1978 NtUserSetClassLong(HWND hWnd
,
1980 ULONG_PTR dwNewLong
,
1984 PWINDOW_OBJECT Window
;
1987 UserEnterExclusive();
1989 pi
= GetW32ProcessInfo();
1993 Window
= UserGetWindowObject(hWnd
);
1996 if (Window
->ti
->kpi
!= pi
)
1998 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2004 UNICODE_STRING Value
;
2006 /* probe the parameters */
2007 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2009 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2010 if (Value
.Length
& 1)
2012 goto InvalidParameter
;
2015 if (Value
.Length
!= 0)
2017 ProbeForRead(Value
.Buffer
,
2023 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2025 goto InvalidParameter
;
2027 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2030 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2035 dwNewLong
= (ULONG_PTR
)&Value
;
2038 Ret
= UserSetClassLongPtr(Window
->Class
,
2045 SetLastNtError(_SEH_GetExceptionCode());
2057 NtUserSetClassWord(DWORD Unknown0
,
2065 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2066 IN HINSTANCE hInstance
)
2068 UNICODE_STRING CapturedClassName
;
2071 UserEnterExclusive();
2075 /* probe the paramters */
2076 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2077 if (CapturedClassName
.Length
& 1)
2079 goto InvalidParameter
;
2082 if (CapturedClassName
.Length
!= 0)
2084 ProbeForRead(CapturedClassName
.Buffer
,
2085 CapturedClassName
.Length
,
2090 if (!IS_ATOM(CapturedClassName
.Buffer
))
2093 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2098 /* unregister the class */
2099 Ret
= UserUnregisterClass(&CapturedClassName
,
2104 SetLastNtError(_SEH_GetExceptionCode());
2113 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2116 HINSTANCE hInstance
,
2117 PUNICODE_STRING ClassName
,
2118 LPWNDCLASSEXW lpWndClassEx
,
2121 UNICODE_STRING CapturedClassName
;
2127 /* NOTE: need exclusive lock because getting the wndproc might require the
2128 creation of a call procedure handle */
2129 UserEnterExclusive();
2131 pi
= GetW32ProcessInfo();
2134 ERR("GetW32ProcessInfo() returned NULL!\n");
2139 /* probe the paramters */
2140 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2142 if (CapturedClassName
.Length
== 0)
2143 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2145 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2147 if (CapturedClassName
.Length
& 1)
2149 goto InvalidParameter
;
2152 if (CapturedClassName
.Length
!= 0)
2154 ProbeForRead(CapturedClassName
.Buffer
,
2155 CapturedClassName
.Length
,
2160 if (!IS_ATOM(CapturedClassName
.Buffer
))
2162 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2163 goto InvalidParameter
;
2167 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2170 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2174 ProbeForWrite(lpWndClassEx
,
2175 sizeof(WNDCLASSEXW
),
2178 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2183 if (ClassAtom
!= (RTL_ATOM
)0)
2185 if (hInstance
== NULL
)
2186 hInstance
= pi
->hModUser
;
2188 Ret
= UserGetClassInfo(Class
,
2195 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2196 /* FIXME - handle Class->Desktop == NULL!!!!! */
2198 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2200 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2201 (PVOID
)Class
->AnsiMenuName
:
2202 (PVOID
)Class
->MenuName
);
2205 /* Undocumented behavior! Return the class atom as a BOOL! */
2206 Ret
= (BOOL
)ClassAtom
;
2211 if (CapturedClassName
.Length
== 0)
2212 WARN("Tried to get information of a non-existing class atom 0x%p\n", CapturedClassName
.Buffer
);
2214 WARN("Tried to get information of a non-existing class \"%wZ\"\n", &CapturedClassName
);
2215 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2220 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2232 NtUserGetClassName (IN HWND hWnd
,
2233 OUT PUNICODE_STRING ClassName
,
2236 PWINDOW_OBJECT Window
;
2237 UNICODE_STRING CapturedClassName
;
2242 Window
= UserGetWindowObject(hWnd
);
2247 ProbeForWriteUnicodeString(ClassName
);
2248 CapturedClassName
= *ClassName
;
2250 /* get the class name */
2251 Ret
= UserGetClassName(Window
->Class
,
2257 /* update the Length field */
2258 ClassName
->Length
= CapturedClassName
.Length
;
2263 SetLastNtError(_SEH_GetExceptionCode());
2274 NtUserGetWOWClass(DWORD Unknown0
,