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
->rpdeskParent
!= NULL
)
90 DesktopHeapFree(Class
->rpdeskParent
,
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
->rpdeskParent
== Desktop
)
408 /* it is most likely that a window is created on the same
409 desktop as the window class. */
414 if (BaseClass
->rpdeskParent
== 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
->rpdeskParent
== 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
->rpdeskParent
= Desktop
;
463 if (BaseClass
->rpdeskParent
== 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
->rpdeskParent
!= NULL
);
532 ASSERT(Class
->Windows
!= 0);
533 ASSERT(Class
->Base
->rpdeskParent
!= 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
,
566 IN PDESKTOPINFO Desktop
,
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
->rpdeskParent
!= 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
->rpdeskParent
= 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
->rpdeskParent
== 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
->rpdeskParent
= 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
;
913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
915 Status
= _SEH2_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 */
1139 RTL_ATOM Ret
= (RTL_ATOM
)0;
1141 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1143 pti
= PsGetCurrentThreadWin32Thread();
1144 ti
= GetW32ThreadInfo();
1145 if (ti
== NULL
|| !ti
->kpi
->RegisteredSysClasses
)
1147 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1153 /* try to find a previously registered class */
1154 ClassAtom
= IntGetClassAtom(ClassName
,
1159 if (ClassAtom
!= (RTL_ATOM
)0)
1161 if (lpwcx
->style
& CS_GLOBALCLASS
)
1163 // global classes shall not have same names as system classes
1164 if (Class
->Global
|| Class
->System
)
1166 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1167 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1171 else if ( !Class
->Global
&& !Class
->System
)
1173 // local class already exists
1174 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1175 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1180 Class
= IntCreateClass(lpwcx
,
1192 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1193 Class
->hMenu
= hMenu
;
1195 /* Register the class */
1197 List
= &pi
->SystemClassList
;
1198 else if (Class
->Global
)
1199 List
= &pi
->GlobalClassList
;
1201 List
= &pi
->LocalClassList
;
1203 Class
->Next
= *List
;
1204 (void)InterlockedExchangePointer((PVOID
*)List
,
1214 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1215 IN HINSTANCE hInstance
)
1222 pi
= GetW32ProcessInfo();
1225 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1229 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1231 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1232 ClassAtom
= IntGetClassAtom(ClassName
,
1237 if (ClassAtom
== (RTL_ATOM
)0)
1242 ASSERT(Class
!= NULL
);
1244 if (Class
->Windows
!= 0 ||
1245 Class
->Clone
!= NULL
)
1247 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1251 /* must be a base class! */
1252 ASSERT(Class
->Base
== Class
);
1254 /* unlink the class */
1255 *Link
= Class
->Next
;
1257 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1259 /* finally free the resources */
1260 IntDestroyClass(Class
);
1267 UserGetClassName(IN PWINDOWCLASS Class
,
1268 IN OUT PUNICODE_STRING ClassName
,
1271 NTSTATUS Status
= STATUS_SUCCESS
;
1272 WCHAR szStaticTemp
[32];
1273 PWSTR szTemp
= NULL
;
1274 ULONG BufLen
= sizeof(szStaticTemp
);
1277 /* Note: Accessing the buffer in ClassName may raise an exception! */
1283 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1284 UNICODE_STRING UnicodeClassName
;
1286 /* limit the size of the static buffer on the stack to the
1287 size of the buffer provided by the caller */
1288 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1290 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1293 /* find out how big the buffer needs to be */
1294 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1300 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1302 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1304 /* the buffer required exceeds the ansi buffer provided,
1305 pretend like we're using the ansi buffer and limit the
1306 size to the buffer size provided */
1307 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1310 /* allocate a temporary buffer that can hold the unicode class name */
1311 szTemp
= ExAllocatePool(PagedPool
,
1315 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1319 /* query the class name */
1320 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1328 szTemp
= szStaticTemp
;
1330 if (NT_SUCCESS(Status
))
1332 /* convert the atom name to ansi */
1334 RtlInitUnicodeString(&UnicodeClassName
,
1337 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1340 if (!NT_SUCCESS(Status
))
1342 SetLastNtError(Status
);
1347 Ret
= BufLen
/ sizeof(WCHAR
);
1351 BufLen
= ClassName
->MaximumLength
;
1353 /* query the atom name */
1354 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1361 if (!NT_SUCCESS(Status
))
1363 SetLastNtError(Status
);
1367 Ret
= BufLen
/ sizeof(WCHAR
);
1370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1372 SetLastNtError(_SEH2_GetExceptionCode());
1376 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1385 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1395 TRACE("GetClassLong(%d)\n", Index
);
1396 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1397 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1399 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1403 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1405 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1406 certain architectures, maybe using RtlCopyMemory is a
1407 better choice for those architectures! */
1409 TRACE("Result: %x\n", Ret
);
1415 case GCL_CBWNDEXTRA
:
1416 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1419 case GCL_CBCLSEXTRA
:
1420 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1423 case GCLP_HBRBACKGROUND
:
1424 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1428 /* FIXME - get handle from pointer to CURSOR object */
1429 Ret
= (ULONG_PTR
)Class
->hCursor
;
1433 /* FIXME - get handle from pointer to ICON object */
1434 Ret
= (ULONG_PTR
)Class
->hIcon
;
1438 /* FIXME - get handle from pointer to ICON object */
1439 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1443 Ret
= (ULONG_PTR
)Class
->hInstance
;
1447 /* NOTE: Returns pointer in kernel heap! */
1449 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1451 Ret
= (ULONG_PTR
)Class
->MenuName
;
1455 Ret
= (ULONG_PTR
)Class
->Style
;
1459 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1460 GetW32ProcessInfo(),
1465 Ret
= (ULONG_PTR
)Class
->Atom
;
1469 SetLastWin32Error(ERROR_INVALID_INDEX
);
1477 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1478 IN PUNICODE_STRING MenuName
)
1482 /* change the base class first */
1483 Class
= Class
->Base
;
1485 if (MenuName
->Length
!= 0)
1487 ANSI_STRING AnsiString
;
1490 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1492 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1493 AnsiString
.MaximumLength
);
1494 if (strBufW
!= NULL
)
1500 /* copy the unicode string */
1501 RtlCopyMemory(strBufW
,
1504 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1506 /* create an ansi copy of the string */
1507 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1508 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1511 if (!NT_SUCCESS(Status
))
1513 SetLastNtError(Status
);
1519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1521 SetLastNtError(_SEH2_GetExceptionCode());
1527 /* update the base class */
1528 IntFreeClassMenuName(Class
);
1529 Class
->MenuName
= strBufW
;
1530 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1531 Class
->MenuNameIsString
= TRUE
;
1533 /* update the clones */
1534 Class
= Class
->Clone
;
1535 while (Class
!= NULL
)
1537 Class
->MenuName
= strBufW
;
1538 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1539 Class
->MenuNameIsString
= TRUE
;
1541 Class
= Class
->Next
;
1546 DPRINT1("Failed to copy class menu name!\n");
1547 UserHeapFree(strBufW
);
1551 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1555 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1557 /* update the base class */
1558 IntFreeClassMenuName(Class
);
1559 Class
->MenuName
= MenuName
->Buffer
;
1560 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1561 Class
->MenuNameIsString
= FALSE
;
1563 /* update the clones */
1564 Class
= Class
->Clone
;
1565 while (Class
!= NULL
)
1567 Class
->MenuName
= MenuName
->Buffer
;
1568 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1569 Class
->MenuNameIsString
= FALSE
;
1571 Class
= Class
->Next
;
1581 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1583 IN ULONG_PTR NewLong
,
1588 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1590 /* change the information in the base class first, then update the clones */
1591 Class
= Class
->Base
;
1597 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1599 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1600 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1602 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1606 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1608 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1609 certain architectures, maybe using RtlCopyMemory is a
1610 better choice for those architectures! */
1614 /* update the clones */
1615 Class
= Class
->Clone
;
1616 while (Class
!= NULL
)
1618 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1619 Class
= Class
->Next
;
1627 case GCL_CBWNDEXTRA
:
1628 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1629 Class
->WndExtra
= (INT
)NewLong
;
1631 /* update the clones */
1632 Class
= Class
->Clone
;
1633 while (Class
!= NULL
)
1635 Class
->WndExtra
= (INT
)NewLong
;
1636 Class
= Class
->Next
;
1641 case GCL_CBCLSEXTRA
:
1642 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1645 case GCLP_HBRBACKGROUND
:
1646 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1647 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1649 /* update the clones */
1650 Class
= Class
->Clone
;
1651 while (Class
!= NULL
)
1653 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1654 Class
= Class
->Next
;
1659 /* FIXME - get handle from pointer to CURSOR object */
1660 Ret
= (ULONG_PTR
)Class
->hCursor
;
1661 Class
->hCursor
= (HANDLE
)NewLong
;
1663 /* update the clones */
1664 Class
= Class
->Clone
;
1665 while (Class
!= NULL
)
1667 Class
->hCursor
= (HANDLE
)NewLong
;
1668 Class
= Class
->Next
;
1673 /* FIXME - get handle from pointer to ICON object */
1674 Ret
= (ULONG_PTR
)Class
->hIcon
;
1675 Class
->hIcon
= (HANDLE
)NewLong
;
1677 /* update the clones */
1678 Class
= Class
->Clone
;
1679 while (Class
!= NULL
)
1681 Class
->hIcon
= (HANDLE
)NewLong
;
1682 Class
= Class
->Next
;
1687 /* FIXME - get handle from pointer to ICON object */
1688 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1689 Class
->hIconSm
= (HANDLE
)NewLong
;
1691 /* update the clones */
1692 Class
= Class
->Clone
;
1693 while (Class
!= NULL
)
1695 Class
->hIconSm
= (HANDLE
)NewLong
;
1696 Class
= Class
->Next
;
1701 Ret
= (ULONG_PTR
)Class
->hInstance
;
1702 Class
->hInstance
= (HINSTANCE
)NewLong
;
1704 /* update the clones */
1705 Class
= Class
->Clone
;
1706 while (Class
!= NULL
)
1708 Class
->hInstance
= (HINSTANCE
)NewLong
;
1709 Class
= Class
->Next
;
1715 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1717 if (!IntSetClassMenuName(Class
,
1720 DPRINT("Setting the class menu name failed!\n");
1723 /* FIXME - really return NULL? Wine does so... */
1728 Ret
= (ULONG_PTR
)Class
->Style
;
1729 Class
->Style
= (UINT
)NewLong
;
1731 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1732 move the class to the appropriate list? For now, we save
1733 the original value in Class->Global, so we can always
1734 locate the appropriate list */
1736 /* update the clones */
1737 Class
= Class
->Clone
;
1738 while (Class
!= NULL
)
1740 Class
->Style
= (UINT
)NewLong
;
1741 Class
= Class
->Next
;
1746 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1753 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1755 Ret
= (ULONG_PTR
)Class
->Atom
;
1756 if (!IntSetClassAtom(Class
,
1765 SetLastWin32Error(ERROR_INVALID_INDEX
);
1773 UserGetClassInfo(IN PWINDOWCLASS Class
,
1774 OUT PWNDCLASSEXW lpwcx
,
1776 HINSTANCE hInstance
)
1780 lpwcx
->style
= Class
->Style
;
1782 pi
= GetW32ProcessInfo();
1783 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1787 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1788 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1789 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1790 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1791 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1794 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1796 lpwcx
->lpszMenuName
= Class
->MenuName
;
1798 if (Class
->hInstance
== pi
->hModUser
)
1799 lpwcx
->hInstance
= NULL
;
1801 lpwcx
->hInstance
= Class
->hInstance
;
1803 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1805 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1811 UserRegisterSystemClasses(IN ULONG Count
,
1812 IN PREGISTER_SYSCLASS SystemClasses
)
1814 /* NOTE: This routine may raise exceptions! */
1816 UNICODE_STRING ClassName
, MenuName
;
1817 PW32PROCESSINFO pi
= GetW32ProcessInfo();
1822 if (pi
->RegisteredSysClasses
|| pi
->hModUser
== NULL
)
1825 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1827 for (i
= 0; i
!= Count
; i
++)
1829 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1830 if (ClassName
.Length
!= 0)
1832 ProbeForRead(ClassName
.Buffer
,
1837 wc
.cbSize
= sizeof(wc
);
1838 wc
.style
= SystemClasses
[i
].Style
;
1839 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1841 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1842 wc
.hInstance
= pi
->hModUser
;
1844 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1845 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1846 wc
.lpszMenuName
= NULL
;
1847 wc
.lpszClassName
= ClassName
.Buffer
;
1850 Class
= IntCreateClass(&wc
,
1853 SystemClasses
[i
].ProcA
,
1854 REGISTERCLASS_SYSTEM
,
1859 Class
->fnID
= SystemClasses
[i
].ClassId
;
1861 ASSERT(Class
->System
);
1862 Class
->Next
= pi
->SystemClassList
;
1863 (void)InterlockedExchangePointer((PVOID
*)&pi
->SystemClassList
,
1868 WARN("!!! Registering system class failed!\n");
1874 pi
->RegisteredSysClasses
= TRUE
;
1878 /* SYSCALLS *****************************************************************/
1882 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1883 IN PUNICODE_STRING ClassName
,
1884 IN PUNICODE_STRING MenuName
,
1891 * Registers a new class with the window manager
1893 * lpwcx = Win32 extended window class structure
1894 * bUnicodeClass = Whether to send ANSI or unicode strings
1895 * to window procedures
1896 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1898 * Atom identifying the new class
1901 WNDCLASSEXW CapturedClassInfo
= {0};
1902 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1903 RTL_ATOM Ret
= (RTL_ATOM
)0;
1905 if (Flags
& ~REGISTERCLASS_ALL
)
1907 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1911 UserEnterExclusive();
1915 /* Probe the parameters and basic parameter checks */
1916 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1918 goto InvalidParameter
;
1922 sizeof(WNDCLASSEXW
),
1924 RtlCopyMemory(&CapturedClassInfo
,
1926 sizeof(WNDCLASSEXW
));
1928 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1929 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1931 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1932 CapturedClassInfo
.cbClsExtra
< 0 ||
1933 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1934 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1935 CapturedClassInfo
.cbWndExtra
< 0 ||
1936 CapturedClassInfo
.hInstance
== NULL
)
1938 goto InvalidParameter
;
1941 if (CapturedName
.Length
!= 0)
1943 ProbeForRead(CapturedName
.Buffer
,
1944 CapturedName
.Length
,
1949 if (!IS_ATOM(CapturedName
.Buffer
))
1951 goto InvalidParameter
;
1955 if (CapturedMenuName
.Length
!= 0)
1957 ProbeForRead(CapturedMenuName
.Buffer
,
1958 CapturedMenuName
.Length
,
1961 else if (CapturedMenuName
.Buffer
!= NULL
&&
1962 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1965 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1969 /* Register the class */
1970 Ret
= UserRegisterClass(&CapturedClassInfo
,
1973 hMenu
, /* FIXME - pass pointer */
1978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1980 SetLastNtError(_SEH2_GetExceptionCode());
1992 NtUserRegisterClassExWOW(
1994 PUNICODE_STRING ClassName
,
1995 PUNICODE_STRING ClsNVersion
,
1996 PCLSMENUNAME pClassMenuName
,
2001 WNDCLASSEXW CapturedClassInfo
= {0};
2002 UNICODE_STRING CapturedName
= {0}, ClassnametoVersion
= {0};
2003 RTL_ATOM Ret
= (RTL_ATOM
)0;
2005 UserEnterExclusive();
2009 /* Probe the parameters and basic parameter checks */
2010 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2012 goto InvalidParameter
;
2014 if (!pClassMenuName
)
2016 goto InvalidParameter
;
2020 sizeof(WNDCLASSEXW
),
2022 RtlCopyMemory(&CapturedClassInfo
,
2024 sizeof(WNDCLASSEXW
));
2026 Need to watch this. When UnregisterClass is called these pointers
2027 are freed by the caller in user space. So, we just probe the data
2028 for now and pass it on and copy it to the shared class structure.
2030 ProbeForRead(pClassMenuName
,
2031 sizeof(CLSMENUNAME
),
2034 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2035 ClassnametoVersion
= ProbeForReadUnicodeString(ClsNVersion
);
2037 if (CapturedName
.Length
& 1 || ClassnametoVersion
.Length
& 1 ||
2038 CapturedClassInfo
.cbClsExtra
< 0 ||
2039 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2040 ClassnametoVersion
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
2041 CapturedClassInfo
.cbWndExtra
< 0 ||
2042 CapturedClassInfo
.hInstance
== NULL
)
2044 goto InvalidParameter
;
2047 if (CapturedName
.Length
!= 0)
2049 ProbeForRead(CapturedName
.Buffer
,
2050 CapturedName
.Length
,
2055 if (!IS_ATOM(CapturedName
.Buffer
))
2057 goto InvalidParameter
;
2061 if (ClassnametoVersion
.Length
!= 0)
2063 ProbeForRead(ClassnametoVersion
.Buffer
,
2064 ClassnametoVersion
.Length
,
2067 else if (ClassnametoVersion
.Buffer
!= NULL
&&
2068 !IS_INTRESOURCE(ClassnametoVersion
.Buffer
))
2071 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2075 /* Register the class */
2076 // Ret = UserRegisterClass(&CapturedClassInfo,
2078 // &ClassnametoVersion,
2079 // hMenu, /* FIXME - pass pointer */
2084 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2086 SetLastNtError(_SEH2_GetExceptionCode());
2097 NtUserGetClassLong(IN HWND hWnd
,
2101 PWINDOW_OBJECT Window
;
2104 if (Offset
!= GCLP_WNDPROC
)
2110 UserEnterExclusive();
2113 Window
= UserGetWindowObject(hWnd
);
2116 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
2120 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
2122 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2134 NtUserSetClassLong(HWND hWnd
,
2136 ULONG_PTR dwNewLong
,
2140 PWINDOW_OBJECT Window
;
2143 UserEnterExclusive();
2145 pi
= GetW32ProcessInfo();
2149 Window
= UserGetWindowObject(hWnd
);
2152 if (Window
->ti
->kpi
!= pi
)
2154 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2160 UNICODE_STRING Value
;
2162 /* probe the parameters */
2163 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2165 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2166 if (Value
.Length
& 1)
2168 goto InvalidParameter
;
2171 if (Value
.Length
!= 0)
2173 ProbeForRead(Value
.Buffer
,
2179 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2181 goto InvalidParameter
;
2183 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2186 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2191 dwNewLong
= (ULONG_PTR
)&Value
;
2194 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2201 SetLastNtError(_SEH2_GetExceptionCode());
2223 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2224 IN HINSTANCE hInstance
,
2225 OUT PCLSMENUNAME pClassMenuName
)
2227 UNICODE_STRING CapturedClassName
;
2230 UserEnterExclusive();
2234 /* probe the paramters */
2235 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2236 if (CapturedClassName
.Length
& 1)
2238 goto InvalidParameter
;
2241 if (CapturedClassName
.Length
!= 0)
2243 ProbeForRead(CapturedClassName
.Buffer
,
2244 CapturedClassName
.Length
,
2249 if (!IS_ATOM(CapturedClassName
.Buffer
))
2252 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2257 /* unregister the class */
2258 Ret
= UserUnregisterClass(&CapturedClassName
,
2261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2263 SetLastNtError(_SEH2_GetExceptionCode());
2272 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2275 HINSTANCE hInstance
,
2276 PUNICODE_STRING ClassName
,
2277 LPWNDCLASSEXW lpWndClassEx
,
2278 LPWSTR
*ppszMenuName
,
2281 UNICODE_STRING CapturedClassName
;
2287 /* NOTE: need exclusive lock because getting the wndproc might require the
2288 creation of a call procedure handle */
2289 UserEnterExclusive();
2291 pi
= GetW32ProcessInfo();
2294 ERR("GetW32ProcessInfo() returned NULL!\n");
2299 /* probe the paramters */
2300 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2302 if (CapturedClassName
.Length
== 0)
2303 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2305 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2307 if (CapturedClassName
.Length
& 1)
2309 goto InvalidParameter
;
2312 if (CapturedClassName
.Length
!= 0)
2314 ProbeForRead(CapturedClassName
.Buffer
,
2315 CapturedClassName
.Length
,
2320 if (!IS_ATOM(CapturedClassName
.Buffer
))
2322 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2323 goto InvalidParameter
;
2327 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2330 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2334 ProbeForWrite(lpWndClassEx
,
2335 sizeof(WNDCLASSEXW
),
2338 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2343 if (ClassAtom
!= (RTL_ATOM
)0)
2345 if (hInstance
== NULL
)
2346 hInstance
= pi
->hModUser
;
2348 Ret
= UserGetClassInfo(Class
,
2355 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2356 /* FIXME - handle Class->Desktop == NULL!!!!! */
2358 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2360 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2361 (PVOID
)Class
->AnsiMenuName
:
2362 (PVOID
)Class
->MenuName
);
2365 /* Undocumented behavior! Return the class atom as a BOOL! */
2366 Ret
= (BOOL
)ClassAtom
;
2370 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2374 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2386 NtUserGetClassName (IN HWND hWnd
,
2387 OUT PUNICODE_STRING ClassName
,
2390 PWINDOW_OBJECT Window
;
2391 UNICODE_STRING CapturedClassName
;
2396 Window
= UserGetWindowObject(hWnd
);
2401 ProbeForWriteUnicodeString(ClassName
);
2402 CapturedClassName
= *ClassName
;
2404 /* get the class name */
2405 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2411 /* update the Length field */
2412 ClassName
->Length
= CapturedClassName
.Length
;
2415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2417 SetLastNtError(_SEH2_GetExceptionCode());
2428 NtUserGetWOWClass(DWORD Unknown0
,