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.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Window classes
23 * FILE: subsys/win32k/ntuser/class.c
24 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
26 * 06-06-2001 CSH Created
28 /* INCLUDES ******************************************************************/
38 /* WINDOWCLASS ***************************************************************/
40 #define REGISTERCLASS_SYSTEM 0x4
43 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class
)
45 /* free the menu name, if it was changed and allocated */
46 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
48 UserHeapFree(Class
->MenuName
);
49 Class
->MenuName
= NULL
;
50 Class
->AnsiMenuName
= NULL
;
55 IntDestroyClass(IN OUT PWINDOWCLASS Class
)
57 /* there shouldn't be any clones anymore */
58 ASSERT(Class
->Windows
== 0);
59 ASSERT(Class
->Clone
== NULL
);
61 if (Class
->Base
== Class
)
63 PCALLPROC CallProc
, NextCallProc
;
65 /* Destroy allocated callproc handles */
66 CallProc
= Class
->CallProcList
;
67 while (CallProc
!= NULL
)
69 NextCallProc
= CallProc
->Next
;
71 CallProc
->Next
= NULL
;
75 CallProc
= NextCallProc
;
80 DceFreeClassDCE(((PDCE
)Class
->Dce
)->hDC
);
84 IntFreeClassMenuName(Class
);
87 /* free the structure */
88 if (Class
->Desktop
!= NULL
)
90 DesktopHeapFree(Class
->Desktop
,
100 /* clean all process classes. all process windows must cleaned first!! */
101 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
104 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
108 /* free all local classes */
109 Class
= pi
->LocalClassList
;
110 while (Class
!= NULL
)
112 pi
->LocalClassList
= Class
->Next
;
114 ASSERT(Class
->Base
== Class
);
115 IntDestroyClass(Class
);
117 Class
= pi
->LocalClassList
;
120 /* free all global classes */
121 Class
= pi
->GlobalClassList
;
122 while (Class
!= NULL
)
124 pi
->GlobalClassList
= Class
->Next
;
126 ASSERT(Class
->Base
== Class
);
127 IntDestroyClass(Class
);
129 Class
= pi
->GlobalClassList
;
132 /* free all system classes */
133 Class
= pi
->SystemClassList
;
134 while (Class
!= NULL
)
136 pi
->SystemClassList
= Class
->Next
;
138 ASSERT(Class
->Base
== Class
);
139 IntDestroyClass(Class
);
141 Class
= pi
->SystemClassList
;
147 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
154 if (ClassName
->Length
!= 0)
156 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
157 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
159 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
166 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
170 AtomName
= ClassName
->Buffer
;
172 Status
= RtlAddAtomToAtomTable(gAtomTable
,
176 if (!NT_SUCCESS(Status
))
178 SetLastNtError(Status
);
186 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
188 return RtlDeleteAtomFromAtomTable(gAtomTable
,
193 UserFindCallProc(IN PWINDOWCLASS Class
,
199 CallProc
= Class
->CallProcList
;
200 while (CallProc
!= NULL
)
202 if (CallProc
->WndProc
== WndProc
&&
203 CallProc
->Unicode
== (UINT
)bUnicode
)
208 CallProc
= CallProc
->Next
;
215 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class
,
216 IN PCALLPROC CallProc
)
218 PWINDOWCLASS BaseClass
;
220 ASSERT(CallProc
->Next
== NULL
);
222 BaseClass
= Class
->Base
;
223 ASSERT(CallProc
->Next
== NULL
);
224 CallProc
->Next
= BaseClass
->CallProcList
;
225 BaseClass
->CallProcList
= CallProc
;
227 /* Update all clones */
228 Class
= Class
->Clone
;
229 while (Class
!= NULL
)
231 Class
->CallProcList
= BaseClass
->CallProcList
;
237 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
238 IN PUNICODE_STRING ClassName
)
240 RTL_ATOM Atom
= (RTL_ATOM
)0;
242 /* update the base class first */
245 if (!IntRegisterClassAtom(ClassName
,
251 IntDeregisterClassAtom(Class
->Atom
);
255 /* update the clones */
256 Class
= Class
->Clone
;
257 while (Class
!= NULL
)
268 IntGetClassWndProc(IN PWINDOWCLASS Class
,
269 IN PW32PROCESSINFO pi
,
272 ASSERT(UserIsEnteredExclusive() == TRUE
);
276 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
280 if (!Ansi
== Class
->Unicode
)
282 return Class
->WndProc
;
286 PWINDOWCLASS BaseClass
;
288 /* make sure the call procedures are located on the desktop
289 of the base class! */
290 BaseClass
= Class
->Base
;
293 if (Class
->CallProc
!= NULL
)
295 return GetCallProcHandle(Class
->CallProc
);
299 PCALLPROC NewCallProc
;
304 NewCallProc
= UserFindCallProc(Class
,
307 if (NewCallProc
== NULL
)
309 NewCallProc
= CreateCallProc(NULL
,
313 if (NewCallProc
== NULL
)
315 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
319 UserAddCallProcToClass(Class
,
323 Class
->CallProc
= NewCallProc
;
325 /* update the clones */
326 Class
= Class
->Clone
;
327 while (Class
!= NULL
)
329 Class
->CallProc
= NewCallProc
;
334 return GetCallProcHandle(NewCallProc
);
341 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
349 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
350 SetLastWin32Error(ERROR_ACCESS_DENIED
);
354 /* update the base class first */
357 /* resolve any callproc handle if possible */
358 if (IsCallProcHandle(WndProc
))
362 if (UserGetCallProcInfo((HANDLE
)WndProc
,
365 WndProc
= wpInfo
.WindowProc
;
366 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
370 Ret
= IntGetClassWndProc(Class
,
378 /* update the class info */
379 Class
->Unicode
= !Ansi
;
380 Class
->WndProc
= WndProc
;
382 /* update the clones */
383 Class
= Class
->Clone
;
384 while (Class
!= NULL
)
386 Class
->Unicode
= !Ansi
;
387 Class
->WndProc
= WndProc
;
396 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
397 IN OUT PWINDOWCLASS
*ClassLink
,
403 ASSERT(Desktop
!= NULL
);
404 ASSERT(BaseClass
->Base
== BaseClass
);
406 if (BaseClass
->Desktop
== Desktop
)
408 /* it is most likely that a window is created on the same
409 desktop as the window class. */
414 if (BaseClass
->Desktop
== NULL
)
416 ASSERT(BaseClass
->Windows
== 0);
417 ASSERT(BaseClass
->Clone
== NULL
);
419 /* Classes are also located in the shared heap when the class
420 was created before the thread attached to a desktop. As soon
421 as a window is created for such a class located on the shared
422 heap, the class is cloned into the desktop heap on which the
423 window is created. */
428 /* The user is asking for a class object on a different desktop,
430 Class
= BaseClass
->Clone
;
431 while (Class
!= NULL
)
433 if (Class
->Desktop
== Desktop
)
435 ASSERT(Class
->Base
== BaseClass
);
436 ASSERT(Class
->Clone
== NULL
);
446 /* The window is created on a different desktop, we need to
447 clone the class object to the desktop heap of the window! */
448 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
450 Class
= DesktopHeapAlloc(Desktop
,
454 /* simply clone the class */
459 /* update some pointers and link the class */
460 Class
->Desktop
= Desktop
;
463 if (BaseClass
->Desktop
== NULL
)
465 /* we don't really need the base class on the shared
466 heap anymore, delete it so the only class left is
467 the clone we just created, which now serves as the
469 ASSERT(BaseClass
->Clone
== NULL
);
470 ASSERT(Class
->Clone
== NULL
);
472 Class
->Next
= BaseClass
->Next
;
474 /* replace the base class */
475 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
478 /* destroy the obsolete copy on the shared heap */
479 BaseClass
->Base
= NULL
;
480 BaseClass
->Clone
= NULL
;
481 IntDestroyClass(BaseClass
);
485 /* link in the clone */
487 Class
->Base
= BaseClass
;
488 Class
->Next
= BaseClass
->Clone
;
489 (void)InterlockedExchangePointer((VOID
*)&BaseClass
->Clone
,
495 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
503 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
504 IN OUT PWINDOWCLASS
*ClassLink
,
509 ASSERT(BaseClass
->Base
== BaseClass
);
511 Class
= IntGetClassForDesktop(BaseClass
,
523 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
524 IN OUT PWINDOWCLASS
*BaseClassLink
,
525 IN OUT PWINDOWCLASS
*CloneLink
)
527 PWINDOWCLASS Clone
, BaseClass
;
529 ASSERT(Class
->Base
!= Class
);
530 ASSERT(Class
->Base
->Clone
!= NULL
);
531 ASSERT(Class
->Desktop
!= NULL
);
532 ASSERT(Class
->Windows
!= 0);
533 ASSERT(Class
->Base
->Desktop
!= NULL
);
534 ASSERT(Class
->Base
->Windows
== 0);
536 /* unlink the clone */
537 *CloneLink
= Class
->Next
;
538 Class
->Clone
= Class
->Base
->Clone
;
540 BaseClass
= Class
->Base
;
542 /* update the class information to make it a base class */
544 Class
->Next
= (*BaseClassLink
)->Next
;
546 /* update all clones */
547 Clone
= Class
->Clone
;
548 while (Clone
!= NULL
)
550 ASSERT(Clone
->Clone
== NULL
);
554 Clone
->CallProc
= Class
->CallProc
;
559 /* link in the new base class */
560 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
565 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
567 IN PW32PROCESSINFO pi
)
569 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
571 BaseClass
= Class
->Base
;
573 if (--Class
->Windows
== 0)
575 if (BaseClass
== Class
)
577 ASSERT(Class
->Base
== Class
);
579 /* check if there are clones of the class on other desktops,
580 link the first clone in if possible. If there are no clones
581 then leave the class on the desktop heap. It will get moved
582 to the shared heap when the thread detaches. */
583 if (BaseClass
->Clone
!= NULL
)
585 if (BaseClass
->System
)
586 PrevLink
= &pi
->SystemClassList
;
587 else if (BaseClass
->Global
)
588 PrevLink
= &pi
->GlobalClassList
;
590 PrevLink
= &pi
->LocalClassList
;
592 CurrentClass
= *PrevLink
;
593 while (CurrentClass
!= BaseClass
)
595 ASSERT(CurrentClass
!= NULL
);
597 PrevLink
= &CurrentClass
->Next
;
598 CurrentClass
= CurrentClass
->Next
;
601 ASSERT(*PrevLink
== BaseClass
);
603 /* make the first clone become the new base class */
604 IntMakeCloneBaseClass(BaseClass
->Clone
,
608 /* destroy the class, there's still another clone of the class
609 that now serves as a base class. Make sure we don't destruct
610 resources shared by all classes (Base = NULL)! */
611 BaseClass
->Base
= NULL
;
612 BaseClass
->Clone
= NULL
;
613 IntDestroyClass(BaseClass
);
618 /* locate the cloned class and unlink it */
619 PrevLink
= &BaseClass
->Clone
;
620 CurrentClass
= BaseClass
->Clone
;
621 while (CurrentClass
!= Class
)
623 ASSERT(CurrentClass
!= NULL
);
625 PrevLink
= &CurrentClass
->Next
;
626 CurrentClass
= CurrentClass
->Next
;
629 ASSERT(CurrentClass
== Class
);
631 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
634 ASSERT(Class
->Base
== BaseClass
);
635 ASSERT(Class
->Clone
== NULL
);
637 /* the class was just a clone, we don't need it anymore */
638 IntDestroyClass(Class
);
644 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
645 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
647 PWINDOWCLASS NewClass
;
650 ASSERT(Class
->Base
== Class
);
651 ASSERT(Class
->Desktop
!= NULL
);
652 ASSERT(Class
->Windows
== 0);
653 ASSERT(Class
->Clone
== NULL
);
655 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
657 /* allocate the new base class on the shared heap */
658 NewClass
= UserHeapAlloc(ClassSize
);
659 if (NewClass
!= NULL
)
661 RtlCopyMemory(NewClass
,
665 NewClass
->Desktop
= NULL
;
666 NewClass
->Base
= NewClass
;
668 /* replace the class in the list */
669 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
671 *ClassLinkPtr
= &NewClass
->Next
;
673 /* free the obsolete class on the desktop heap */
675 IntDestroyClass(Class
);
683 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
684 IN OUT PWINDOWCLASS
*ClassList
,
685 IN BOOL FreeOnFailure
,
688 PWINDOWCLASS Class
, NextClass
, *Link
;
690 /* NOTE: We only need to check base classes! When classes are no longer needed
691 on a desktop, the clones will be freed automatically as soon as possible.
692 However, we need to move base classes to the shared heap, as soon as
693 the last desktop heap where a class is allocated on is about to be destroyed.
694 If we didn't move the class to the shared heap, the class would become
697 ASSERT(Desktop
!= NULL
);
701 while (Class
!= NULL
)
703 NextClass
= Class
->Next
;
705 ASSERT(Class
->Base
== Class
);
707 if (Class
->Desktop
== Desktop
&&
710 /* there shouldn't be any clones around anymore! */
711 ASSERT(Class
->Clone
== NULL
);
713 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
714 /* FIXME - We could move the class to another desktop heap if there's still desktops
715 mapped into the process... */
717 /* move the class to the shared heap */
718 if (IntMoveClassToSharedHeap(Class
,
721 ASSERT(*Link
== NextClass
);
725 ASSERT(NextClass
== Class
->Next
);
729 /* unlink the base class */
730 (void)InterlockedExchangePointer((PVOID
*)Link
,
733 /* we can free the old base class now */
735 IntDestroyClass(Class
);
752 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
753 IN BOOL FreeOnFailure
)
758 pi
= GetW32ProcessInfo();
762 /* check all local classes */
763 IntCheckDesktopClasses(Desktop
,
768 /* check all global classes */
769 IntCheckDesktopClasses(Desktop
,
770 &pi
->GlobalClassList
,
774 /* check all system classes */
775 IntCheckDesktopClasses(Desktop
,
776 &pi
->SystemClassList
,
782 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
783 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
790 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
791 IN PUNICODE_STRING ClassName
,
792 IN PUNICODE_STRING MenuName
,
796 IN PW32PROCESSINFO pi
)
799 PWINDOWCLASS Class
= NULL
;
801 PWSTR pszMenuName
= NULL
;
802 NTSTATUS Status
= STATUS_SUCCESS
;
804 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
805 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
807 if (!IntRegisterClassAtom(ClassName
,
810 DPRINT1("Failed to register class atom!\n");
814 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
815 if (MenuName
->Length
!= 0)
817 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
818 RtlUnicodeStringToAnsiSize(MenuName
));
819 if (pszMenuName
== NULL
)
825 Class
= DesktopHeapAlloc(Desktop
,
830 /* FIXME - the class was created before being connected
831 to a desktop. It is possible for the desktop window,
832 but should it be allowed for any other case? */
833 Class
= UserHeapAlloc(ClassSize
);
841 Class
->Desktop
= Desktop
;
845 if (dwFlags
& REGISTERCLASS_SYSTEM
)
847 dwFlags
&= ~REGISTERCLASS_ANSI
;
848 Class
->WndProcExtra
= wpExtra
;
849 Class
->System
= TRUE
;
854 PWSTR pszMenuNameBuffer
= pszMenuName
;
856 /* need to protect with SEH since accessing the WNDCLASSEX structure
857 and string buffers might raise an exception! We don't want to
859 Class
->WndProc
= lpwcx
->lpfnWndProc
;
860 Class
->Style
= lpwcx
->style
;
861 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
862 Class
->WndExtra
= lpwcx
->cbWndExtra
;
863 Class
->hInstance
= lpwcx
->hInstance
;
864 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
865 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
866 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
867 Class
->hbrBackground
= lpwcx
->hbrBackground
;
869 /* make a copy of the string */
870 if (pszMenuNameBuffer
!= NULL
)
872 Class
->MenuNameIsString
= TRUE
;
874 Class
->MenuName
= pszMenuNameBuffer
;
875 RtlCopyMemory(Class
->MenuName
,
878 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
880 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
883 Class
->MenuName
= MenuName
->Buffer
;
885 /* save an ansi copy of the string */
886 if (pszMenuNameBuffer
!= NULL
)
888 ANSI_STRING AnsiString
;
890 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
891 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
892 AnsiString
.Buffer
= Class
->AnsiMenuName
;
893 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
896 if (!NT_SUCCESS(Status
))
898 DPRINT1("Failed to convert unicode menu name to ansi!\n");
900 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
905 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
907 if (!(dwFlags
& REGISTERCLASS_ANSI
))
908 Class
->Unicode
= TRUE
;
910 if (Class
->Style
& CS_GLOBALCLASS
)
911 Class
->Global
= TRUE
;
915 Status
= _SEH_GetExceptionCode();
919 if (!NT_SUCCESS(Status
))
921 DPRINT1("Failed creating the class: 0x%x\n", Status
);
923 SetLastNtError(Status
);
925 if (pszMenuName
!= NULL
)
926 UserHeapFree(pszMenuName
);
928 DesktopHeapFree(Desktop
,
932 IntDeregisterClassAtom(Atom
);
938 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
940 if (pszMenuName
!= NULL
)
941 UserHeapFree(pszMenuName
);
943 IntDeregisterClassAtom(Atom
);
945 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
952 IntFindClass(IN RTL_ATOM Atom
,
953 IN HINSTANCE hInstance
,
954 IN PWINDOWCLASS
*ClassList
,
955 OUT PWINDOWCLASS
**Link OPTIONAL
)
957 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
960 while (Class
!= NULL
)
962 if (Class
->Atom
== Atom
&&
963 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
966 ASSERT(Class
->Base
== Class
);
973 PrevLink
= &Class
->Next
;
981 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
986 if (ClassName
->Length
!= 0)
992 /* NOTE: Caller has to protect the call with SEH! */
994 if (ClassName
->Length
!= 0)
996 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
997 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
999 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1003 /* We need to make a local copy of the class name! The caller could
1004 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1005 We're protected by SEH, but the ranges that might be accessed were
1007 RtlCopyMemory(szBuf
,
1010 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1014 AtomName
= ClassName
->Buffer
;
1016 /* lookup the atom */
1017 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1020 if (NT_SUCCESS(Status
))
1026 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1028 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1032 SetLastNtError(Status
);
1038 ASSERT(IS_ATOM(ClassName
->Buffer
));
1039 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1047 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1048 IN HINSTANCE hInstance OPTIONAL
,
1049 IN PW32PROCESSINFO pi OPTIONAL
,
1050 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1051 OUT PWINDOWCLASS
**Link OPTIONAL
)
1053 RTL_ATOM Atom
= (RTL_ATOM
)0;
1055 ASSERT(BaseClass
!= NULL
);
1057 if (IntGetAtomFromStringOrAtom(ClassName
,
1059 Atom
!= (RTL_ATOM
)0)
1063 /* attempt to locate the class object */
1067 /* Step 1: try to find an exact match of locally registered classes */
1068 Class
= IntFindClass(Atom
,
1070 &pi
->LocalClassList
,
1077 /* Step 2: try to find any globally registered class. The hInstance
1078 is not relevant for global classes */
1079 Class
= IntFindClass(Atom
,
1081 &pi
->GlobalClassList
,
1088 /* Step 3: try to find any local class registered by user32 */
1089 Class
= IntFindClass(Atom
,
1091 &pi
->LocalClassList
,
1098 /* Step 4: try to find any global class registered by user32 */
1099 Class
= IntFindClass(Atom
,
1101 &pi
->GlobalClassList
,
1108 /* Step 5: try to find a system class */
1109 Class
= IntFindClass(Atom
,
1111 &pi
->SystemClassList
,
1115 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1127 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1128 IN PUNICODE_STRING ClassName
,
1129 IN PUNICODE_STRING MenuName
,
1130 IN HANDLE hMenu
, /* FIXME */
1138 RTL_ATOM Ret
= (RTL_ATOM
)0;
1140 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1142 ti
= GetW32ThreadInfo();
1143 if (ti
== NULL
|| !ti
->kpi
->RegisteredSysClasses
)
1145 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1151 /* try to find a previously registered class */
1152 ClassAtom
= IntGetClassAtom(ClassName
,
1157 if (ClassAtom
!= (RTL_ATOM
)0)
1159 if (lpwcx
->style
& CS_GLOBALCLASS
)
1161 // global classes shall not have same names as system classes
1162 if (Class
->Global
|| Class
->System
)
1164 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1165 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1169 else if ( !Class
->Global
&& !Class
->System
)
1171 // local class already exists
1172 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1173 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1178 Class
= IntCreateClass(lpwcx
,
1190 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1191 Class
->hMenu
= hMenu
;
1193 /* Register the class */
1195 List
= &pi
->SystemClassList
;
1196 else if (Class
->Global
)
1197 List
= &pi
->GlobalClassList
;
1199 List
= &pi
->LocalClassList
;
1201 Class
->Next
= *List
;
1202 (void)InterlockedExchangePointer((PVOID
*)List
,
1212 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1213 IN HINSTANCE hInstance
)
1220 pi
= GetW32ProcessInfo();
1223 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1227 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1229 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1230 ClassAtom
= IntGetClassAtom(ClassName
,
1235 if (ClassAtom
== (RTL_ATOM
)0)
1240 ASSERT(Class
!= NULL
);
1242 if (Class
->Windows
!= 0 ||
1243 Class
->Clone
!= NULL
)
1245 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1249 /* must be a base class! */
1250 ASSERT(Class
->Base
== Class
);
1252 /* unlink the class */
1253 *Link
= Class
->Next
;
1255 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1257 /* finally free the resources */
1258 IntDestroyClass(Class
);
1265 UserGetClassName(IN PWINDOWCLASS Class
,
1266 IN OUT PUNICODE_STRING ClassName
,
1269 NTSTATUS Status
= STATUS_SUCCESS
;
1270 WCHAR szStaticTemp
[32];
1271 PWSTR szTemp
= NULL
;
1272 ULONG BufLen
= sizeof(szStaticTemp
);
1275 /* Note: Accessing the buffer in ClassName may raise an exception! */
1281 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1282 UNICODE_STRING UnicodeClassName
;
1284 /* limit the size of the static buffer on the stack to the
1285 size of the buffer provided by the caller */
1286 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1288 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1291 /* find out how big the buffer needs to be */
1292 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1298 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1300 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1302 /* the buffer required exceeds the ansi buffer provided,
1303 pretend like we're using the ansi buffer and limit the
1304 size to the buffer size provided */
1305 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1308 /* allocate a temporary buffer that can hold the unicode class name */
1309 szTemp
= ExAllocatePool(PagedPool
,
1313 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1317 /* query the class name */
1318 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1326 szTemp
= szStaticTemp
;
1328 if (NT_SUCCESS(Status
))
1330 /* convert the atom name to ansi */
1332 RtlInitUnicodeString(&UnicodeClassName
,
1335 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1338 if (!NT_SUCCESS(Status
))
1340 SetLastNtError(Status
);
1345 Ret
= BufLen
/ sizeof(WCHAR
);
1349 BufLen
= ClassName
->MaximumLength
;
1351 /* query the atom name */
1352 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1359 if (!NT_SUCCESS(Status
))
1361 SetLastNtError(Status
);
1365 Ret
= BufLen
/ sizeof(WCHAR
);
1370 SetLastNtError(_SEH_GetExceptionCode());
1374 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1383 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1393 TRACE("GetClassLong(%d)\n", Index
);
1394 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1395 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1397 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1401 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1403 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1404 certain architectures, maybe using RtlCopyMemory is a
1405 better choice for those architectures! */
1407 TRACE("Result: %x\n", Ret
);
1413 case GCL_CBWNDEXTRA
:
1414 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1417 case GCL_CBCLSEXTRA
:
1418 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1421 case GCLP_HBRBACKGROUND
:
1422 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1426 /* FIXME - get handle from pointer to CURSOR object */
1427 Ret
= (ULONG_PTR
)Class
->hCursor
;
1431 /* FIXME - get handle from pointer to ICON object */
1432 Ret
= (ULONG_PTR
)Class
->hIcon
;
1436 /* FIXME - get handle from pointer to ICON object */
1437 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1441 Ret
= (ULONG_PTR
)Class
->hInstance
;
1445 /* NOTE: Returns pointer in kernel heap! */
1447 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1449 Ret
= (ULONG_PTR
)Class
->MenuName
;
1453 Ret
= (ULONG_PTR
)Class
->Style
;
1457 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1458 GetW32ProcessInfo(),
1463 Ret
= (ULONG_PTR
)Class
->Atom
;
1467 SetLastWin32Error(ERROR_INVALID_INDEX
);
1475 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1476 IN PUNICODE_STRING MenuName
)
1480 /* change the base class first */
1481 Class
= Class
->Base
;
1483 if (MenuName
->Length
!= 0)
1485 ANSI_STRING AnsiString
;
1488 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1490 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1491 AnsiString
.MaximumLength
);
1492 if (strBufW
!= NULL
)
1498 /* copy the unicode string */
1499 RtlCopyMemory(strBufW
,
1502 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1504 /* create an ansi copy of the string */
1505 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1506 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1509 if (!NT_SUCCESS(Status
))
1511 SetLastNtError(Status
);
1519 SetLastNtError(_SEH_GetExceptionCode());
1525 /* update the base class */
1526 IntFreeClassMenuName(Class
);
1527 Class
->MenuName
= strBufW
;
1528 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1529 Class
->MenuNameIsString
= TRUE
;
1531 /* update the clones */
1532 Class
= Class
->Clone
;
1533 while (Class
!= NULL
)
1535 Class
->MenuName
= strBufW
;
1536 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1537 Class
->MenuNameIsString
= TRUE
;
1539 Class
= Class
->Next
;
1544 DPRINT1("Failed to copy class menu name!\n");
1545 UserHeapFree(strBufW
);
1549 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1553 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1555 /* update the base class */
1556 IntFreeClassMenuName(Class
);
1557 Class
->MenuName
= MenuName
->Buffer
;
1558 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1559 Class
->MenuNameIsString
= FALSE
;
1561 /* update the clones */
1562 Class
= Class
->Clone
;
1563 while (Class
!= NULL
)
1565 Class
->MenuName
= MenuName
->Buffer
;
1566 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1567 Class
->MenuNameIsString
= FALSE
;
1569 Class
= Class
->Next
;
1579 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1581 IN ULONG_PTR NewLong
,
1586 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1588 /* change the information in the base class first, then update the clones */
1589 Class
= Class
->Base
;
1595 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1597 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1598 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1600 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1604 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1606 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1607 certain architectures, maybe using RtlCopyMemory is a
1608 better choice for those architectures! */
1612 /* update the clones */
1613 Class
= Class
->Clone
;
1614 while (Class
!= NULL
)
1616 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1617 Class
= Class
->Next
;
1625 case GCL_CBWNDEXTRA
:
1626 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1627 Class
->WndExtra
= (INT
)NewLong
;
1629 /* update the clones */
1630 Class
= Class
->Clone
;
1631 while (Class
!= NULL
)
1633 Class
->WndExtra
= (INT
)NewLong
;
1634 Class
= Class
->Next
;
1639 case GCL_CBCLSEXTRA
:
1640 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1643 case GCLP_HBRBACKGROUND
:
1644 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1645 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1647 /* update the clones */
1648 Class
= Class
->Clone
;
1649 while (Class
!= NULL
)
1651 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1652 Class
= Class
->Next
;
1657 /* FIXME - get handle from pointer to CURSOR object */
1658 Ret
= (ULONG_PTR
)Class
->hCursor
;
1659 Class
->hCursor
= (HANDLE
)NewLong
;
1661 /* update the clones */
1662 Class
= Class
->Clone
;
1663 while (Class
!= NULL
)
1665 Class
->hCursor
= (HANDLE
)NewLong
;
1666 Class
= Class
->Next
;
1671 /* FIXME - get handle from pointer to ICON object */
1672 Ret
= (ULONG_PTR
)Class
->hIcon
;
1673 Class
->hIcon
= (HANDLE
)NewLong
;
1675 /* update the clones */
1676 Class
= Class
->Clone
;
1677 while (Class
!= NULL
)
1679 Class
->hIcon
= (HANDLE
)NewLong
;
1680 Class
= Class
->Next
;
1685 /* FIXME - get handle from pointer to ICON object */
1686 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1687 Class
->hIconSm
= (HANDLE
)NewLong
;
1689 /* update the clones */
1690 Class
= Class
->Clone
;
1691 while (Class
!= NULL
)
1693 Class
->hIconSm
= (HANDLE
)NewLong
;
1694 Class
= Class
->Next
;
1699 Ret
= (ULONG_PTR
)Class
->hInstance
;
1700 Class
->hInstance
= (HINSTANCE
)NewLong
;
1702 /* update the clones */
1703 Class
= Class
->Clone
;
1704 while (Class
!= NULL
)
1706 Class
->hInstance
= (HINSTANCE
)NewLong
;
1707 Class
= Class
->Next
;
1713 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1715 if (!IntSetClassMenuName(Class
,
1718 DPRINT("Setting the class menu name failed!\n");
1721 /* FIXME - really return NULL? Wine does so... */
1726 Ret
= (ULONG_PTR
)Class
->Style
;
1727 Class
->Style
= (UINT
)NewLong
;
1729 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1730 move the class to the appropriate list? For now, we save
1731 the original value in Class->Global, so we can always
1732 locate the appropriate list */
1734 /* update the clones */
1735 Class
= Class
->Clone
;
1736 while (Class
!= NULL
)
1738 Class
->Style
= (UINT
)NewLong
;
1739 Class
= Class
->Next
;
1744 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1751 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1753 Ret
= (ULONG_PTR
)Class
->Atom
;
1754 if (!IntSetClassAtom(Class
,
1763 SetLastWin32Error(ERROR_INVALID_INDEX
);
1771 UserGetClassInfo(IN PWINDOWCLASS Class
,
1772 OUT PWNDCLASSEXW lpwcx
,
1774 HINSTANCE hInstance
)
1778 lpwcx
->style
= Class
->Style
;
1780 pi
= GetW32ProcessInfo();
1781 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1785 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1786 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1787 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1788 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1789 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1792 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1794 lpwcx
->lpszMenuName
= Class
->MenuName
;
1796 if (Class
->hInstance
== pi
->hModUser
)
1797 lpwcx
->hInstance
= NULL
;
1799 lpwcx
->hInstance
= Class
->hInstance
;
1801 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1803 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1809 UserRegisterSystemClasses(IN ULONG Count
,
1810 IN PREGISTER_SYSCLASS SystemClasses
)
1812 /* NOTE: This routine may raise exceptions! */
1814 UNICODE_STRING ClassName
, MenuName
;
1815 PW32PROCESSINFO pi
= GetW32ProcessInfo();
1820 if (pi
->RegisteredSysClasses
|| pi
->hModUser
== NULL
)
1823 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1825 for (i
= 0; i
!= Count
; i
++)
1827 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1828 if (ClassName
.Length
!= 0)
1830 ProbeForRead(ClassName
.Buffer
,
1835 wc
.cbSize
= sizeof(wc
);
1836 wc
.style
= SystemClasses
[i
].Style
;
1837 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1839 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1840 wc
.hInstance
= pi
->hModUser
;
1842 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1843 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1844 wc
.lpszMenuName
= NULL
;
1845 wc
.lpszClassName
= ClassName
.Buffer
;
1848 Class
= IntCreateClass(&wc
,
1851 SystemClasses
[i
].ProcA
,
1852 REGISTERCLASS_SYSTEM
,
1857 Class
->fnID
= SystemClasses
[i
].ClassId
;
1859 ASSERT(Class
->System
);
1860 Class
->Next
= pi
->SystemClassList
;
1861 (void)InterlockedExchangePointer((PVOID
*)&pi
->SystemClassList
,
1866 WARN("!!! Registering system class failed!\n");
1872 pi
->RegisteredSysClasses
= TRUE
;
1876 /* SYSCALLS *****************************************************************/
1880 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1881 IN PUNICODE_STRING ClassName
,
1882 IN PUNICODE_STRING MenuName
,
1889 * Registers a new class with the window manager
1891 * lpwcx = Win32 extended window class structure
1892 * bUnicodeClass = Whether to send ANSI or unicode strings
1893 * to window procedures
1894 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1896 * Atom identifying the new class
1899 WNDCLASSEXW CapturedClassInfo
= {0};
1900 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1901 RTL_ATOM Ret
= (RTL_ATOM
)0;
1903 if (Flags
& ~REGISTERCLASS_ALL
)
1905 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1909 UserEnterExclusive();
1913 /* Probe the parameters and basic parameter checks */
1914 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1916 goto InvalidParameter
;
1920 sizeof(WNDCLASSEXW
),
1922 RtlCopyMemory(&CapturedClassInfo
,
1924 sizeof(WNDCLASSEXW
));
1926 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1927 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1929 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1930 CapturedClassInfo
.cbClsExtra
< 0 ||
1931 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1932 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1933 CapturedClassInfo
.cbWndExtra
< 0 ||
1934 CapturedClassInfo
.hInstance
== NULL
)
1936 goto InvalidParameter
;
1939 if (CapturedName
.Length
!= 0)
1941 ProbeForRead(CapturedName
.Buffer
,
1942 CapturedName
.Length
,
1947 if (!IS_ATOM(CapturedName
.Buffer
))
1949 goto InvalidParameter
;
1953 if (CapturedMenuName
.Length
!= 0)
1955 ProbeForRead(CapturedMenuName
.Buffer
,
1956 CapturedMenuName
.Length
,
1959 else if (CapturedMenuName
.Buffer
!= NULL
&&
1960 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1963 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1967 /* Register the class */
1968 Ret
= UserRegisterClass(&CapturedClassInfo
,
1971 hMenu
, /* FIXME - pass pointer */
1978 SetLastNtError(_SEH_GetExceptionCode());
1990 NtUserRegisterClassExWOW(
1992 PUNICODE_STRING ClassName
,
1993 PUNICODE_STRING ClsNVersion
,
1994 PCLSMENUNAME pClassMenuName
,
1999 WNDCLASSEXW CapturedClassInfo
= {0};
2000 UNICODE_STRING CapturedName
= {0}, ClassnametoVersion
= {0};
2001 RTL_ATOM Ret
= (RTL_ATOM
)0;
2003 UserEnterExclusive();
2007 /* Probe the parameters and basic parameter checks */
2008 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2010 goto InvalidParameter
;
2012 if (!pClassMenuName
)
2014 goto InvalidParameter
;
2018 sizeof(WNDCLASSEXW
),
2020 RtlCopyMemory(&CapturedClassInfo
,
2022 sizeof(WNDCLASSEXW
));
2024 Need to watch this. When UnregisterClass is called these pointers
2025 are freed by the caller in user space. So, we just probe the data
2026 for now and pass it on and copy it to the shared class structure.
2028 ProbeForRead(pClassMenuName
,
2029 sizeof(CLSMENUNAME
),
2032 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2033 ClassnametoVersion
= ProbeForReadUnicodeString(ClsNVersion
);
2035 if (CapturedName
.Length
& 1 || ClassnametoVersion
.Length
& 1 ||
2036 CapturedClassInfo
.cbClsExtra
< 0 ||
2037 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2038 ClassnametoVersion
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
2039 CapturedClassInfo
.cbWndExtra
< 0 ||
2040 CapturedClassInfo
.hInstance
== NULL
)
2042 goto InvalidParameter
;
2045 if (CapturedName
.Length
!= 0)
2047 ProbeForRead(CapturedName
.Buffer
,
2048 CapturedName
.Length
,
2053 if (!IS_ATOM(CapturedName
.Buffer
))
2055 goto InvalidParameter
;
2059 if (ClassnametoVersion
.Length
!= 0)
2061 ProbeForRead(ClassnametoVersion
.Buffer
,
2062 ClassnametoVersion
.Length
,
2065 else if (ClassnametoVersion
.Buffer
!= NULL
&&
2066 !IS_INTRESOURCE(ClassnametoVersion
.Buffer
))
2069 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2073 /* Register the class */
2074 // Ret = UserRegisterClass(&CapturedClassInfo,
2076 // &ClassnametoVersion,
2077 // hMenu, /* FIXME - pass pointer */
2084 SetLastNtError(_SEH_GetExceptionCode());
2095 NtUserGetClassLong(IN HWND hWnd
,
2099 PWINDOW_OBJECT Window
;
2102 if (Offset
!= GCLP_WNDPROC
)
2108 UserEnterExclusive();
2111 Window
= UserGetWindowObject(hWnd
);
2114 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
2118 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
2120 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2132 NtUserSetClassLong(HWND hWnd
,
2134 ULONG_PTR dwNewLong
,
2138 PWINDOW_OBJECT Window
;
2141 UserEnterExclusive();
2143 pi
= GetW32ProcessInfo();
2147 Window
= UserGetWindowObject(hWnd
);
2150 if (Window
->ti
->kpi
!= pi
)
2152 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2158 UNICODE_STRING Value
;
2160 /* probe the parameters */
2161 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2163 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2164 if (Value
.Length
& 1)
2166 goto InvalidParameter
;
2169 if (Value
.Length
!= 0)
2171 ProbeForRead(Value
.Buffer
,
2177 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2179 goto InvalidParameter
;
2181 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2184 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2189 dwNewLong
= (ULONG_PTR
)&Value
;
2192 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2199 SetLastNtError(_SEH_GetExceptionCode());
2221 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2222 IN HINSTANCE hInstance
,
2223 OUT PCLSMENUNAME pClassMenuName
)
2225 UNICODE_STRING CapturedClassName
;
2228 UserEnterExclusive();
2232 /* probe the paramters */
2233 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2234 if (CapturedClassName
.Length
& 1)
2236 goto InvalidParameter
;
2239 if (CapturedClassName
.Length
!= 0)
2241 ProbeForRead(CapturedClassName
.Buffer
,
2242 CapturedClassName
.Length
,
2247 if (!IS_ATOM(CapturedClassName
.Buffer
))
2250 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2255 /* unregister the class */
2256 Ret
= UserUnregisterClass(&CapturedClassName
,
2261 SetLastNtError(_SEH_GetExceptionCode());
2270 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2273 HINSTANCE hInstance
,
2274 PUNICODE_STRING ClassName
,
2275 LPWNDCLASSEXW lpWndClassEx
,
2276 LPWSTR
*ppszMenuName
,
2279 UNICODE_STRING CapturedClassName
;
2285 /* NOTE: need exclusive lock because getting the wndproc might require the
2286 creation of a call procedure handle */
2287 UserEnterExclusive();
2289 pi
= GetW32ProcessInfo();
2292 ERR("GetW32ProcessInfo() returned NULL!\n");
2297 /* probe the paramters */
2298 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2300 if (CapturedClassName
.Length
== 0)
2301 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2303 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2305 if (CapturedClassName
.Length
& 1)
2307 goto InvalidParameter
;
2310 if (CapturedClassName
.Length
!= 0)
2312 ProbeForRead(CapturedClassName
.Buffer
,
2313 CapturedClassName
.Length
,
2318 if (!IS_ATOM(CapturedClassName
.Buffer
))
2320 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2321 goto InvalidParameter
;
2325 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2328 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2332 ProbeForWrite(lpWndClassEx
,
2333 sizeof(WNDCLASSEXW
),
2336 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2341 if (ClassAtom
!= (RTL_ATOM
)0)
2343 if (hInstance
== NULL
)
2344 hInstance
= pi
->hModUser
;
2346 Ret
= UserGetClassInfo(Class
,
2353 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2354 /* FIXME - handle Class->Desktop == NULL!!!!! */
2356 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2358 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2359 (PVOID
)Class
->AnsiMenuName
:
2360 (PVOID
)Class
->MenuName
);
2363 /* Undocumented behavior! Return the class atom as a BOOL! */
2364 Ret
= (BOOL
)ClassAtom
;
2368 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2372 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2384 NtUserGetClassName (IN HWND hWnd
,
2385 OUT PUNICODE_STRING ClassName
,
2388 PWINDOW_OBJECT Window
;
2389 UNICODE_STRING CapturedClassName
;
2394 Window
= UserGetWindowObject(hWnd
);
2399 ProbeForWriteUnicodeString(ClassName
);
2400 CapturedClassName
= *ClassName
;
2402 /* get the class name */
2403 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2409 /* update the Length field */
2410 ClassName
->Length
= CapturedClassName
.Length
;
2415 SetLastNtError(_SEH_GetExceptionCode());
2426 NtUserGetWOWClass(DWORD Unknown0
,