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(PPROCESSINFO 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
,
826 PWSTR pszMenuName
= NULL
;
827 NTSTATUS Status
= STATUS_SUCCESS
;
829 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
830 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
832 if (!IntRegisterClassAtom(ClassName
,
835 DPRINT1("Failed to register class atom!\n");
839 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
840 if (MenuName
->Length
!= 0)
842 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
843 RtlUnicodeStringToAnsiSize(MenuName
));
844 if (pszMenuName
== NULL
)
850 Class
= DesktopHeapAlloc(Desktop
,
855 /* FIXME - the class was created before being connected
856 to a desktop. It is possible for the desktop window,
857 but should it be allowed for any other case? */
858 Class
= UserHeapAlloc(ClassSize
);
866 Class
->rpdeskParent
= Desktop
;
867 Class
->pclsBase
= Class
;
868 Class
->atomClassName
= Atom
;
870 Class
->CSF_flags
= dwFlags
;
872 if (dwFlags
& CSF_SYSTEMCLASS
)
876 dwFlags
&= ~CSF_ANSIPROC
;
877 Class
->WndProcExtra
= wpExtra
;
878 Class
->System
= TRUE
;
879 /* Now set the Atom table, notice only non ntuser.c atoms can go in.*/
880 if (LockupFnIdToiCls(Class
->fnid
, &iCls
))
882 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
888 PWSTR pszMenuNameBuffer
= pszMenuName
;
890 /* need to protect with SEH since accessing the WNDCLASSEX structure
891 and string buffers might raise an exception! We don't want to
893 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
894 Class
->style
= lpwcx
->style
;
895 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
896 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
897 Class
->hModule
= lpwcx
->hInstance
;
898 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
899 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
900 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
901 Class
->hbrBackground
= lpwcx
->hbrBackground
;
904 /* make a copy of the string */
905 if (pszMenuNameBuffer
!= NULL
)
907 Class
->MenuNameIsString
= TRUE
;
909 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
910 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
913 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
915 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
918 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
920 /* save an ansi copy of the string */
921 if (pszMenuNameBuffer
!= NULL
)
923 ANSI_STRING AnsiString
;
925 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
926 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
927 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
928 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
931 if (!NT_SUCCESS(Status
))
933 DPRINT1("Failed to convert unicode menu name to ansi!\n");
935 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
940 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
942 /* Save kernel use menu name and ansi class name */
943 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
944 //Class->lpszAnsiClassName = Fixme!
946 if (!(dwFlags
& CSF_ANSIPROC
))
947 Class
->Unicode
= TRUE
;
949 if (Class
->style
& CS_GLOBALCLASS
)
950 Class
->Global
= TRUE
;
952 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
954 Status
= _SEH2_GetExceptionCode();
958 if (!NT_SUCCESS(Status
))
960 DPRINT1("Failed creating the class: 0x%x\n", Status
);
962 SetLastNtError(Status
);
964 if (pszMenuName
!= NULL
)
965 UserHeapFree(pszMenuName
);
967 DesktopHeapFree(Desktop
,
971 IntDeregisterClassAtom(Atom
);
977 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
979 if (pszMenuName
!= NULL
)
980 UserHeapFree(pszMenuName
);
982 IntDeregisterClassAtom(Atom
);
984 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
991 IntFindClass(IN RTL_ATOM Atom
,
992 IN HINSTANCE hInstance
,
994 OUT PCLS
**Link OPTIONAL
)
996 PCLS Class
, *PrevLink
= ClassList
;
999 while (Class
!= NULL
)
1001 if (Class
->atomClassName
== Atom
&&
1002 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1005 ASSERT(Class
->pclsBase
== Class
);
1012 PrevLink
= &Class
->pclsNext
;
1013 Class
= Class
->pclsNext
;
1020 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1025 if (ClassName
->Length
!= 0)
1031 /* NOTE: Caller has to protect the call with SEH! */
1033 if (ClassName
->Length
!= 0)
1035 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1036 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1038 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1042 /* We need to make a local copy of the class name! The caller could
1043 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1044 We're protected by SEH, but the ranges that might be accessed were
1046 RtlCopyMemory(szBuf
,
1049 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1053 AtomName
= ClassName
->Buffer
;
1055 /* lookup the atom */
1056 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1059 if (NT_SUCCESS(Status
))
1065 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1067 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1071 SetLastNtError(Status
);
1077 ASSERT(IS_ATOM(ClassName
->Buffer
));
1078 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1086 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1087 IN HINSTANCE hInstance OPTIONAL
,
1088 IN PPROCESSINFO pi OPTIONAL
,
1089 OUT PCLS
*BaseClass OPTIONAL
,
1090 OUT PCLS
**Link OPTIONAL
)
1092 RTL_ATOM Atom
= (RTL_ATOM
)0;
1094 ASSERT(BaseClass
!= NULL
);
1096 if (IntGetAtomFromStringOrAtom(ClassName
,
1098 Atom
!= (RTL_ATOM
)0)
1102 /* attempt to locate the class object */
1106 /* Step 1: try to find an exact match of locally registered classes */
1107 Class
= IntFindClass(Atom
,
1109 &pi
->pclsPrivateList
,
1116 /* Step 2: try to find any globally registered class. The hInstance
1117 is not relevant for global classes */
1118 Class
= IntFindClass(Atom
,
1120 &pi
->pclsPublicList
,
1127 /* Step 3: try to find any local class registered by user32 */
1128 Class
= IntFindClass(Atom
,
1130 &pi
->pclsPrivateList
,
1137 /* Step 4: try to find any global class registered by user32 */
1138 Class
= IntFindClass(Atom
,
1140 &pi
->pclsPublicList
,
1147 /* Step 5: try to find a system class */
1148 Class
= IntFindClass(Atom
,
1154 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1166 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1167 IN PUNICODE_STRING ClassName
,
1168 IN PUNICODE_STRING MenuName
,
1178 RTL_ATOM Ret
= (RTL_ATOM
)0;
1180 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1182 pti
= PsGetCurrentThreadWin32Thread();
1183 ti
= GetW32ThreadInfo();
1184 if (ti
== NULL
|| !RegisteredSysClasses
)
1186 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1192 /* try to find a previously registered class */
1193 ClassAtom
= IntGetClassAtom(ClassName
,
1198 if (ClassAtom
!= (RTL_ATOM
)0)
1200 if (lpwcx
->style
& CS_GLOBALCLASS
)
1202 // global classes shall not have same names as system classes
1203 if (Class
->Global
|| Class
->System
)
1205 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1206 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1210 else if ( !Class
->Global
&& !Class
->System
)
1212 // local class already exists
1213 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1214 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1219 Class
= IntCreateClass(lpwcx
,
1232 /* Register the class */
1234 List
= &SystemClassList
;
1235 else if (Class
->Global
)
1236 List
= &pi
->pclsPublicList
;
1238 List
= &pi
->pclsPrivateList
;
1240 Class
->pclsNext
= *List
;
1241 (void)InterlockedExchangePointer((PVOID
*)List
,
1244 Ret
= Class
->atomClassName
;
1251 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1252 IN HINSTANCE hInstance
)
1259 pi
= GetW32ProcessInfo();
1262 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1266 TRACE("UserUnregisterClass(%wZ)\n", ClassName
);
1268 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1269 ClassAtom
= IntGetClassAtom(ClassName
,
1274 if (ClassAtom
== (RTL_ATOM
)0)
1279 ASSERT(Class
!= NULL
);
1281 if (Class
->cWndReferenceCount
!= 0 ||
1282 Class
->pclsClone
!= NULL
)
1284 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1288 /* must be a base class! */
1289 ASSERT(Class
->pclsBase
== Class
);
1291 /* unlink the class */
1292 *Link
= Class
->pclsNext
;
1294 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1296 /* finally free the resources */
1297 IntDestroyClass(Class
);
1304 UserGetClassName(IN PCLS Class
,
1305 IN OUT PUNICODE_STRING ClassName
,
1308 NTSTATUS Status
= STATUS_SUCCESS
;
1309 WCHAR szStaticTemp
[32];
1310 PWSTR szTemp
= NULL
;
1311 ULONG BufLen
= sizeof(szStaticTemp
);
1314 /* Note: Accessing the buffer in ClassName may raise an exception! */
1320 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1321 UNICODE_STRING UnicodeClassName
;
1323 /* limit the size of the static buffer on the stack to the
1324 size of the buffer provided by the caller */
1325 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1327 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1330 /* find out how big the buffer needs to be */
1331 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1332 Class
->atomClassName
,
1337 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1339 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1341 /* the buffer required exceeds the ansi buffer provided,
1342 pretend like we're using the ansi buffer and limit the
1343 size to the buffer size provided */
1344 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1347 /* allocate a temporary buffer that can hold the unicode class name */
1348 szTemp
= ExAllocatePool(PagedPool
,
1352 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1356 /* query the class name */
1357 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1358 Class
->atomClassName
,
1365 szTemp
= szStaticTemp
;
1367 if (NT_SUCCESS(Status
))
1369 /* convert the atom name to ansi */
1371 RtlInitUnicodeString(&UnicodeClassName
,
1374 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1377 if (!NT_SUCCESS(Status
))
1379 SetLastNtError(Status
);
1384 Ret
= BufLen
/ sizeof(WCHAR
);
1388 BufLen
= ClassName
->MaximumLength
;
1390 /* query the atom name */
1391 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1392 Class
->atomClassName
,
1398 if (!NT_SUCCESS(Status
))
1400 SetLastNtError(Status
);
1404 Ret
= BufLen
/ sizeof(WCHAR
);
1407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1409 SetLastNtError(_SEH2_GetExceptionCode());
1413 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1422 UserGetClassLongPtr(IN PCLS Class
,
1432 TRACE("GetClassLong(%d)\n", Index
);
1433 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1434 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1436 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1440 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1442 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1443 certain architectures, maybe using RtlCopyMemory is a
1444 better choice for those architectures! */
1446 TRACE("Result: %x\n", Ret
);
1452 case GCL_CBWNDEXTRA
:
1453 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1456 case GCL_CBCLSEXTRA
:
1457 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
1460 case GCLP_HBRBACKGROUND
:
1461 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1465 /* FIXME - get handle from pointer to CURSOR object */
1466 Ret
= (ULONG_PTR
)Class
->hCursor
;
1470 /* FIXME - get handle from pointer to ICON object */
1471 Ret
= (ULONG_PTR
)Class
->hIcon
;
1475 /* FIXME - get handle from pointer to ICON object */
1476 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1480 Ret
= (ULONG_PTR
)Class
->hModule
;
1484 /* NOTE: Returns pointer in kernel heap! */
1486 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
1488 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
1492 Ret
= (ULONG_PTR
)Class
->style
;
1496 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1497 GetW32ProcessInfo(),
1502 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1506 SetLastWin32Error(ERROR_INVALID_INDEX
);
1514 IntSetClassMenuName(IN PCLS Class
,
1515 IN PUNICODE_STRING MenuName
)
1519 /* change the base class first */
1520 Class
= Class
->pclsBase
;
1522 if (MenuName
->Length
!= 0)
1524 ANSI_STRING AnsiString
;
1527 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1529 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1530 AnsiString
.MaximumLength
);
1531 if (strBufW
!= NULL
)
1537 /* copy the unicode string */
1538 RtlCopyMemory(strBufW
,
1541 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1543 /* create an ansi copy of the string */
1544 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1545 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1548 if (!NT_SUCCESS(Status
))
1550 SetLastNtError(Status
);
1556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1558 SetLastNtError(_SEH2_GetExceptionCode());
1564 /* update the base class */
1565 IntFreeClassMenuName(Class
);
1566 Class
->lpszClientUnicodeMenuName
= strBufW
;
1567 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1568 Class
->MenuNameIsString
= TRUE
;
1570 /* update the clones */
1571 Class
= Class
->pclsClone
;
1572 while (Class
!= NULL
)
1574 Class
->lpszClientUnicodeMenuName
= strBufW
;
1575 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1576 Class
->MenuNameIsString
= TRUE
;
1578 Class
= Class
->pclsNext
;
1583 DPRINT1("Failed to copy class menu name!\n");
1584 UserHeapFree(strBufW
);
1588 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1592 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1594 /* update the base class */
1595 IntFreeClassMenuName(Class
);
1596 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1597 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1598 Class
->MenuNameIsString
= FALSE
;
1600 /* update the clones */
1601 Class
= Class
->pclsClone
;
1602 while (Class
!= NULL
)
1604 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1605 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1606 Class
->MenuNameIsString
= FALSE
;
1608 Class
= Class
->pclsNext
;
1618 UserSetClassLongPtr(IN PCLS Class
,
1620 IN ULONG_PTR NewLong
,
1625 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1627 /* change the information in the base class first, then update the clones */
1628 Class
= Class
->pclsBase
;
1634 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1636 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1637 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1639 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1643 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1645 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1646 certain architectures, maybe using RtlCopyMemory is a
1647 better choice for those architectures! */
1651 /* update the clones */
1652 Class
= Class
->pclsClone
;
1653 while (Class
!= NULL
)
1655 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1656 Class
= Class
->pclsNext
;
1664 case GCL_CBWNDEXTRA
:
1665 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1666 Class
->cbwndExtra
= (INT
)NewLong
;
1668 /* update the clones */
1669 Class
= Class
->pclsClone
;
1670 while (Class
!= NULL
)
1672 Class
->cbwndExtra
= (INT
)NewLong
;
1673 Class
= Class
->pclsNext
;
1678 case GCL_CBCLSEXTRA
:
1679 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1682 case GCLP_HBRBACKGROUND
:
1683 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1684 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1686 /* update the clones */
1687 Class
= Class
->pclsClone
;
1688 while (Class
!= NULL
)
1690 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1691 Class
= Class
->pclsNext
;
1696 /* FIXME - get handle from pointer to CURSOR object */
1697 Ret
= (ULONG_PTR
)Class
->hCursor
;
1698 Class
->hCursor
= (HANDLE
)NewLong
;
1700 /* update the clones */
1701 Class
= Class
->pclsClone
;
1702 while (Class
!= NULL
)
1704 Class
->hCursor
= (HANDLE
)NewLong
;
1705 Class
= Class
->pclsNext
;
1710 /* FIXME - get handle from pointer to ICON object */
1711 Ret
= (ULONG_PTR
)Class
->hIcon
;
1712 Class
->hIcon
= (HANDLE
)NewLong
;
1714 /* update the clones */
1715 Class
= Class
->pclsClone
;
1716 while (Class
!= NULL
)
1718 Class
->hIcon
= (HANDLE
)NewLong
;
1719 Class
= Class
->pclsNext
;
1724 /* FIXME - get handle from pointer to ICON object */
1725 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1726 Class
->hIconSm
= (HANDLE
)NewLong
;
1728 /* update the clones */
1729 Class
= Class
->pclsClone
;
1730 while (Class
!= NULL
)
1732 Class
->hIconSm
= (HANDLE
)NewLong
;
1733 Class
= Class
->pclsNext
;
1738 Ret
= (ULONG_PTR
)Class
->hModule
;
1739 Class
->hModule
= (HINSTANCE
)NewLong
;
1741 /* update the clones */
1742 Class
= Class
->pclsClone
;
1743 while (Class
!= NULL
)
1745 Class
->hModule
= (HINSTANCE
)NewLong
;
1746 Class
= Class
->pclsNext
;
1752 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1754 if (!IntSetClassMenuName(Class
,
1757 DPRINT1("Setting the class menu name failed!\n");
1760 /* FIXME - really return NULL? Wine does so... */
1765 Ret
= (ULONG_PTR
)Class
->style
;
1766 Class
->style
= (UINT
)NewLong
;
1768 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1769 move the class to the appropriate list? For now, we save
1770 the original value in Class->Global, so we can always
1771 locate the appropriate list */
1773 /* update the clones */
1774 Class
= Class
->pclsClone
;
1775 while (Class
!= NULL
)
1777 Class
->style
= (UINT
)NewLong
;
1778 Class
= Class
->pclsNext
;
1783 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1790 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1792 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1793 if (!IntSetClassAtom(Class
,
1802 SetLastWin32Error(ERROR_INVALID_INDEX
);
1810 UserGetClassInfo(IN PCLS Class
,
1811 OUT PWNDCLASSEXW lpwcx
,
1813 HINSTANCE hInstance
)
1817 lpwcx
->style
= Class
->style
;
1819 pi
= GetW32ProcessInfo();
1820 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1824 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1825 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1826 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1827 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1828 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1831 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1832 lpszClientXxxMenuName should already be mapped to user space.
1835 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1837 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1839 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1840 Class
->MenuNameIsString
)
1842 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1843 (PVOID
)Class
->lpszClientAnsiMenuName
:
1844 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1847 if (hInstance
== hModClient
)
1848 lpwcx
->hInstance
= NULL
;
1850 lpwcx
->hInstance
= hInstance
;
1852 /* FIXME - return the string? Okay! This is performed in User32!*/
1853 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
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 ( hModClient
== NULL
)
1874 /* Init System Classes once only*/
1875 if (RegisteredSysClasses
)
1878 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1880 for (i
= 0; i
!= Count
; i
++)
1882 ClassName
= ProbeForReadUnicodeString(&SystemClasses
[i
].ClassName
);
1883 if (ClassName
.Length
!= 0)
1885 ProbeForRead(ClassName
.Buffer
,
1890 wc
.cbSize
= sizeof(wc
);
1891 wc
.style
= SystemClasses
[i
].Style
;
1892 wc
.lpfnWndProc
= SystemClasses
[i
].ProcW
;
1894 wc
.cbWndExtra
= SystemClasses
[i
].ExtraBytes
;
1895 wc
.hInstance
= hModClient
;
1897 wc
.hCursor
= SystemClasses
[i
].hCursor
;
1898 wc
.hbrBackground
= SystemClasses
[i
].hBrush
;
1899 wc
.lpszMenuName
= NULL
;
1900 wc
.lpszClassName
= ClassName
.Buffer
;
1903 Class
= IntCreateClass(&wc
,
1906 SystemClasses
[i
].ProcA
,
1907 SystemClasses
[i
].ClassId
,
1913 ASSERT(Class
->System
);
1914 Class
->pclsNext
= SystemClassList
;
1915 (void)InterlockedExchangePointer((PVOID
*)&SystemClassList
,
1920 WARN("!!! Registering system class failed!\n");
1926 RegisteredSysClasses
= TRUE
;
1930 /* SYSCALLS *****************************************************************/
1934 NtUserRegisterClassExWOW(
1936 PUNICODE_STRING ClassName
,
1937 PUNICODE_STRING ClsNVersion
,
1938 PCLSMENUNAME pClassMenuName
,
1944 * Registers a new class with the window manager
1946 * lpwcx = Win32 extended window class structure
1947 * bUnicodeClass = Whether to send ANSI or unicode strings
1948 * to window procedures
1950 * Atom identifying the new class
1953 WNDCLASSEXW CapturedClassInfo
= {0};
1954 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1955 RTL_ATOM Ret
= (RTL_ATOM
)0;
1956 WNDPROC wpExtra
= NULL
;
1958 if (Flags
& ~(CSF_ANSIPROC
))
1960 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1964 UserEnterExclusive();
1968 /* Probe the parameters and basic parameter checks */
1969 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1971 goto InvalidParameter
;
1975 sizeof(WNDCLASSEXW
),
1977 RtlCopyMemory(&CapturedClassInfo
,
1979 sizeof(WNDCLASSEXW
));
1981 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1983 ProbeForRead(pClassMenuName
,
1984 sizeof(CLSMENUNAME
),
1987 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
1989 if ( CapturedName
.Length
& 1 ||
1990 CapturedMenuName
.Length
& 1 ||
1991 CapturedClassInfo
.cbClsExtra
< 0 ||
1992 CapturedClassInfo
.cbClsExtra
+
1993 CapturedName
.Length
+
1994 CapturedMenuName
.Length
+
1995 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
1996 CapturedClassInfo
.cbWndExtra
< 0 ||
1997 CapturedClassInfo
.hInstance
== NULL
)
1999 goto InvalidParameter
;
2002 if (CapturedName
.Length
!= 0)
2004 ProbeForRead(CapturedName
.Buffer
,
2005 CapturedName
.Length
,
2010 if (!IS_ATOM(CapturedName
.Buffer
))
2012 goto InvalidParameter
;
2016 if (CapturedMenuName
.Length
!= 0)
2018 ProbeForRead(CapturedMenuName
.Buffer
,
2019 CapturedMenuName
.Length
,
2022 else if (CapturedMenuName
.Buffer
!= NULL
&&
2023 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2026 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2029 /* Register the class */
2030 Ret
= UserRegisterClass(&CapturedClassInfo
,
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2039 SetLastNtError(_SEH2_GetExceptionCode());
2049 NtUserGetClassLong(IN HWND hWnd
,
2053 PWINDOW_OBJECT Window
;
2056 if (Offset
!= GCLP_WNDPROC
)
2062 UserEnterExclusive();
2065 Window
= UserGetWindowObject(hWnd
);
2068 Ret
= UserGetClassLongPtr(Window
->Wnd
->pcls
,
2072 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& Window
->Wnd
->pcls
->MenuNameIsString
)
2074 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2086 NtUserSetClassLong(HWND hWnd
,
2088 ULONG_PTR dwNewLong
,
2092 PWINDOW_OBJECT Window
;
2095 UserEnterExclusive();
2097 pi
= GetW32ProcessInfo();
2101 Window
= UserGetWindowObject(hWnd
);
2104 if (Window
->ti
->ppi
!= pi
)
2106 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2112 UNICODE_STRING Value
;
2114 /* probe the parameters */
2115 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2117 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2118 if (Value
.Length
& 1)
2120 goto InvalidParameter
;
2123 if (Value
.Length
!= 0)
2125 ProbeForRead(Value
.Buffer
,
2131 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2133 goto InvalidParameter
;
2135 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2138 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2143 dwNewLong
= (ULONG_PTR
)&Value
;
2146 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2153 SetLastNtError(_SEH2_GetExceptionCode());
2172 * NOTE: Obsoleted in 32-bit windows
2178 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2179 IN HINSTANCE hInstance
,
2180 OUT PCLSMENUNAME pClassMenuName
)
2182 UNICODE_STRING CapturedClassName
;
2185 UserEnterExclusive();
2189 /* probe the paramters */
2190 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2191 if (CapturedClassName
.Length
& 1)
2193 goto InvalidParameter
;
2196 if (CapturedClassName
.Length
!= 0)
2198 ProbeForRead(CapturedClassName
.Buffer
,
2199 CapturedClassName
.Length
,
2204 if (!IS_ATOM(CapturedClassName
.Buffer
))
2207 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2212 /* unregister the class */
2213 Ret
= UserUnregisterClass(&CapturedClassName
,
2216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2218 SetLastNtError(_SEH2_GetExceptionCode());
2226 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2229 HINSTANCE hInstance
,
2230 PUNICODE_STRING ClassName
,
2231 LPWNDCLASSEXW lpWndClassEx
,
2232 LPWSTR
*ppszMenuName
,
2235 UNICODE_STRING CapturedClassName
, SafeClassName
;
2236 WNDCLASSEXW Safewcexw
;
2238 RTL_ATOM ClassAtom
= 0;
2242 /* NOTE: need exclusive lock because getting the wndproc might require the
2243 creation of a call procedure handle */
2244 UserEnterExclusive();
2246 pi
= GetW32ProcessInfo();
2249 ERR("GetW32ProcessInfo() returned NULL!\n");
2255 /* probe the paramters */
2256 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2258 if (CapturedClassName
.Length
== 0)
2259 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2261 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2263 if (CapturedClassName
.Length
& 1)
2265 goto InvalidParameter
;
2268 if (CapturedClassName
.Length
!= 0)
2270 ProbeForRead( CapturedClassName
.Buffer
,
2271 CapturedClassName
.Length
,
2274 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2276 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2277 SafeClassName
.MaximumLength
,
2279 RtlCopyMemory( SafeClassName
.Buffer
,
2280 CapturedClassName
.Buffer
,
2281 SafeClassName
.MaximumLength
);
2285 if (!IS_ATOM(CapturedClassName
.Buffer
))
2287 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2288 goto InvalidParameter
;
2291 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2292 SafeClassName
.Length
= 0;
2293 SafeClassName
.MaximumLength
= 0;
2296 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2299 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2304 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2306 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2310 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2317 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2322 if (ClassAtom
!= (RTL_ATOM
)0)
2324 if (hInstance
== NULL
) hInstance
= hModClient
;
2326 Ret
= UserGetClassInfo( Class
,
2333 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2341 /* Emulate Function. */
2342 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2344 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2347 /* We must return the atom of the class here instead of just TRUE. */
2348 /* Undocumented behavior! Return the class atom as a BOOL! */
2349 Ret
= (BOOL
)ClassAtom
;
2352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2354 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2360 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2368 NtUserGetClassName (IN HWND hWnd
,
2369 OUT PUNICODE_STRING ClassName
,
2372 PWINDOW_OBJECT Window
;
2373 UNICODE_STRING CapturedClassName
;
2378 Window
= UserGetWindowObject(hWnd
);
2383 ProbeForWriteUnicodeString(ClassName
);
2384 CapturedClassName
= *ClassName
;
2386 /* get the class name */
2387 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2393 /* update the Length field */
2394 ClassName
->Length
= CapturedClassName
.Length
;
2397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2399 SetLastNtError(_SEH2_GetExceptionCode());
2409 /* Return Pointer to Class structure. */
2411 NtUserGetWOWClass(HINSTANCE hInstance
,
2412 PUNICODE_STRING ClassName
)
2414 UNICODE_STRING SafeClassName
;
2417 RTL_ATOM ClassAtom
= 0;
2420 UserEnterExclusive();
2422 pi
= GetW32ProcessInfo();
2425 ERR("GetW32ProcessInfo() returned NULL!\n");
2431 if (ClassName
->Length
!= 0)
2433 ProbeForRead( ClassName
->Buffer
,
2437 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2439 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2440 SafeClassName
.MaximumLength
,
2442 RtlCopyMemory( SafeClassName
.Buffer
,
2444 SafeClassName
.MaximumLength
);
2448 if (!IS_ATOM(ClassName
->Buffer
))
2450 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2455 SafeClassName
.Buffer
= ClassName
->Buffer
;
2456 SafeClassName
.Length
= 0;
2457 SafeClassName
.MaximumLength
= 0;
2461 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2463 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2470 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2477 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2482 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2485 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.