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 ******************************************************************/
44 { FNID_BUTTON
, ICLS_BUTTON
},
45 { FNID_EDIT
, ICLS_EDIT
},
46 { FNID_STATIC
, ICLS_STATIC
},
47 { FNID_LISTBOX
, ICLS_LISTBOX
},
48 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
49 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
50 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
51 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
52 { FNID_DIALOG
, ICLS_DIALOG
},
53 { FNID_MENU
, ICLS_MENU
},
54 { FNID_ICONTITLE
, ICLS_ICONTITLE
}
60 LockupFnIdToiCls(int FnId
, int *iCls
)
64 for ( i
= 0; i
< 10; i
++)
66 if (FnidToiCls
[i
].FnId
== FnId
)
68 *iCls
= FnidToiCls
[i
].ClsId
;
75 /* WINDOWCLASS ***************************************************************/
78 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class
)
80 /* free the menu name, if it was changed and allocated */
81 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
83 UserHeapFree(Class
->MenuName
);
84 Class
->MenuName
= NULL
;
85 Class
->AnsiMenuName
= NULL
;
90 IntDestroyClass(IN OUT PWINDOWCLASS Class
)
92 /* there shouldn't be any clones anymore */
93 ASSERT(Class
->Windows
== 0);
94 ASSERT(Class
->Clone
== NULL
);
96 if (Class
->Base
== Class
)
98 PCALLPROC CallProc
, NextCallProc
;
100 /* Destroy allocated callproc handles */
101 CallProc
= Class
->CallProcList
;
102 while (CallProc
!= NULL
)
104 NextCallProc
= CallProc
->Next
;
106 CallProc
->Next
= NULL
;
107 DestroyCallProc(NULL
,
110 CallProc
= NextCallProc
;
115 DceFreeClassDCE(((PDCE
)Class
->Dce
)->hDC
);
119 IntFreeClassMenuName(Class
);
122 /* free the structure */
123 if (Class
->rpdeskParent
!= NULL
)
125 DesktopHeapFree(Class
->rpdeskParent
,
135 /* clean all process classes. all process windows must cleaned first!! */
136 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
139 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
143 /* free all local classes */
144 Class
= pi
->LocalClassList
;
145 while (Class
!= NULL
)
147 pi
->LocalClassList
= Class
->Next
;
149 ASSERT(Class
->Base
== Class
);
150 IntDestroyClass(Class
);
152 Class
= pi
->LocalClassList
;
155 /* free all global classes */
156 Class
= pi
->GlobalClassList
;
157 while (Class
!= NULL
)
159 pi
->GlobalClassList
= Class
->Next
;
161 ASSERT(Class
->Base
== Class
);
162 IntDestroyClass(Class
);
164 Class
= pi
->GlobalClassList
;
167 /* free all system classes */
168 Class
= pi
->SystemClassList
;
169 while (Class
!= NULL
)
171 pi
->SystemClassList
= Class
->Next
;
173 ASSERT(Class
->Base
== Class
);
174 IntDestroyClass(Class
);
176 Class
= pi
->SystemClassList
;
182 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
189 if (ClassName
->Length
!= 0)
191 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
192 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
194 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
201 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
205 AtomName
= ClassName
->Buffer
;
207 /* If an Atom, need to verify, if it was already added to the global atom list. */
208 if (IS_ATOM(AtomName
))
210 *pAtom
= (RTL_ATOM
)((ULONG_PTR
)AtomName
);
211 Status
= RtlQueryAtomInAtomTable( gAtomTable
,
218 if (NT_SUCCESS(Status
)) return TRUE
;
221 Status
= RtlAddAtomToAtomTable(gAtomTable
,
225 if (!NT_SUCCESS(Status
))
227 SetLastNtError(Status
);
235 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
237 return RtlDeleteAtomFromAtomTable(gAtomTable
,
242 UserFindCallProc(IN PWINDOWCLASS Class
,
248 CallProc
= Class
->CallProcList
;
249 while (CallProc
!= NULL
)
251 if (CallProc
->WndProc
== WndProc
&&
252 CallProc
->Unicode
== (UINT
)bUnicode
)
257 CallProc
= CallProc
->Next
;
264 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class
,
265 IN PCALLPROC CallProc
)
267 PWINDOWCLASS BaseClass
;
269 ASSERT(CallProc
->Next
== NULL
);
271 BaseClass
= Class
->Base
;
272 ASSERT(CallProc
->Next
== NULL
);
273 CallProc
->Next
= BaseClass
->CallProcList
;
274 BaseClass
->CallProcList
= CallProc
;
276 /* Update all clones */
277 Class
= Class
->Clone
;
278 while (Class
!= NULL
)
280 Class
->CallProcList
= BaseClass
->CallProcList
;
286 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
287 IN PUNICODE_STRING ClassName
)
289 RTL_ATOM Atom
= (RTL_ATOM
)0;
291 /* update the base class first */
294 if (!IntRegisterClassAtom(ClassName
,
300 IntDeregisterClassAtom(Class
->Atom
);
304 /* update the clones */
305 Class
= Class
->Clone
;
306 while (Class
!= NULL
)
317 IntGetClassWndProc(IN PWINDOWCLASS Class
,
321 ASSERT(UserIsEnteredExclusive() == TRUE
);
325 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
329 if (!Ansi
== Class
->Unicode
)
331 return Class
->WndProc
;
335 PWINDOWCLASS BaseClass
;
337 /* make sure the call procedures are located on the desktop
338 of the base class! */
339 BaseClass
= Class
->Base
;
342 if (Class
->CallProc
!= NULL
)
344 return GetCallProcHandle(Class
->CallProc
);
348 PCALLPROC NewCallProc
;
353 NewCallProc
= UserFindCallProc(Class
,
356 if (NewCallProc
== NULL
)
358 NewCallProc
= CreateCallProc(NULL
,
362 if (NewCallProc
== NULL
)
364 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
368 UserAddCallProcToClass(Class
,
372 Class
->CallProc
= NewCallProc
;
374 /* update the clones */
375 Class
= Class
->Clone
;
376 while (Class
!= NULL
)
378 Class
->CallProc
= NewCallProc
;
383 return GetCallProcHandle(NewCallProc
);
390 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
398 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
399 SetLastWin32Error(ERROR_ACCESS_DENIED
);
403 /* update the base class first */
406 /* resolve any callproc handle if possible */
407 if (IsCallProcHandle(WndProc
))
411 if (UserGetCallProcInfo((HANDLE
)WndProc
,
414 WndProc
= wpInfo
.WindowProc
;
415 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
419 Ret
= IntGetClassWndProc(Class
,
427 /* update the class info */
428 Class
->Unicode
= !Ansi
;
429 Class
->WndProc
= WndProc
;
431 /* update the clones */
432 Class
= Class
->Clone
;
433 while (Class
!= NULL
)
435 Class
->Unicode
= !Ansi
;
436 Class
->WndProc
= WndProc
;
445 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
446 IN OUT PWINDOWCLASS
*ClassLink
,
452 ASSERT(Desktop
!= NULL
);
453 ASSERT(BaseClass
->Base
== BaseClass
);
455 if (BaseClass
->rpdeskParent
== Desktop
)
457 /* it is most likely that a window is created on the same
458 desktop as the window class. */
463 if (BaseClass
->rpdeskParent
== NULL
)
465 ASSERT(BaseClass
->Windows
== 0);
466 ASSERT(BaseClass
->Clone
== NULL
);
468 /* Classes are also located in the shared heap when the class
469 was created before the thread attached to a desktop. As soon
470 as a window is created for such a class located on the shared
471 heap, the class is cloned into the desktop heap on which the
472 window is created. */
477 /* The user is asking for a class object on a different desktop,
479 Class
= BaseClass
->Clone
;
480 while (Class
!= NULL
)
482 if (Class
->rpdeskParent
== Desktop
)
484 ASSERT(Class
->Base
== BaseClass
);
485 ASSERT(Class
->Clone
== NULL
);
495 /* The window is created on a different desktop, we need to
496 clone the class object to the desktop heap of the window! */
497 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->ClsExtra
;
499 Class
= DesktopHeapAlloc(Desktop
,
503 /* simply clone the class */
508 /* update some pointers and link the class */
509 Class
->rpdeskParent
= Desktop
;
512 if (BaseClass
->rpdeskParent
== NULL
)
514 /* we don't really need the base class on the shared
515 heap anymore, delete it so the only class left is
516 the clone we just created, which now serves as the
518 ASSERT(BaseClass
->Clone
== NULL
);
519 ASSERT(Class
->Clone
== NULL
);
521 Class
->Next
= BaseClass
->Next
;
523 /* replace the base class */
524 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
527 /* destroy the obsolete copy on the shared heap */
528 BaseClass
->Base
= NULL
;
529 BaseClass
->Clone
= NULL
;
530 IntDestroyClass(BaseClass
);
534 /* link in the clone */
536 Class
->Base
= BaseClass
;
537 Class
->Next
= BaseClass
->Clone
;
538 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
544 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
552 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
553 IN OUT PWINDOWCLASS
*ClassLink
,
558 ASSERT(BaseClass
->Base
== BaseClass
);
560 Class
= IntGetClassForDesktop(BaseClass
,
572 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
573 IN OUT PWINDOWCLASS
*BaseClassLink
,
574 IN OUT PWINDOWCLASS
*CloneLink
)
576 PWINDOWCLASS Clone
, BaseClass
;
578 ASSERT(Class
->Base
!= Class
);
579 ASSERT(Class
->Base
->Clone
!= NULL
);
580 ASSERT(Class
->rpdeskParent
!= NULL
);
581 ASSERT(Class
->Windows
!= 0);
582 ASSERT(Class
->Base
->rpdeskParent
!= NULL
);
583 ASSERT(Class
->Base
->Windows
== 0);
585 /* unlink the clone */
586 *CloneLink
= Class
->Next
;
587 Class
->Clone
= Class
->Base
->Clone
;
589 BaseClass
= Class
->Base
;
591 /* update the class information to make it a base class */
593 Class
->Next
= (*BaseClassLink
)->Next
;
595 /* update all clones */
596 Clone
= Class
->Clone
;
597 while (Clone
!= NULL
)
599 ASSERT(Clone
->Clone
== NULL
);
603 Clone
->CallProc
= Class
->CallProc
;
608 /* link in the new base class */
609 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
614 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
615 IN PDESKTOPINFO Desktop
,
618 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
620 BaseClass
= Class
->Base
;
622 if (--Class
->Windows
== 0)
624 if (BaseClass
== Class
)
626 ASSERT(Class
->Base
== Class
);
628 /* check if there are clones of the class on other desktops,
629 link the first clone in if possible. If there are no clones
630 then leave the class on the desktop heap. It will get moved
631 to the shared heap when the thread detaches. */
632 if (BaseClass
->Clone
!= NULL
)
634 if (BaseClass
->System
)
635 PrevLink
= &pi
->SystemClassList
;
636 else if (BaseClass
->Global
)
637 PrevLink
= &pi
->GlobalClassList
;
639 PrevLink
= &pi
->LocalClassList
;
641 CurrentClass
= *PrevLink
;
642 while (CurrentClass
!= BaseClass
)
644 ASSERT(CurrentClass
!= NULL
);
646 PrevLink
= &CurrentClass
->Next
;
647 CurrentClass
= CurrentClass
->Next
;
650 ASSERT(*PrevLink
== BaseClass
);
652 /* make the first clone become the new base class */
653 IntMakeCloneBaseClass(BaseClass
->Clone
,
657 /* destroy the class, there's still another clone of the class
658 that now serves as a base class. Make sure we don't destruct
659 resources shared by all classes (Base = NULL)! */
660 BaseClass
->Base
= NULL
;
661 BaseClass
->Clone
= NULL
;
662 IntDestroyClass(BaseClass
);
667 /* locate the cloned class and unlink it */
668 PrevLink
= &BaseClass
->Clone
;
669 CurrentClass
= BaseClass
->Clone
;
670 while (CurrentClass
!= Class
)
672 ASSERT(CurrentClass
!= NULL
);
674 PrevLink
= &CurrentClass
->Next
;
675 CurrentClass
= CurrentClass
->Next
;
678 ASSERT(CurrentClass
== Class
);
680 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
683 ASSERT(Class
->Base
== BaseClass
);
684 ASSERT(Class
->Clone
== NULL
);
686 /* the class was just a clone, we don't need it anymore */
687 IntDestroyClass(Class
);
693 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
694 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
696 PWINDOWCLASS NewClass
;
699 ASSERT(Class
->Base
== Class
);
700 ASSERT(Class
->rpdeskParent
!= NULL
);
701 ASSERT(Class
->Windows
== 0);
702 ASSERT(Class
->Clone
== NULL
);
704 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->ClsExtra
;
706 /* allocate the new base class on the shared heap */
707 NewClass
= UserHeapAlloc(ClassSize
);
708 if (NewClass
!= NULL
)
710 RtlCopyMemory(NewClass
,
714 NewClass
->rpdeskParent
= NULL
;
715 NewClass
->Base
= NewClass
;
717 /* replace the class in the list */
718 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
720 *ClassLinkPtr
= &NewClass
->Next
;
722 /* free the obsolete class on the desktop heap */
724 IntDestroyClass(Class
);
732 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
733 IN OUT PWINDOWCLASS
*ClassList
,
734 IN BOOL FreeOnFailure
,
737 PWINDOWCLASS Class
, NextClass
, *Link
;
739 /* NOTE: We only need to check base classes! When classes are no longer needed
740 on a desktop, the clones will be freed automatically as soon as possible.
741 However, we need to move base classes to the shared heap, as soon as
742 the last desktop heap where a class is allocated on is about to be destroyed.
743 If we didn't move the class to the shared heap, the class would become
746 ASSERT(Desktop
!= NULL
);
750 while (Class
!= NULL
)
752 NextClass
= Class
->Next
;
754 ASSERT(Class
->Base
== Class
);
756 if (Class
->rpdeskParent
== Desktop
&&
759 /* there shouldn't be any clones around anymore! */
760 ASSERT(Class
->Clone
== NULL
);
762 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
763 /* FIXME - We could move the class to another desktop heap if there's still desktops
764 mapped into the process... */
766 /* move the class to the shared heap */
767 if (IntMoveClassToSharedHeap(Class
,
770 ASSERT(*Link
== NextClass
);
774 ASSERT(NextClass
== Class
->Next
);
778 /* unlink the base class */
779 (void)InterlockedExchangePointer((PVOID
*)Link
,
782 /* we can free the old base class now */
784 IntDestroyClass(Class
);
801 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
802 IN BOOL FreeOnFailure
)
807 pi
= GetW32ProcessInfo();
811 /* check all local classes */
812 IntCheckDesktopClasses(Desktop
,
817 /* check all global classes */
818 IntCheckDesktopClasses(Desktop
,
819 &pi
->GlobalClassList
,
823 /* check all system classes */
824 IntCheckDesktopClasses(Desktop
,
825 &pi
->SystemClassList
,
831 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
832 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
840 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
841 IN PUNICODE_STRING ClassName
,
842 IN PUNICODE_STRING MenuName
,
849 PWINDOWCLASS Class
= NULL
;
851 PWSTR pszMenuName
= NULL
;
852 NTSTATUS Status
= STATUS_SUCCESS
;
854 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
855 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
857 if (!IntRegisterClassAtom(ClassName
,
860 DPRINT1("Failed to register class atom!\n");
864 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
865 if (MenuName
->Length
!= 0)
867 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
868 RtlUnicodeStringToAnsiSize(MenuName
));
869 if (pszMenuName
== NULL
)
875 Class
= DesktopHeapAlloc(Desktop
,
880 /* FIXME - the class was created before being connected
881 to a desktop. It is possible for the desktop window,
882 but should it be allowed for any other case? */
883 Class
= UserHeapAlloc(ClassSize
);
891 Class
->rpdeskParent
= Desktop
;
895 if (dwFlags
& REGISTERCLASS_SYSTEM
)
897 dwFlags
&= ~REGISTERCLASS_ANSI
;
898 Class
->WndProcExtra
= wpExtra
;
899 Class
->System
= TRUE
;
904 PWSTR pszMenuNameBuffer
= pszMenuName
;
906 /* need to protect with SEH since accessing the WNDCLASSEX structure
907 and string buffers might raise an exception! We don't want to
909 Class
->WndProc
= lpwcx
->lpfnWndProc
;
910 Class
->Style
= lpwcx
->style
;
911 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
912 Class
->WndExtra
= lpwcx
->cbWndExtra
;
913 Class
->hInstance
= lpwcx
->hInstance
;
914 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
915 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
916 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
917 Class
->hbrBackground
= lpwcx
->hbrBackground
;
919 /* make a copy of the string */
920 if (pszMenuNameBuffer
!= NULL
)
922 Class
->MenuNameIsString
= TRUE
;
924 Class
->MenuName
= pszMenuNameBuffer
;
925 RtlCopyMemory(Class
->MenuName
,
928 Class
->MenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
930 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
933 Class
->MenuName
= MenuName
->Buffer
;
935 /* save an ansi copy of the string */
936 if (pszMenuNameBuffer
!= NULL
)
938 ANSI_STRING AnsiString
;
940 Class
->AnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
941 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
942 AnsiString
.Buffer
= Class
->AnsiMenuName
;
943 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
946 if (!NT_SUCCESS(Status
))
948 DPRINT1("Failed to convert unicode menu name to ansi!\n");
950 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
955 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
957 if (!(dwFlags
& REGISTERCLASS_ANSI
))
958 Class
->Unicode
= TRUE
;
960 if (Class
->Style
& CS_GLOBALCLASS
)
961 Class
->Global
= TRUE
;
963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
965 Status
= _SEH2_GetExceptionCode();
969 if (!NT_SUCCESS(Status
))
971 DPRINT1("Failed creating the class: 0x%x\n", Status
);
973 SetLastNtError(Status
);
975 if (pszMenuName
!= NULL
)
976 UserHeapFree(pszMenuName
);
978 DesktopHeapFree(Desktop
,
982 IntDeregisterClassAtom(Atom
);
988 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
990 if (pszMenuName
!= NULL
)
991 UserHeapFree(pszMenuName
);
993 IntDeregisterClassAtom(Atom
);
995 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1002 IntFindClass(IN RTL_ATOM Atom
,
1003 IN HINSTANCE hInstance
,
1004 IN PWINDOWCLASS
*ClassList
,
1005 OUT PWINDOWCLASS
**Link OPTIONAL
)
1007 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
1010 while (Class
!= NULL
)
1012 if (Class
->Atom
== Atom
&&
1013 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
1016 ASSERT(Class
->Base
== Class
);
1023 PrevLink
= &Class
->Next
;
1024 Class
= Class
->Next
;
1031 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1036 if (ClassName
->Length
!= 0)
1042 /* NOTE: Caller has to protect the call with SEH! */
1044 if (ClassName
->Length
!= 0)
1046 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1047 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1049 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1053 /* We need to make a local copy of the class name! The caller could
1054 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1055 We're protected by SEH, but the ranges that might be accessed were
1057 RtlCopyMemory(szBuf
,
1060 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1064 AtomName
= ClassName
->Buffer
;
1066 /* lookup the atom */
1067 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1070 if (NT_SUCCESS(Status
))
1076 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1078 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1082 SetLastNtError(Status
);
1088 ASSERT(IS_ATOM(ClassName
->Buffer
));
1089 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1097 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1098 IN HINSTANCE hInstance OPTIONAL
,
1099 IN PPROCESSINFO pi OPTIONAL
,
1100 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1101 OUT PWINDOWCLASS
**Link OPTIONAL
)
1103 RTL_ATOM Atom
= (RTL_ATOM
)0;
1105 ASSERT(BaseClass
!= NULL
);
1107 if (IntGetAtomFromStringOrAtom(ClassName
,
1109 Atom
!= (RTL_ATOM
)0)
1113 /* attempt to locate the class object */
1117 /* Step 1: try to find an exact match of locally registered classes */
1118 Class
= IntFindClass(Atom
,
1120 &pi
->LocalClassList
,
1127 /* Step 2: try to find any globally registered class. The hInstance
1128 is not relevant for global classes */
1129 Class
= IntFindClass(Atom
,
1131 &pi
->GlobalClassList
,
1138 /* Step 3: try to find any local class registered by user32 */
1139 Class
= IntFindClass(Atom
,
1141 &pi
->LocalClassList
,
1148 /* Step 4: try to find any global class registered by user32 */
1149 Class
= IntFindClass(Atom
,
1151 &pi
->GlobalClassList
,
1158 /* Step 5: try to find a system class */
1159 Class
= IntFindClass(Atom
,
1161 &pi
->SystemClassList
,
1165 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1177 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1178 IN PUNICODE_STRING ClassName
,
1179 IN PUNICODE_STRING MenuName
,
1180 IN HANDLE hMenu
, /* FIXME */
1189 RTL_ATOM Ret
= (RTL_ATOM
)0;
1191 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1193 pti
= PsGetCurrentThreadWin32Thread();
1194 ti
= GetW32ThreadInfo();
1195 if (ti
== NULL
|| !ti
->ppi
->RegisteredSysClasses
)
1197 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1203 /* try to find a previously registered class */
1204 ClassAtom
= IntGetClassAtom(ClassName
,
1209 if (ClassAtom
!= (RTL_ATOM
)0)
1211 if (lpwcx
->style
& CS_GLOBALCLASS
)
1213 // global classes shall not have same names as system classes
1214 if (Class
->Global
|| Class
->System
)
1216 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1217 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1221 else if ( !Class
->Global
&& !Class
->System
)
1223 // local class already exists
1224 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1225 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1230 Class
= IntCreateClass(lpwcx
,
1242 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1243 Class
->hMenu
= hMenu
;
1245 /* Register the class */
1247 List
= &pi
->SystemClassList
;
1248 else if (Class
->Global
)
1249 List
= &pi
->GlobalClassList
;
1251 List
= &pi
->LocalClassList
;
1253 Class
->Next
= *List
;
1254 (void)InterlockedExchangePointer((PVOID
*)List
,
1264 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1265 IN HINSTANCE hInstance
)
1272 pi
= GetW32ProcessInfo();
1275 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1279 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1281 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1282 ClassAtom
= IntGetClassAtom(ClassName
,
1287 if (ClassAtom
== (RTL_ATOM
)0)
1292 ASSERT(Class
!= NULL
);
1294 if (Class
->Windows
!= 0 ||
1295 Class
->Clone
!= NULL
)
1297 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1301 /* must be a base class! */
1302 ASSERT(Class
->Base
== Class
);
1304 /* unlink the class */
1305 *Link
= Class
->Next
;
1307 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1309 /* finally free the resources */
1310 IntDestroyClass(Class
);
1317 UserGetClassName(IN PWINDOWCLASS Class
,
1318 IN OUT PUNICODE_STRING ClassName
,
1321 NTSTATUS Status
= STATUS_SUCCESS
;
1322 WCHAR szStaticTemp
[32];
1323 PWSTR szTemp
= NULL
;
1324 ULONG BufLen
= sizeof(szStaticTemp
);
1327 /* Note: Accessing the buffer in ClassName may raise an exception! */
1333 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1334 UNICODE_STRING UnicodeClassName
;
1336 /* limit the size of the static buffer on the stack to the
1337 size of the buffer provided by the caller */
1338 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1340 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1343 /* find out how big the buffer needs to be */
1344 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1350 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1352 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1354 /* the buffer required exceeds the ansi buffer provided,
1355 pretend like we're using the ansi buffer and limit the
1356 size to the buffer size provided */
1357 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1360 /* allocate a temporary buffer that can hold the unicode class name */
1361 szTemp
= ExAllocatePool(PagedPool
,
1365 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1369 /* query the class name */
1370 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1378 szTemp
= szStaticTemp
;
1380 if (NT_SUCCESS(Status
))
1382 /* convert the atom name to ansi */
1384 RtlInitUnicodeString(&UnicodeClassName
,
1387 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1390 if (!NT_SUCCESS(Status
))
1392 SetLastNtError(Status
);
1397 Ret
= BufLen
/ sizeof(WCHAR
);
1401 BufLen
= ClassName
->MaximumLength
;
1403 /* query the atom name */
1404 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1411 if (!NT_SUCCESS(Status
))
1413 SetLastNtError(Status
);
1417 Ret
= BufLen
/ sizeof(WCHAR
);
1420 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1422 SetLastNtError(_SEH2_GetExceptionCode());
1426 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1435 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1445 TRACE("GetClassLong(%d)\n", Index
);
1446 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1447 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1449 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1453 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1455 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1456 certain architectures, maybe using RtlCopyMemory is a
1457 better choice for those architectures! */
1459 TRACE("Result: %x\n", Ret
);
1465 case GCL_CBWNDEXTRA
:
1466 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1469 case GCL_CBCLSEXTRA
:
1470 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1473 case GCLP_HBRBACKGROUND
:
1474 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1478 /* FIXME - get handle from pointer to CURSOR object */
1479 Ret
= (ULONG_PTR
)Class
->hCursor
;
1483 /* FIXME - get handle from pointer to ICON object */
1484 Ret
= (ULONG_PTR
)Class
->hIcon
;
1488 /* FIXME - get handle from pointer to ICON object */
1489 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1493 Ret
= (ULONG_PTR
)Class
->hInstance
;
1497 /* NOTE: Returns pointer in kernel heap! */
1499 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1501 Ret
= (ULONG_PTR
)Class
->MenuName
;
1505 Ret
= (ULONG_PTR
)Class
->Style
;
1509 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1510 GetW32ProcessInfo(),
1515 Ret
= (ULONG_PTR
)Class
->Atom
;
1519 SetLastWin32Error(ERROR_INVALID_INDEX
);
1527 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1528 IN PUNICODE_STRING MenuName
)
1532 /* change the base class first */
1533 Class
= Class
->Base
;
1535 if (MenuName
->Length
!= 0)
1537 ANSI_STRING AnsiString
;
1540 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1542 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1543 AnsiString
.MaximumLength
);
1544 if (strBufW
!= NULL
)
1550 /* copy the unicode string */
1551 RtlCopyMemory(strBufW
,
1554 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1556 /* create an ansi copy of the string */
1557 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1558 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1561 if (!NT_SUCCESS(Status
))
1563 SetLastNtError(Status
);
1569 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1571 SetLastNtError(_SEH2_GetExceptionCode());
1577 /* update the base class */
1578 IntFreeClassMenuName(Class
);
1579 Class
->MenuName
= strBufW
;
1580 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1581 Class
->MenuNameIsString
= TRUE
;
1583 /* update the clones */
1584 Class
= Class
->Clone
;
1585 while (Class
!= NULL
)
1587 Class
->MenuName
= strBufW
;
1588 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1589 Class
->MenuNameIsString
= TRUE
;
1591 Class
= Class
->Next
;
1596 DPRINT1("Failed to copy class menu name!\n");
1597 UserHeapFree(strBufW
);
1601 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1605 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1607 /* update the base class */
1608 IntFreeClassMenuName(Class
);
1609 Class
->MenuName
= MenuName
->Buffer
;
1610 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1611 Class
->MenuNameIsString
= FALSE
;
1613 /* update the clones */
1614 Class
= Class
->Clone
;
1615 while (Class
!= NULL
)
1617 Class
->MenuName
= MenuName
->Buffer
;
1618 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1619 Class
->MenuNameIsString
= FALSE
;
1621 Class
= Class
->Next
;
1631 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1633 IN ULONG_PTR NewLong
,
1638 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1640 /* change the information in the base class first, then update the clones */
1641 Class
= Class
->Base
;
1647 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1649 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1650 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1652 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1656 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1658 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1659 certain architectures, maybe using RtlCopyMemory is a
1660 better choice for those architectures! */
1664 /* update the clones */
1665 Class
= Class
->Clone
;
1666 while (Class
!= NULL
)
1668 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1669 Class
= Class
->Next
;
1677 case GCL_CBWNDEXTRA
:
1678 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1679 Class
->WndExtra
= (INT
)NewLong
;
1681 /* update the clones */
1682 Class
= Class
->Clone
;
1683 while (Class
!= NULL
)
1685 Class
->WndExtra
= (INT
)NewLong
;
1686 Class
= Class
->Next
;
1691 case GCL_CBCLSEXTRA
:
1692 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1695 case GCLP_HBRBACKGROUND
:
1696 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1697 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1699 /* update the clones */
1700 Class
= Class
->Clone
;
1701 while (Class
!= NULL
)
1703 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1704 Class
= Class
->Next
;
1709 /* FIXME - get handle from pointer to CURSOR object */
1710 Ret
= (ULONG_PTR
)Class
->hCursor
;
1711 Class
->hCursor
= (HANDLE
)NewLong
;
1713 /* update the clones */
1714 Class
= Class
->Clone
;
1715 while (Class
!= NULL
)
1717 Class
->hCursor
= (HANDLE
)NewLong
;
1718 Class
= Class
->Next
;
1723 /* FIXME - get handle from pointer to ICON object */
1724 Ret
= (ULONG_PTR
)Class
->hIcon
;
1725 Class
->hIcon
= (HANDLE
)NewLong
;
1727 /* update the clones */
1728 Class
= Class
->Clone
;
1729 while (Class
!= NULL
)
1731 Class
->hIcon
= (HANDLE
)NewLong
;
1732 Class
= Class
->Next
;
1737 /* FIXME - get handle from pointer to ICON object */
1738 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1739 Class
->hIconSm
= (HANDLE
)NewLong
;
1741 /* update the clones */
1742 Class
= Class
->Clone
;
1743 while (Class
!= NULL
)
1745 Class
->hIconSm
= (HANDLE
)NewLong
;
1746 Class
= Class
->Next
;
1751 Ret
= (ULONG_PTR
)Class
->hInstance
;
1752 Class
->hInstance
= (HINSTANCE
)NewLong
;
1754 /* update the clones */
1755 Class
= Class
->Clone
;
1756 while (Class
!= NULL
)
1758 Class
->hInstance
= (HINSTANCE
)NewLong
;
1759 Class
= Class
->Next
;
1765 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1767 if (!IntSetClassMenuName(Class
,
1770 DPRINT("Setting the class menu name failed!\n");
1773 /* FIXME - really return NULL? Wine does so... */
1778 Ret
= (ULONG_PTR
)Class
->Style
;
1779 Class
->Style
= (UINT
)NewLong
;
1781 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1782 move the class to the appropriate list? For now, we save
1783 the original value in Class->Global, so we can always
1784 locate the appropriate list */
1786 /* update the clones */
1787 Class
= Class
->Clone
;
1788 while (Class
!= NULL
)
1790 Class
->Style
= (UINT
)NewLong
;
1791 Class
= Class
->Next
;
1796 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1803 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1805 Ret
= (ULONG_PTR
)Class
->Atom
;
1806 if (!IntSetClassAtom(Class
,
1815 SetLastWin32Error(ERROR_INVALID_INDEX
);
1823 UserGetClassInfo(IN PWINDOWCLASS Class
,
1824 OUT PWNDCLASSEXW lpwcx
,
1826 HINSTANCE hInstance
)
1830 lpwcx
->style
= Class
->Style
;
1832 pi
= GetW32ProcessInfo();
1833 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1837 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1838 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1839 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1840 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1841 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1844 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1846 lpwcx
->lpszMenuName
= Class
->MenuName
;
1848 if (Class
->hInstance
== pi
->hModUser
)
1849 lpwcx
->hInstance
= NULL
;
1851 lpwcx
->hInstance
= Class
->hInstance
;
1853 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1855 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1861 UserRegisterSystemClasses(IN ULONG Count
,
1862 IN PREGISTER_SYSCLASS SystemClasses
)
1864 /* NOTE: This routine may raise exceptions! */
1866 UNICODE_STRING ClassName
, MenuName
;
1867 PPROCESSINFO pi
= GetW32ProcessInfo();
1872 if (pi
->RegisteredSysClasses
|| pi
->hModUser
== NULL
)
1875 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1877 for (i
= 0; i
!= Count
; i
++)
1879 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1880 if (ClassName
.Length
!= 0)
1882 ProbeForRead(ClassName
.Buffer
,
1887 wc
.cbSize
= sizeof(wc
);
1888 wc
.style
= SystemClasses
[i
].Style
;
1889 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1891 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1892 wc
.hInstance
= pi
->hModUser
;
1894 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1895 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1896 wc
.lpszMenuName
= NULL
;
1897 wc
.lpszClassName
= ClassName
.Buffer
;
1900 Class
= IntCreateClass(&wc
,
1903 SystemClasses
[i
].ProcA
,
1904 REGISTERCLASS_SYSTEM
,
1911 Class
->fnID
= SystemClasses
[i
].ClassId
;
1912 if (LockupFnIdToiCls(Class
->fnID
, &iCls
))
1914 gpsi
->atomSysClass
[iCls
] = Class
->Atom
;
1917 ASSERT(Class
->System
);
1918 Class
->Next
= pi
->SystemClassList
;
1919 (void)InterlockedExchangePointer((PVOID
*)&pi
->SystemClassList
,
1924 WARN("!!! Registering system class failed!\n");
1930 pi
->RegisteredSysClasses
= TRUE
;
1934 /* SYSCALLS *****************************************************************/
1938 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1939 IN PUNICODE_STRING ClassName
,
1940 IN PUNICODE_STRING MenuName
,
1947 * Registers a new class with the window manager
1949 * lpwcx = Win32 extended window class structure
1950 * bUnicodeClass = Whether to send ANSI or unicode strings
1951 * to window procedures
1952 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1954 * Atom identifying the new class
1957 WNDCLASSEXW CapturedClassInfo
= {0};
1958 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1959 RTL_ATOM Ret
= (RTL_ATOM
)0;
1961 if (Flags
& ~REGISTERCLASS_ALL
)
1963 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1967 UserEnterExclusive();
1971 /* Probe the parameters and basic parameter checks */
1972 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1974 goto InvalidParameter
;
1978 sizeof(WNDCLASSEXW
),
1980 RtlCopyMemory(&CapturedClassInfo
,
1982 sizeof(WNDCLASSEXW
));
1984 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1985 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1987 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1988 CapturedClassInfo
.cbClsExtra
< 0 ||
1989 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1990 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1991 CapturedClassInfo
.cbWndExtra
< 0 ||
1992 CapturedClassInfo
.hInstance
== NULL
)
1994 goto InvalidParameter
;
1997 if (CapturedName
.Length
!= 0)
1999 ProbeForRead(CapturedName
.Buffer
,
2000 CapturedName
.Length
,
2005 if (!IS_ATOM(CapturedName
.Buffer
))
2007 goto InvalidParameter
;
2011 if (CapturedMenuName
.Length
!= 0)
2013 ProbeForRead(CapturedMenuName
.Buffer
,
2014 CapturedMenuName
.Length
,
2017 else if (CapturedMenuName
.Buffer
!= NULL
&&
2018 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2021 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2025 /* Register the class */
2026 Ret
= UserRegisterClass(&CapturedClassInfo
,
2029 hMenu
, /* FIXME - pass pointer */
2034 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2036 SetLastNtError(_SEH2_GetExceptionCode());
2048 NtUserRegisterClassExWOW(
2050 PUNICODE_STRING ClassName
,
2051 PUNICODE_STRING ClsNVersion
,
2052 PCLSMENUNAME pClassMenuName
,
2057 WNDCLASSEXW CapturedClassInfo
= {0};
2058 UNICODE_STRING CapturedName
= {0}, ClassnametoVersion
= {0};
2059 RTL_ATOM Ret
= (RTL_ATOM
)0;
2061 UserEnterExclusive();
2065 /* Probe the parameters and basic parameter checks */
2066 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2068 goto InvalidParameter
;
2070 if (!pClassMenuName
)
2072 goto InvalidParameter
;
2076 sizeof(WNDCLASSEXW
),
2078 RtlCopyMemory(&CapturedClassInfo
,
2080 sizeof(WNDCLASSEXW
));
2082 Need to watch this. When UnregisterClass is called these pointers
2083 are freed by the caller in user space. So, we just probe the data
2084 for now and pass it on and copy it to the shared class structure.
2086 ProbeForRead(pClassMenuName
,
2087 sizeof(CLSMENUNAME
),
2090 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2091 ClassnametoVersion
= ProbeForReadUnicodeString(ClsNVersion
);
2093 if (CapturedName
.Length
& 1 || ClassnametoVersion
.Length
& 1 ||
2094 CapturedClassInfo
.cbClsExtra
< 0 ||
2095 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2096 ClassnametoVersion
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
2097 CapturedClassInfo
.cbWndExtra
< 0 ||
2098 CapturedClassInfo
.hInstance
== NULL
)
2100 goto InvalidParameter
;
2103 if (CapturedName
.Length
!= 0)
2105 ProbeForRead(CapturedName
.Buffer
,
2106 CapturedName
.Length
,
2111 if (!IS_ATOM(CapturedName
.Buffer
))
2113 goto InvalidParameter
;
2117 if (ClassnametoVersion
.Length
!= 0)
2119 ProbeForRead(ClassnametoVersion
.Buffer
,
2120 ClassnametoVersion
.Length
,
2123 else if (ClassnametoVersion
.Buffer
!= NULL
&&
2124 !IS_INTRESOURCE(ClassnametoVersion
.Buffer
))
2127 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2131 /* Register the class */
2132 // Ret = UserRegisterClass(&CapturedClassInfo,
2134 // &ClassnametoVersion,
2135 // hMenu, /* FIXME - pass pointer */
2140 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2142 SetLastNtError(_SEH2_GetExceptionCode());
2153 NtUserGetClassLong(IN HWND hWnd
,
2157 PWINDOW_OBJECT Window
;
2160 if (Offset
!= GCLP_WNDPROC
)
2166 UserEnterExclusive();
2169 Window
= UserGetWindowObject(hWnd
);
2172 Ret
= UserGetClassLongPtr(Window
->Wnd
->Class
,
2176 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->Class
->MenuNameIsString
)
2178 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2190 NtUserSetClassLong(HWND hWnd
,
2192 ULONG_PTR dwNewLong
,
2196 PWINDOW_OBJECT Window
;
2199 UserEnterExclusive();
2201 pi
= GetW32ProcessInfo();
2205 Window
= UserGetWindowObject(hWnd
);
2208 if (Window
->ti
->ppi
!= pi
)
2210 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2216 UNICODE_STRING Value
;
2218 /* probe the parameters */
2219 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2221 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2222 if (Value
.Length
& 1)
2224 goto InvalidParameter
;
2227 if (Value
.Length
!= 0)
2229 ProbeForRead(Value
.Buffer
,
2235 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2237 goto InvalidParameter
;
2239 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2242 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2247 dwNewLong
= (ULONG_PTR
)&Value
;
2250 Ret
= UserSetClassLongPtr(Window
->Wnd
->Class
,
2255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2257 SetLastNtError(_SEH2_GetExceptionCode());
2279 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2280 IN HINSTANCE hInstance
,
2281 OUT PCLSMENUNAME pClassMenuName
)
2283 UNICODE_STRING CapturedClassName
;
2286 UserEnterExclusive();
2290 /* probe the paramters */
2291 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2292 if (CapturedClassName
.Length
& 1)
2294 goto InvalidParameter
;
2297 if (CapturedClassName
.Length
!= 0)
2299 ProbeForRead(CapturedClassName
.Buffer
,
2300 CapturedClassName
.Length
,
2305 if (!IS_ATOM(CapturedClassName
.Buffer
))
2308 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2313 /* unregister the class */
2314 Ret
= UserUnregisterClass(&CapturedClassName
,
2317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2319 SetLastNtError(_SEH2_GetExceptionCode());
2328 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2331 HINSTANCE hInstance
,
2332 PUNICODE_STRING ClassName
,
2333 LPWNDCLASSEXW lpWndClassEx
,
2334 LPWSTR
*ppszMenuName
,
2337 UNICODE_STRING CapturedClassName
;
2343 /* NOTE: need exclusive lock because getting the wndproc might require the
2344 creation of a call procedure handle */
2345 UserEnterExclusive();
2347 pi
= GetW32ProcessInfo();
2350 ERR("GetW32ProcessInfo() returned NULL!\n");
2355 /* probe the paramters */
2356 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2358 if (CapturedClassName
.Length
== 0)
2359 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2361 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2363 if (CapturedClassName
.Length
& 1)
2365 goto InvalidParameter
;
2368 if (CapturedClassName
.Length
!= 0)
2370 ProbeForRead(CapturedClassName
.Buffer
,
2371 CapturedClassName
.Length
,
2376 if (!IS_ATOM(CapturedClassName
.Buffer
))
2378 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2379 goto InvalidParameter
;
2383 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2386 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2390 ProbeForWrite(lpWndClassEx
,
2391 sizeof(WNDCLASSEXW
),
2394 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2399 if (ClassAtom
!= (RTL_ATOM
)0)
2401 if (hInstance
== NULL
)
2402 hInstance
= pi
->hModUser
;
2404 Ret
= UserGetClassInfo(Class
,
2411 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2412 /* FIXME - handle Class->Desktop == NULL!!!!! */
2414 if (Class
->MenuName
!= NULL
&& Class
->MenuNameIsString
)
2416 lpWndClassEx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2417 (PVOID
)Class
->AnsiMenuName
:
2418 (PVOID
)Class
->MenuName
);
2421 /* Undocumented behavior! Return the class atom as a BOOL! */
2422 Ret
= (BOOL
)ClassAtom
;
2426 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2430 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2442 NtUserGetClassName (IN HWND hWnd
,
2443 OUT PUNICODE_STRING ClassName
,
2446 PWINDOW_OBJECT Window
;
2447 UNICODE_STRING CapturedClassName
;
2452 Window
= UserGetWindowObject(hWnd
);
2457 ProbeForWriteUnicodeString(ClassName
);
2458 CapturedClassName
= *ClassName
;
2460 /* get the class name */
2461 Ret
= UserGetClassName(Window
->Wnd
->Class
,
2467 /* update the Length field */
2468 ClassName
->Length
= CapturedClassName
.Length
;
2471 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2473 SetLastNtError(_SEH2_GetExceptionCode());
2484 NtUserGetWOWClass(DWORD Unknown0
,