2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsys/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
8 * 06-06-2001 CSH Created
10 /* INCLUDES ******************************************************************/
20 PCLS SystemClassList
= NULL
;
21 BOOL RegisteredSysClasses
= FALSE
;
29 { FNID_BUTTON
, ICLS_BUTTON
},
30 { FNID_EDIT
, ICLS_EDIT
},
31 { FNID_STATIC
, ICLS_STATIC
},
32 { FNID_LISTBOX
, ICLS_LISTBOX
},
33 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
34 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
35 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
36 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
37 { FNID_DIALOG
, ICLS_DIALOG
},
38 { FNID_MENU
, ICLS_MENU
},
39 { FNID_ICONTITLE
, ICLS_ICONTITLE
}
45 LockupFnIdToiCls(int FnId
, int *iCls
)
49 for ( i
= 0; i
< (sizeof(FnidToiCls
)/2)/sizeof(int); i
++)
51 if (FnidToiCls
[i
].FnId
== FnId
)
53 *iCls
= FnidToiCls
[i
].ClsId
;
60 /* WINDOWCLASS ***************************************************************/
63 IntFreeClassMenuName(IN OUT PCLS Class
)
65 /* free the menu name, if it was changed and allocated */
66 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
68 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
69 Class
->lpszClientUnicodeMenuName
= NULL
;
70 Class
->lpszClientAnsiMenuName
= NULL
;
75 IntDestroyClass(IN OUT PCLS Class
)
77 /* there shouldn't be any clones anymore */
78 ASSERT(Class
->cWndReferenceCount
== 0);
79 ASSERT(Class
->pclsClone
== NULL
);
81 if (Class
->pclsBase
== Class
)
83 PCALLPROCDATA CallProc
, NextCallProc
;
85 /* Destroy allocated callproc handles */
86 CallProc
= Class
->spcpdFirst
;
87 while (CallProc
!= NULL
)
89 NextCallProc
= CallProc
->spcpdNext
;
91 CallProc
->spcpdNext
= NULL
;
95 CallProc
= NextCallProc
;
100 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
104 IntFreeClassMenuName(Class
);
107 /* free the structure */
108 if (Class
->rpdeskParent
!= NULL
)
110 DesktopHeapFree(Class
->rpdeskParent
,
120 /* clean all process classes. all process windows must cleaned first!! */
121 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
124 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
128 /* free all local classes */
129 Class
= pi
->pclsPrivateList
;
130 while (Class
!= NULL
)
132 pi
->pclsPrivateList
= Class
->pclsNext
;
134 ASSERT(Class
->pclsBase
== Class
);
135 IntDestroyClass(Class
);
137 Class
= pi
->pclsPrivateList
;
140 /* free all global classes */
141 Class
= pi
->pclsPublicList
;
142 while (Class
!= NULL
)
144 pi
->pclsPublicList
= Class
->pclsNext
;
146 ASSERT(Class
->pclsBase
== Class
);
147 IntDestroyClass(Class
);
149 Class
= pi
->pclsPublicList
;
155 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
162 if (ClassName
->Length
!= 0)
164 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
165 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
167 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
174 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
178 AtomName
= ClassName
->Buffer
;
180 /* If an Atom, need to verify, if it was already added to the global atom list. */
181 if (IS_ATOM(AtomName
))
183 *pAtom
= (RTL_ATOM
)((ULONG_PTR
)AtomName
);
184 Status
= RtlQueryAtomInAtomTable( gAtomTable
,
191 if (NT_SUCCESS(Status
)) return TRUE
;
194 Status
= RtlAddAtomToAtomTable(gAtomTable
,
198 if (!NT_SUCCESS(Status
))
200 SetLastNtError(Status
);
208 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
210 return RtlDeleteAtomFromAtomTable(gAtomTable
,
215 UserFindCallProc(IN PCLS Class
,
219 PCALLPROCDATA CallProc
;
221 CallProc
= Class
->spcpdFirst
;
222 while (CallProc
!= NULL
)
224 if (CallProc
->pfnClientPrevious
== WndProc
&&
225 CallProc
->Unicode
== (UINT
)bUnicode
)
230 CallProc
= CallProc
->spcpdNext
;
237 UserAddCallProcToClass(IN OUT PCLS Class
,
238 IN PCALLPROCDATA CallProc
)
242 ASSERT(CallProc
->spcpdNext
== NULL
);
244 BaseClass
= Class
->pclsBase
;
245 ASSERT(CallProc
->spcpdNext
== NULL
);
246 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
247 BaseClass
->spcpdFirst
= CallProc
;
249 /* Update all clones */
250 Class
= Class
->pclsClone
;
251 while (Class
!= NULL
)
253 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
254 Class
= Class
->pclsNext
;
259 IntSetClassAtom(IN OUT PCLS Class
,
260 IN PUNICODE_STRING ClassName
)
262 RTL_ATOM Atom
= (RTL_ATOM
)0;
264 /* update the base class first */
265 Class
= Class
->pclsBase
;
267 if (!IntRegisterClassAtom(ClassName
,
273 IntDeregisterClassAtom(Class
->atomClassName
);
275 Class
->atomClassName
= Atom
;
277 /* update the clones */
278 Class
= Class
->pclsClone
;
279 while (Class
!= NULL
)
281 Class
->atomClassName
= Atom
;
283 Class
= Class
->pclsNext
;
290 IntGetClassWndProc(IN PCLS Class
,
292 IN BOOL Ansi
) // This is what we are looking for?!?
294 ASSERT(UserIsEnteredExclusive() == TRUE
);
298 // FIXME! System class have gpsi->apfnClientA/W to pick from.
299 return (Ansi
? Class
->WndProcExtra
: Class
->lpfnWndProc
);
303 if (!Ansi
== Class
->Unicode
)
305 return Class
->lpfnWndProc
;
311 /* make sure the call procedures are located on the desktop
312 of the base class! */
313 BaseClass
= Class
->pclsBase
;
316 if (Class
->CallProc
!= NULL
)
318 return GetCallProcHandle(Class
->CallProc
);
322 PCALLPROCDATA NewCallProc
;
327 NewCallProc
= UserFindCallProc(Class
,
330 if (NewCallProc
== NULL
)
332 NewCallProc
= CreateCallProc(NULL
,
336 if (NewCallProc
== NULL
)
338 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
342 UserAddCallProcToClass(Class
,
346 Class
->CallProc
= NewCallProc
;
348 /* update the clones */
349 Class
= Class
->pclsClone
;
350 while (Class
!= NULL
)
352 Class
->CallProc
= NewCallProc
;
354 Class
= Class
->pclsNext
;
357 return GetCallProcHandle(NewCallProc
);
364 IntSetClassWndProc(IN OUT PCLS Class
,
372 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->atomClassName
);
373 SetLastWin32Error(ERROR_ACCESS_DENIED
);
377 /* update the base class first */
378 Class
= Class
->pclsBase
;
380 /* resolve any callproc handle if possible */
381 if (IsCallProcHandle(WndProc
))
385 if (UserGetCallProcInfo((HANDLE
)WndProc
,
388 WndProc
= wpInfo
.WindowProc
;
389 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
393 Ret
= IntGetClassWndProc(Class
,
401 /* update the class info */
402 Class
->Unicode
= !Ansi
;
403 Class
->lpfnWndProc
= WndProc
;
405 /* update the clones */
406 Class
= Class
->pclsClone
;
407 while (Class
!= NULL
)
409 Class
->Unicode
= !Ansi
;
410 Class
->lpfnWndProc
= WndProc
;
412 Class
= Class
->pclsNext
;
419 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
420 IN OUT PCLS
*ClassLink
,
426 ASSERT(Desktop
!= NULL
);
427 ASSERT(BaseClass
->pclsBase
== BaseClass
);
429 if (BaseClass
->rpdeskParent
== Desktop
)
431 /* it is most likely that a window is created on the same
432 desktop as the window class. */
437 if (BaseClass
->rpdeskParent
== NULL
)
439 ASSERT(BaseClass
->cWndReferenceCount
== 0);
440 ASSERT(BaseClass
->pclsClone
== NULL
);
442 /* Classes are also located in the shared heap when the class
443 was created before the thread attached to a desktop. As soon
444 as a window is created for such a class located on the shared
445 heap, the class is cloned into the desktop heap on which the
446 window is created. */
451 /* The user is asking for a class object on a different desktop,
453 Class
= BaseClass
->pclsClone
;
454 while (Class
!= NULL
)
456 if (Class
->rpdeskParent
== Desktop
)
458 ASSERT(Class
->pclsBase
== BaseClass
);
459 ASSERT(Class
->pclsClone
== NULL
);
463 Class
= Class
->pclsNext
;
469 /* The window is created on a different desktop, we need to
470 clone the class object to the desktop heap of the window! */
471 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
473 Class
= DesktopHeapAlloc(Desktop
,
477 /* simply clone the class */
482 /* update some pointers and link the class */
483 Class
->rpdeskParent
= Desktop
;
484 Class
->cWndReferenceCount
= 0;
486 if (BaseClass
->rpdeskParent
== NULL
)
488 /* we don't really need the base class on the shared
489 heap anymore, delete it so the only class left is
490 the clone we just created, which now serves as the
492 ASSERT(BaseClass
->pclsClone
== NULL
);
493 ASSERT(Class
->pclsClone
== NULL
);
494 Class
->pclsBase
= Class
;
495 Class
->pclsNext
= BaseClass
->pclsNext
;
497 /* replace the base class */
498 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
501 /* destroy the obsolete copy on the shared heap */
502 BaseClass
->pclsBase
= NULL
;
503 BaseClass
->pclsClone
= NULL
;
504 IntDestroyClass(BaseClass
);
508 /* link in the clone */
509 Class
->pclsClone
= NULL
;
510 Class
->pclsBase
= BaseClass
;
511 Class
->pclsNext
= BaseClass
->pclsClone
;
512 (void)InterlockedExchangePointer(&BaseClass
->pclsClone
,
518 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
526 IntReferenceClass(IN OUT PCLS BaseClass
,
527 IN OUT PCLS
*ClassLink
,
532 ASSERT(BaseClass
->pclsBase
== BaseClass
);
534 Class
= IntGetClassForDesktop(BaseClass
,
539 Class
->cWndReferenceCount
++;
546 IntMakeCloneBaseClass(IN OUT PCLS Class
,
547 IN OUT PCLS
*BaseClassLink
,
548 IN OUT PCLS
*CloneLink
)
550 PCLS Clone
, BaseClass
;
552 ASSERT(Class
->pclsBase
!= Class
);
553 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
554 ASSERT(Class
->rpdeskParent
!= NULL
);
555 ASSERT(Class
->cWndReferenceCount
!= 0);
556 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
557 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
559 /* unlink the clone */
560 *CloneLink
= Class
->pclsNext
;
561 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
563 BaseClass
= Class
->pclsBase
;
565 /* update the class information to make it a base class */
566 Class
->pclsBase
= Class
;
567 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
569 /* update all clones */
570 Clone
= Class
->pclsClone
;
571 while (Clone
!= NULL
)
573 ASSERT(Clone
->pclsClone
== NULL
);
574 Clone
->pclsBase
= Class
;
577 Clone
->CallProc
= Class
->CallProc
;
579 Clone
= Clone
->pclsNext
;
582 /* link in the new base class */
583 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
588 IntDereferenceClass(IN OUT PCLS Class
,
589 IN PDESKTOPINFO Desktop
,
592 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
594 BaseClass
= Class
->pclsBase
;
596 if (--Class
->cWndReferenceCount
== 0)
598 if (BaseClass
== Class
)
600 ASSERT(Class
->pclsBase
== Class
);
602 /* check if there are clones of the class on other desktops,
603 link the first clone in if possible. If there are no clones
604 then leave the class on the desktop heap. It will get moved
605 to the shared heap when the thread detaches. */
606 if (BaseClass
->pclsClone
!= NULL
)
608 if (BaseClass
->System
)
609 PrevLink
= &SystemClassList
;
610 else if (BaseClass
->Global
)
611 PrevLink
= &pi
->pclsPublicList
;
613 PrevLink
= &pi
->pclsPrivateList
;
615 CurrentClass
= *PrevLink
;
616 while (CurrentClass
!= BaseClass
)
618 ASSERT(CurrentClass
!= NULL
);
620 PrevLink
= &CurrentClass
->pclsNext
;
621 CurrentClass
= CurrentClass
->pclsNext
;
624 ASSERT(*PrevLink
== BaseClass
);
626 /* make the first clone become the new base class */
627 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
629 &BaseClass
->pclsClone
);
631 /* destroy the class, there's still another clone of the class
632 that now serves as a base class. Make sure we don't destruct
633 resources shared by all classes (Base = NULL)! */
634 BaseClass
->pclsBase
= NULL
;
635 BaseClass
->pclsClone
= NULL
;
636 IntDestroyClass(BaseClass
);
641 /* locate the cloned class and unlink it */
642 PrevLink
= &BaseClass
->pclsClone
;
643 CurrentClass
= BaseClass
->pclsClone
;
644 while (CurrentClass
!= Class
)
646 ASSERT(CurrentClass
!= NULL
);
648 PrevLink
= &CurrentClass
->pclsNext
;
649 CurrentClass
= CurrentClass
->pclsNext
;
652 ASSERT(CurrentClass
== Class
);
654 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
657 ASSERT(Class
->pclsBase
== BaseClass
);
658 ASSERT(Class
->pclsClone
== NULL
);
660 /* the class was just a clone, we don't need it anymore */
661 IntDestroyClass(Class
);
667 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
668 IN OUT PCLS
**ClassLinkPtr
)
673 ASSERT(Class
->pclsBase
== Class
);
674 ASSERT(Class
->rpdeskParent
!= NULL
);
675 ASSERT(Class
->cWndReferenceCount
== 0);
676 ASSERT(Class
->pclsClone
== NULL
);
678 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
680 /* allocate the new base class on the shared heap */
681 NewClass
= UserHeapAlloc(ClassSize
);
682 if (NewClass
!= NULL
)
684 RtlCopyMemory(NewClass
,
688 NewClass
->rpdeskParent
= NULL
;
689 NewClass
->pclsBase
= NewClass
;
691 /* replace the class in the list */
692 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
694 *ClassLinkPtr
= &NewClass
->pclsNext
;
696 /* free the obsolete class on the desktop heap */
697 Class
->pclsBase
= NULL
;
698 IntDestroyClass(Class
);
706 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
707 IN OUT PCLS
*ClassList
,
708 IN BOOL FreeOnFailure
,
711 PCLS Class
, NextClass
, *Link
;
713 /* NOTE: We only need to check base classes! When classes are no longer needed
714 on a desktop, the clones will be freed automatically as soon as possible.
715 However, we need to move base classes to the shared heap, as soon as
716 the last desktop heap where a class is allocated on is about to be destroyed.
717 If we didn't move the class to the shared heap, the class would become
720 ASSERT(Desktop
!= NULL
);
724 while (Class
!= NULL
)
726 NextClass
= Class
->pclsNext
;
728 ASSERT(Class
->pclsBase
== Class
);
730 if (Class
->rpdeskParent
== Desktop
&&
731 Class
->cWndReferenceCount
== 0)
733 /* there shouldn't be any clones around anymore! */
734 ASSERT(Class
->pclsClone
== NULL
);
736 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
737 /* FIXME - We could move the class to another desktop heap if there's still desktops
738 mapped into the process... */
740 /* move the class to the shared heap */
741 if (IntMoveClassToSharedHeap(Class
,
744 ASSERT(*Link
== NextClass
);
748 ASSERT(NextClass
== Class
->pclsNext
);
752 /* unlink the base class */
753 (void)InterlockedExchangePointer((PVOID
*)Link
,
756 /* we can free the old base class now */
757 Class
->pclsBase
= NULL
;
758 IntDestroyClass(Class
);
762 Link
= &Class
->pclsNext
;
768 Link
= &Class
->pclsNext
;
775 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
776 IN BOOL FreeOnFailure
)
781 pi
= GetW32ProcessInfo();
785 /* check all local classes */
786 IntCheckDesktopClasses(Desktop
,
787 &pi
->pclsPrivateList
,
791 /* check all global classes */
792 IntCheckDesktopClasses(Desktop
,
797 /* check all system classes */
798 IntCheckDesktopClasses(Desktop
,
805 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
806 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
814 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
815 IN PUNICODE_STRING ClassName
,
816 IN PUNICODE_STRING MenuName
,
825 PWSTR pszMenuName
= NULL
;
826 NTSTATUS Status
= STATUS_SUCCESS
;
828 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
829 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
831 if (!IntRegisterClassAtom(ClassName
,
834 DPRINT1("Failed to register class atom!\n");
838 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
839 if (MenuName
->Length
!= 0)
841 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
842 RtlUnicodeStringToAnsiSize(MenuName
));
843 if (pszMenuName
== NULL
)
849 Class
= DesktopHeapAlloc(Desktop
,
854 /* FIXME - the class was created before being connected
855 to a desktop. It is possible for the desktop window,
856 but should it be allowed for any other case? */
857 Class
= UserHeapAlloc(ClassSize
);
865 Class
->rpdeskParent
= Desktop
;
866 Class
->pclsBase
= Class
;
867 Class
->atomClassName
= Atom
;
869 Class
->CSF_flags
= dwFlags
;
871 if (dwFlags
& CSF_SYSTEMCLASS
)
873 dwFlags
&= ~CSF_ANSIPROC
;
874 Class
->WndProcExtra
= wpExtra
;
875 Class
->System
= TRUE
;
880 PWSTR pszMenuNameBuffer
= pszMenuName
;
882 /* need to protect with SEH since accessing the WNDCLASSEX structure
883 and string buffers might raise an exception! We don't want to
885 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
886 Class
->style
= lpwcx
->style
;
887 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
888 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
889 Class
->hModule
= lpwcx
->hInstance
;
890 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
891 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
892 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
893 Class
->hbrBackground
= lpwcx
->hbrBackground
;
896 /* make a copy of the string */
897 if (pszMenuNameBuffer
!= NULL
)
899 Class
->MenuNameIsString
= TRUE
;
901 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
902 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
905 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
907 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
910 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
912 /* save an ansi copy of the string */
913 if (pszMenuNameBuffer
!= NULL
)
915 ANSI_STRING AnsiString
;
917 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
918 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
919 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
920 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
923 if (!NT_SUCCESS(Status
))
925 DPRINT1("Failed to convert unicode menu name to ansi!\n");
927 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
932 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
934 /* Save kernel use menu name and ansi class name */
935 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
936 //Class->lpszAnsiClassName = Fixme!
938 if (!(dwFlags
& CSF_ANSIPROC
))
939 Class
->Unicode
= TRUE
;
941 if (Class
->style
& CS_GLOBALCLASS
)
942 Class
->Global
= TRUE
;
944 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
946 Status
= _SEH2_GetExceptionCode();
950 if (!NT_SUCCESS(Status
))
952 DPRINT1("Failed creating the class: 0x%x\n", Status
);
954 SetLastNtError(Status
);
956 if (pszMenuName
!= NULL
)
957 UserHeapFree(pszMenuName
);
959 DesktopHeapFree(Desktop
,
963 IntDeregisterClassAtom(Atom
);
969 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
971 if (pszMenuName
!= NULL
)
972 UserHeapFree(pszMenuName
);
974 IntDeregisterClassAtom(Atom
);
976 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
983 IntFindClass(IN RTL_ATOM Atom
,
984 IN HINSTANCE hInstance
,
986 OUT PCLS
**Link OPTIONAL
)
988 PCLS Class
, *PrevLink
= ClassList
;
991 while (Class
!= NULL
)
993 if (Class
->atomClassName
== Atom
&&
994 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
997 ASSERT(Class
->pclsBase
== Class
);
1004 PrevLink
= &Class
->pclsNext
;
1005 Class
= Class
->pclsNext
;
1012 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1017 if (ClassName
->Length
!= 0)
1023 /* NOTE: Caller has to protect the call with SEH! */
1025 if (ClassName
->Length
!= 0)
1027 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1028 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1030 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1034 /* We need to make a local copy of the class name! The caller could
1035 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1036 We're protected by SEH, but the ranges that might be accessed were
1038 RtlCopyMemory(szBuf
,
1041 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1045 AtomName
= ClassName
->Buffer
;
1047 /* lookup the atom */
1048 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1051 if (NT_SUCCESS(Status
))
1057 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1059 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1063 SetLastNtError(Status
);
1069 ASSERT(IS_ATOM(ClassName
->Buffer
));
1070 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1078 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1079 IN HINSTANCE hInstance OPTIONAL
,
1080 IN PPROCESSINFO pi OPTIONAL
,
1081 OUT PCLS
*BaseClass OPTIONAL
,
1082 OUT PCLS
**Link OPTIONAL
)
1084 RTL_ATOM Atom
= (RTL_ATOM
)0;
1086 ASSERT(BaseClass
!= NULL
);
1088 if (IntGetAtomFromStringOrAtom(ClassName
,
1090 Atom
!= (RTL_ATOM
)0)
1094 /* attempt to locate the class object */
1098 /* Step 1: try to find an exact match of locally registered classes */
1099 Class
= IntFindClass(Atom
,
1101 &pi
->pclsPrivateList
,
1108 /* Step 2: try to find any globally registered class. The hInstance
1109 is not relevant for global classes */
1110 Class
= IntFindClass(Atom
,
1112 &pi
->pclsPublicList
,
1119 /* Step 3: try to find any local class registered by user32 */
1120 Class
= IntFindClass(Atom
,
1122 &pi
->pclsPrivateList
,
1129 /* Step 4: try to find any global class registered by user32 */
1130 Class
= IntFindClass(Atom
,
1132 &pi
->pclsPublicList
,
1139 /* Step 5: try to find a system class */
1140 Class
= IntFindClass(Atom
,
1146 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1158 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1159 IN PUNICODE_STRING ClassName
,
1160 IN PUNICODE_STRING MenuName
,
1169 RTL_ATOM Ret
= (RTL_ATOM
)0;
1171 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1173 pti
= PsGetCurrentThreadWin32Thread();
1174 ti
= GetW32ThreadInfo();
1175 if (ti
== NULL
|| !RegisteredSysClasses
)
1177 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1183 /* try to find a previously registered class */
1184 ClassAtom
= IntGetClassAtom(ClassName
,
1189 if (ClassAtom
!= (RTL_ATOM
)0)
1191 if (lpwcx
->style
& CS_GLOBALCLASS
)
1193 // global classes shall not have same names as system classes
1194 if (Class
->Global
|| Class
->System
)
1196 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1197 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1201 else if ( !Class
->Global
&& !Class
->System
)
1203 // local class already exists
1204 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1205 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1210 Class
= IntCreateClass(lpwcx
,
1222 /* Register the class */
1224 List
= &SystemClassList
;
1225 else if (Class
->Global
)
1226 List
= &pi
->pclsPublicList
;
1228 List
= &pi
->pclsPrivateList
;
1230 Class
->pclsNext
= *List
;
1231 (void)InterlockedExchangePointer((PVOID
*)List
,
1234 Ret
= Class
->atomClassName
;
1241 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1242 IN HINSTANCE hInstance
)
1249 pi
= GetW32ProcessInfo();
1252 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1256 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1258 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1259 ClassAtom
= IntGetClassAtom(ClassName
,
1264 if (ClassAtom
== (RTL_ATOM
)0)
1269 ASSERT(Class
!= NULL
);
1271 if (Class
->cWndReferenceCount
!= 0 ||
1272 Class
->pclsClone
!= NULL
)
1274 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1278 /* must be a base class! */
1279 ASSERT(Class
->pclsBase
== Class
);
1281 /* unlink the class */
1282 *Link
= Class
->pclsNext
;
1284 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1286 /* finally free the resources */
1287 IntDestroyClass(Class
);
1294 UserGetClassName(IN PCLS Class
,
1295 IN OUT PUNICODE_STRING ClassName
,
1298 NTSTATUS Status
= STATUS_SUCCESS
;
1299 WCHAR szStaticTemp
[32];
1300 PWSTR szTemp
= NULL
;
1301 ULONG BufLen
= sizeof(szStaticTemp
);
1304 /* Note: Accessing the buffer in ClassName may raise an exception! */
1310 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1311 UNICODE_STRING UnicodeClassName
;
1313 /* limit the size of the static buffer on the stack to the
1314 size of the buffer provided by the caller */
1315 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1317 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1320 /* find out how big the buffer needs to be */
1321 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1322 Class
->atomClassName
,
1327 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1329 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1331 /* the buffer required exceeds the ansi buffer provided,
1332 pretend like we're using the ansi buffer and limit the
1333 size to the buffer size provided */
1334 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1337 /* allocate a temporary buffer that can hold the unicode class name */
1338 szTemp
= ExAllocatePool(PagedPool
,
1342 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1346 /* query the class name */
1347 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1348 Class
->atomClassName
,
1355 szTemp
= szStaticTemp
;
1357 if (NT_SUCCESS(Status
))
1359 /* convert the atom name to ansi */
1361 RtlInitUnicodeString(&UnicodeClassName
,
1364 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1367 if (!NT_SUCCESS(Status
))
1369 SetLastNtError(Status
);
1374 Ret
= BufLen
/ sizeof(WCHAR
);
1378 BufLen
= ClassName
->MaximumLength
;
1380 /* query the atom name */
1381 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1382 Class
->atomClassName
,
1388 if (!NT_SUCCESS(Status
))
1390 SetLastNtError(Status
);
1394 Ret
= BufLen
/ sizeof(WCHAR
);
1397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1399 SetLastNtError(_SEH2_GetExceptionCode());
1403 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1412 UserGetClassLongPtr(IN PCLS Class
,
1422 TRACE("GetClassLong(%d)\n", Index
);
1423 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1424 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1426 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1430 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1432 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1433 certain architectures, maybe using RtlCopyMemory is a
1434 better choice for those architectures! */
1436 TRACE("Result: %x\n", Ret
);
1442 case GCL_CBWNDEXTRA
:
1443 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1446 case GCL_CBCLSEXTRA
:
1447 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
1450 case GCLP_HBRBACKGROUND
:
1451 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1455 /* FIXME - get handle from pointer to CURSOR object */
1456 Ret
= (ULONG_PTR
)Class
->hCursor
;
1460 /* FIXME - get handle from pointer to ICON object */
1461 Ret
= (ULONG_PTR
)Class
->hIcon
;
1465 /* FIXME - get handle from pointer to ICON object */
1466 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1470 Ret
= (ULONG_PTR
)Class
->hModule
;
1474 /* NOTE: Returns pointer in kernel heap! */
1476 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
1478 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
1482 Ret
= (ULONG_PTR
)Class
->style
;
1486 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1487 GetW32ProcessInfo(),
1492 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1496 SetLastWin32Error(ERROR_INVALID_INDEX
);
1504 IntSetClassMenuName(IN PCLS Class
,
1505 IN PUNICODE_STRING MenuName
)
1509 /* change the base class first */
1510 Class
= Class
->pclsBase
;
1512 if (MenuName
->Length
!= 0)
1514 ANSI_STRING AnsiString
;
1517 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1519 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1520 AnsiString
.MaximumLength
);
1521 if (strBufW
!= NULL
)
1527 /* copy the unicode string */
1528 RtlCopyMemory(strBufW
,
1531 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1533 /* create an ansi copy of the string */
1534 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1535 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1538 if (!NT_SUCCESS(Status
))
1540 SetLastNtError(Status
);
1546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1548 SetLastNtError(_SEH2_GetExceptionCode());
1554 /* update the base class */
1555 IntFreeClassMenuName(Class
);
1556 Class
->lpszClientUnicodeMenuName
= strBufW
;
1557 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1558 Class
->MenuNameIsString
= TRUE
;
1560 /* update the clones */
1561 Class
= Class
->pclsClone
;
1562 while (Class
!= NULL
)
1564 Class
->lpszClientUnicodeMenuName
= strBufW
;
1565 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1566 Class
->MenuNameIsString
= TRUE
;
1568 Class
= Class
->pclsNext
;
1573 DPRINT1("Failed to copy class menu name!\n");
1574 UserHeapFree(strBufW
);
1578 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1582 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1584 /* update the base class */
1585 IntFreeClassMenuName(Class
);
1586 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1587 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1588 Class
->MenuNameIsString
= FALSE
;
1590 /* update the clones */
1591 Class
= Class
->pclsClone
;
1592 while (Class
!= NULL
)
1594 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1595 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1596 Class
->MenuNameIsString
= FALSE
;
1598 Class
= Class
->pclsNext
;
1608 UserSetClassLongPtr(IN PCLS Class
,
1610 IN ULONG_PTR NewLong
,
1615 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1617 /* change the information in the base class first, then update the clones */
1618 Class
= Class
->pclsBase
;
1624 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1626 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1627 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1629 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1633 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1635 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1636 certain architectures, maybe using RtlCopyMemory is a
1637 better choice for those architectures! */
1641 /* update the clones */
1642 Class
= Class
->pclsClone
;
1643 while (Class
!= NULL
)
1645 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1646 Class
= Class
->pclsNext
;
1654 case GCL_CBWNDEXTRA
:
1655 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1656 Class
->cbwndExtra
= (INT
)NewLong
;
1658 /* update the clones */
1659 Class
= Class
->pclsClone
;
1660 while (Class
!= NULL
)
1662 Class
->cbwndExtra
= (INT
)NewLong
;
1663 Class
= Class
->pclsNext
;
1668 case GCL_CBCLSEXTRA
:
1669 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1672 case GCLP_HBRBACKGROUND
:
1673 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1674 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1676 /* update the clones */
1677 Class
= Class
->pclsClone
;
1678 while (Class
!= NULL
)
1680 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1681 Class
= Class
->pclsNext
;
1686 /* FIXME - get handle from pointer to CURSOR object */
1687 Ret
= (ULONG_PTR
)Class
->hCursor
;
1688 Class
->hCursor
= (HANDLE
)NewLong
;
1690 /* update the clones */
1691 Class
= Class
->pclsClone
;
1692 while (Class
!= NULL
)
1694 Class
->hCursor
= (HANDLE
)NewLong
;
1695 Class
= Class
->pclsNext
;
1700 /* FIXME - get handle from pointer to ICON object */
1701 Ret
= (ULONG_PTR
)Class
->hIcon
;
1702 Class
->hIcon
= (HANDLE
)NewLong
;
1704 /* update the clones */
1705 Class
= Class
->pclsClone
;
1706 while (Class
!= NULL
)
1708 Class
->hIcon
= (HANDLE
)NewLong
;
1709 Class
= Class
->pclsNext
;
1714 /* FIXME - get handle from pointer to ICON object */
1715 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1716 Class
->hIconSm
= (HANDLE
)NewLong
;
1718 /* update the clones */
1719 Class
= Class
->pclsClone
;
1720 while (Class
!= NULL
)
1722 Class
->hIconSm
= (HANDLE
)NewLong
;
1723 Class
= Class
->pclsNext
;
1728 Ret
= (ULONG_PTR
)Class
->hModule
;
1729 Class
->hModule
= (HINSTANCE
)NewLong
;
1731 /* update the clones */
1732 Class
= Class
->pclsClone
;
1733 while (Class
!= NULL
)
1735 Class
->hModule
= (HINSTANCE
)NewLong
;
1736 Class
= Class
->pclsNext
;
1742 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1744 if (!IntSetClassMenuName(Class
,
1747 DPRINT1("Setting the class menu name failed!\n");
1750 /* FIXME - really return NULL? Wine does so... */
1755 Ret
= (ULONG_PTR
)Class
->style
;
1756 Class
->style
= (UINT
)NewLong
;
1758 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1759 move the class to the appropriate list? For now, we save
1760 the original value in Class->Global, so we can always
1761 locate the appropriate list */
1763 /* update the clones */
1764 Class
= Class
->pclsClone
;
1765 while (Class
!= NULL
)
1767 Class
->style
= (UINT
)NewLong
;
1768 Class
= Class
->pclsNext
;
1773 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1780 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1782 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1783 if (!IntSetClassAtom(Class
,
1792 SetLastWin32Error(ERROR_INVALID_INDEX
);
1800 UserGetClassInfo(IN PCLS Class
,
1801 OUT PWNDCLASSEXW lpwcx
,
1803 HINSTANCE hInstance
)
1807 lpwcx
->style
= Class
->style
;
1809 pi
= GetW32ProcessInfo();
1810 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1814 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1815 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1816 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1817 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1818 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1821 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1822 lpszClientXxxMenuName should already be mapped to user space.
1825 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1827 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1829 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1830 Class
->MenuNameIsString
)
1832 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1833 (PVOID
)Class
->lpszClientAnsiMenuName
:
1834 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1837 if (hInstance
== hModClient
)
1838 lpwcx
->hInstance
= NULL
;
1840 lpwcx
->hInstance
= hInstance
;
1842 /* FIXME - return the string? Okay! This is performed in User32!*/
1843 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1845 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1851 UserRegisterSystemClasses(IN ULONG Count
,
1852 IN PREGISTER_SYSCLASS SystemClasses
)
1854 /* NOTE: This routine may raise exceptions! */
1856 UNICODE_STRING ClassName
, MenuName
;
1857 PPROCESSINFO pi
= GetW32ProcessInfo();
1862 if ( hModClient
== NULL
)
1864 /* Init System Classes once only*/
1865 if (RegisteredSysClasses
)
1868 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1870 for (i
= 0; i
!= Count
; i
++)
1872 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1873 if (ClassName
.Length
!= 0)
1875 ProbeForRead(ClassName
.Buffer
,
1880 wc
.cbSize
= sizeof(wc
);
1881 wc
.style
= SystemClasses
[i
].Style
;
1882 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1884 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1885 wc
.hInstance
= hModClient
;
1887 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1888 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1889 wc
.lpszMenuName
= NULL
;
1890 wc
.lpszClassName
= ClassName
.Buffer
;
1893 Class
= IntCreateClass(&wc
,
1896 SystemClasses
[i
].ProcA
,
1904 Class
->fnid
= SystemClasses
[i
].ClassId
;
1905 if (LockupFnIdToiCls(Class
->fnid
, &iCls
))
1907 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1910 ASSERT(Class
->System
);
1911 Class
->pclsNext
= SystemClassList
;
1912 (void)InterlockedExchangePointer((PVOID
*)&SystemClassList
,
1917 WARN("!!! Registering system class failed!\n");
1923 RegisteredSysClasses
= TRUE
;
1927 /* SYSCALLS *****************************************************************/
1931 NtUserRegisterClassExWOW(
1933 PUNICODE_STRING ClassName
,
1934 PUNICODE_STRING ClsNVersion
,
1935 PCLSMENUNAME pClassMenuName
,
1941 * Registers a new class with the window manager
1943 * lpwcx = Win32 extended window class structure
1944 * bUnicodeClass = Whether to send ANSI or unicode strings
1945 * to window procedures
1947 * Atom identifying the new class
1950 WNDCLASSEXW CapturedClassInfo
= {0};
1951 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1952 RTL_ATOM Ret
= (RTL_ATOM
)0;
1953 WNDPROC wpExtra
= NULL
;
1955 if (Flags
& ~(CSF_ANSIPROC
))
1957 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1961 UserEnterExclusive();
1965 /* Probe the parameters and basic parameter checks */
1966 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1968 goto InvalidParameter
;
1972 sizeof(WNDCLASSEXW
),
1974 RtlCopyMemory(&CapturedClassInfo
,
1976 sizeof(WNDCLASSEXW
));
1978 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1980 ProbeForRead(pClassMenuName
,
1981 sizeof(CLSMENUNAME
),
1984 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
1986 if ( CapturedName
.Length
& 1 ||
1987 CapturedMenuName
.Length
& 1 ||
1988 CapturedClassInfo
.cbClsExtra
< 0 ||
1989 CapturedClassInfo
.cbClsExtra
+
1990 CapturedName
.Length
+
1991 CapturedMenuName
.Length
+
1992 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
1993 CapturedClassInfo
.cbWndExtra
< 0 ||
1994 CapturedClassInfo
.hInstance
== NULL
)
1996 goto InvalidParameter
;
1999 if (CapturedName
.Length
!= 0)
2001 ProbeForRead(CapturedName
.Buffer
,
2002 CapturedName
.Length
,
2007 if (!IS_ATOM(CapturedName
.Buffer
))
2009 goto InvalidParameter
;
2013 if (CapturedMenuName
.Length
!= 0)
2015 ProbeForRead(CapturedMenuName
.Buffer
,
2016 CapturedMenuName
.Length
,
2019 else if (CapturedMenuName
.Buffer
!= NULL
&&
2020 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2023 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2026 /* Register the class */
2027 Ret
= UserRegisterClass(&CapturedClassInfo
,
2033 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2035 SetLastNtError(_SEH2_GetExceptionCode());
2045 NtUserGetClassLong(IN HWND hWnd
,
2049 PWINDOW_OBJECT Window
;
2052 if (Offset
!= GCLP_WNDPROC
)
2058 UserEnterExclusive();
2061 Window
= UserGetWindowObject(hWnd
);
2064 Ret
= UserGetClassLongPtr(Window
->Wnd
->pcls
,
2068 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->pcls
->MenuNameIsString
)
2070 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2082 NtUserSetClassLong(HWND hWnd
,
2084 ULONG_PTR dwNewLong
,
2088 PWINDOW_OBJECT Window
;
2091 UserEnterExclusive();
2093 pi
= GetW32ProcessInfo();
2097 Window
= UserGetWindowObject(hWnd
);
2100 if (Window
->ti
->ppi
!= pi
)
2102 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2108 UNICODE_STRING Value
;
2110 /* probe the parameters */
2111 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2113 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2114 if (Value
.Length
& 1)
2116 goto InvalidParameter
;
2119 if (Value
.Length
!= 0)
2121 ProbeForRead(Value
.Buffer
,
2127 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2129 goto InvalidParameter
;
2131 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2134 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2139 dwNewLong
= (ULONG_PTR
)&Value
;
2142 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2147 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2149 SetLastNtError(_SEH2_GetExceptionCode());
2168 * NOTE: Obsoleted in 32-bit windows
2174 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2175 IN HINSTANCE hInstance
,
2176 OUT PCLSMENUNAME pClassMenuName
)
2178 UNICODE_STRING CapturedClassName
;
2181 UserEnterExclusive();
2185 /* probe the paramters */
2186 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2187 if (CapturedClassName
.Length
& 1)
2189 goto InvalidParameter
;
2192 if (CapturedClassName
.Length
!= 0)
2194 ProbeForRead(CapturedClassName
.Buffer
,
2195 CapturedClassName
.Length
,
2200 if (!IS_ATOM(CapturedClassName
.Buffer
))
2203 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2208 /* unregister the class */
2209 Ret
= UserUnregisterClass(&CapturedClassName
,
2212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2214 SetLastNtError(_SEH2_GetExceptionCode());
2222 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2225 HINSTANCE hInstance
,
2226 PUNICODE_STRING ClassName
,
2227 LPWNDCLASSEXW lpWndClassEx
,
2228 LPWSTR
*ppszMenuName
,
2231 UNICODE_STRING CapturedClassName
, SafeClassName
;
2232 WNDCLASSEXW Safewcexw
;
2234 RTL_ATOM ClassAtom
= 0;
2238 /* NOTE: need exclusive lock because getting the wndproc might require the
2239 creation of a call procedure handle */
2240 UserEnterExclusive();
2242 pi
= GetW32ProcessInfo();
2245 ERR("GetW32ProcessInfo() returned NULL!\n");
2251 /* probe the paramters */
2252 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2254 if (CapturedClassName
.Length
== 0)
2255 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2257 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2259 if (CapturedClassName
.Length
& 1)
2261 goto InvalidParameter
;
2264 if (CapturedClassName
.Length
!= 0)
2266 ProbeForRead( CapturedClassName
.Buffer
,
2267 CapturedClassName
.Length
,
2270 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2272 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2273 SafeClassName
.MaximumLength
,
2275 RtlCopyMemory( SafeClassName
.Buffer
,
2276 CapturedClassName
.Buffer
,
2277 SafeClassName
.MaximumLength
);
2281 if (!IS_ATOM(CapturedClassName
.Buffer
))
2283 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2284 goto InvalidParameter
;
2287 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2288 SafeClassName
.Length
= 0;
2289 SafeClassName
.MaximumLength
= 0;
2292 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2295 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2300 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2302 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2306 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2313 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2318 if (ClassAtom
!= (RTL_ATOM
)0)
2320 if (hInstance
== NULL
) hInstance
= hModClient
;
2322 Ret
= UserGetClassInfo( Class
,
2329 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2337 /* Emulate Function. */
2338 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2340 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2343 /* We must return the atom of the class here instead of just TRUE. */
2344 /* Undocumented behavior! Return the class atom as a BOOL! */
2345 Ret
= (BOOL
)ClassAtom
;
2348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2350 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2356 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2364 NtUserGetClassName (IN HWND hWnd
,
2365 OUT PUNICODE_STRING ClassName
,
2368 PWINDOW_OBJECT Window
;
2369 UNICODE_STRING CapturedClassName
;
2374 Window
= UserGetWindowObject(hWnd
);
2379 ProbeForWriteUnicodeString(ClassName
);
2380 CapturedClassName
= *ClassName
;
2382 /* get the class name */
2383 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2389 /* update the Length field */
2390 ClassName
->Length
= CapturedClassName
.Length
;
2393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2395 SetLastNtError(_SEH2_GetExceptionCode());
2405 /* Return Pointer to Class structure. */
2407 NtUserGetWOWClass(HINSTANCE hInstance
,
2408 PUNICODE_STRING ClassName
)
2410 UNICODE_STRING SafeClassName
;
2413 RTL_ATOM ClassAtom
= 0;
2416 UserEnterExclusive();
2418 pi
= GetW32ProcessInfo();
2421 ERR("GetW32ProcessInfo() returned NULL!\n");
2427 if (ClassName
->Length
!= 0)
2429 ProbeForRead( ClassName
->Buffer
,
2433 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2435 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2436 SafeClassName
.MaximumLength
,
2438 RtlCopyMemory( SafeClassName
.Buffer
,
2440 SafeClassName
.MaximumLength
);
2444 if (!IS_ATOM(ClassName
->Buffer
))
2446 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2451 SafeClassName
.Buffer
= ClassName
->Buffer
;
2452 SafeClassName
.Length
= 0;
2453 SafeClassName
.MaximumLength
= 0;
2457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2459 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2466 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2473 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2478 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2481 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.