2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
10 DBG_DEFAULT_CHANNEL(UserClass
);
12 static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom
);
14 REGISTER_SYSCLASS DefaultServerClasses
[] =
16 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
17 CS_GLOBALCLASS
|CS_DBLCLKS
,
18 NULL
, // Use User32 procs
21 (HBRUSH
)(COLOR_BACKGROUND
),
25 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
26 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
27 NULL
, // Use User32 procs
34 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
35 CS_DBLCLKS
|CS_SAVEBITS
,
36 NULL
, // Use User32 procs
39 (HBRUSH
)(COLOR_MENU
+ 1),
44 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
45 NULL
, // Use User32 procs
46 sizeof(SBWND
)-sizeof(WND
),
53 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8006))), // Tooltips
54 CS_PARENTDC
|CS_DBLCLKS
,
55 NULL
, // Use User32 procs
63 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
65 NULL
, // Use User32 procs
74 NULL
, // Use User32 procs
88 { /* Function Ids to Class indexes. */
89 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
90 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
91 { FNID_MENU
, ICLS_MENU
},
92 { FNID_DESKTOP
, ICLS_DESKTOP
},
93 { FNID_SWITCH
, ICLS_SWITCH
},
94 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
95 { FNID_BUTTON
, ICLS_BUTTON
},
96 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
97 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
98 { FNID_DIALOG
, ICLS_DIALOG
},
99 { FNID_EDIT
, ICLS_EDIT
},
100 { FNID_LISTBOX
, ICLS_LISTBOX
},
101 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
102 { FNID_STATIC
, ICLS_STATIC
},
103 { FNID_IME
, ICLS_IME
},
104 { FNID_GHOST
, ICLS_GHOST
},
105 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
110 LookupFnIdToiCls(int FnId
, int *iCls
)
114 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
116 if (FnidToiCls
[i
].FnId
== FnId
)
118 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
126 _Must_inspect_result_
129 ProbeAndCaptureUnicodeStringOrAtom(
130 _Out_
_When_(return>=0, _At_(pustrOut
->Buffer
, _Post_ _Notnull_
)) PUNICODE_STRING pustrOut
,
131 __in_data_source(USER_MODE
) _In_ PUNICODE_STRING pustrUnsafe
)
133 NTSTATUS Status
= STATUS_SUCCESS
;
135 /* Default to NULL */
136 pustrOut
->Buffer
= NULL
;
140 ProbeForRead(pustrUnsafe
, sizeof(UNICODE_STRING
), 1);
142 /* Validate the string */
143 if ((pustrUnsafe
->Length
& 1) || (pustrUnsafe
->Buffer
== NULL
))
145 /* This is not legal */
146 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
149 /* Check if this is an atom */
150 if (IS_ATOM(pustrUnsafe
->Buffer
))
152 /* Copy the atom, length is 0 */
153 pustrOut
->MaximumLength
= pustrOut
->Length
= 0;
154 pustrOut
->Buffer
= pustrUnsafe
->Buffer
;
158 /* Get the length, maximum length includes zero termination */
159 pustrOut
->Length
= pustrUnsafe
->Length
;
160 pustrOut
->MaximumLength
= pustrOut
->Length
+ sizeof(WCHAR
);
162 /* Allocate a buffer */
163 pustrOut
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
164 pustrOut
->MaximumLength
,
166 if (!pustrOut
->Buffer
)
168 _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES
);
171 /* Copy the string and zero terminate it */
172 ProbeForRead(pustrUnsafe
->Buffer
, pustrOut
->Length
, 1);
173 RtlCopyMemory(pustrOut
->Buffer
, pustrUnsafe
->Buffer
, pustrOut
->Length
);
174 pustrOut
->Buffer
[pustrOut
->Length
/ sizeof(WCHAR
)] = L
'\0';
177 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
179 /* Check if we already allocated a buffer */
180 if (pustrOut
->Buffer
)
182 /* Free the buffer */
183 ExFreePoolWithTag(pustrOut
->Buffer
, TAG_STRING
);
184 Status
= _SEH2_GetExceptionCode();
192 /* WINDOWCLASS ***************************************************************/
195 IntFreeClassMenuName(IN OUT PCLS Class
)
197 /* Free the menu name, if it was changed and allocated */
198 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
200 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
201 Class
->lpszClientUnicodeMenuName
= NULL
;
202 Class
->lpszClientAnsiMenuName
= NULL
;
207 IntDestroyClass(IN OUT PCLS Class
)
211 /* There shouldn't be any clones anymore */
212 ASSERT(Class
->cWndReferenceCount
== 0);
213 ASSERT(Class
->pclsClone
== NULL
);
215 if (Class
->pclsBase
== Class
)
217 PCALLPROCDATA CallProc
, NextCallProc
;
219 /* Destroy allocated callproc handles */
220 CallProc
= Class
->spcpdFirst
;
221 while (CallProc
!= NULL
)
223 NextCallProc
= CallProc
->spcpdNext
;
225 CallProc
->spcpdNext
= NULL
;
226 DestroyCallProc(CallProc
);
228 CallProc
= NextCallProc
;
231 // Fixes running the static test then run class test issue.
232 // Some applications do not use UnregisterClass before exiting.
233 // Keep from reusing the same atom with case insensitive
234 // comparisons, remove registration of the atom if not zeroed.
235 if (Class
->atomClassName
)
236 IntDeregisterClassAtom(Class
->atomClassName
);
240 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
244 IntFreeClassMenuName(Class
);
247 #ifdef NEW_CURSORICON
249 UserDereferenceObject(Class
->spicn
);
251 UserDereferenceObject(Class
->spcur
);
254 UserDereferenceObject(Class
->spicnSm
);
255 /* Destroy the icon if we own it */
256 if ((Class
->CSF_flags
& CSF_CACHEDSMICON
)
257 && !(UserObjectInDestroy(UserHMGetHandle(Class
->spicnSm
))))
258 IntDestroyCurIconObject(Class
->spicnSm
);
261 if (Class
->hIconSmIntern
)
262 IntClassDestroyIcon(Class
->hIconSmIntern
);
265 pDesk
= Class
->rpdeskParent
;
266 Class
->rpdeskParent
= NULL
;
268 /* Free the structure */
271 DesktopHeapFree(pDesk
, Class
);
280 /* Clean all process classes. all process windows must cleaned first!! */
281 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
284 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
288 /* Free all local classes */
289 Class
= pi
->pclsPrivateList
;
290 while (Class
!= NULL
)
292 pi
->pclsPrivateList
= Class
->pclsNext
;
294 ASSERT(Class
->pclsBase
== Class
);
295 IntDestroyClass(Class
);
297 Class
= pi
->pclsPrivateList
;
300 /* Free all global classes */
301 Class
= pi
->pclsPublicList
;
302 while (Class
!= NULL
)
304 pi
->pclsPublicList
= Class
->pclsNext
;
306 ASSERT(Class
->pclsBase
== Class
);
307 IntDestroyClass(Class
);
309 Class
= pi
->pclsPublicList
;
315 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
322 if (ClassName
->Length
!= 0)
324 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
325 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
327 EngSetLastError(ERROR_INVALID_PARAMETER
);
334 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
338 AtomName
= ClassName
->Buffer
;
340 Status
= RtlAddAtomToAtomTable(gAtomTable
,
344 if (!NT_SUCCESS(Status
))
346 SetLastNtError(Status
);
354 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
356 return RtlDeleteAtomFromAtomTable(gAtomTable
,
361 UserAddCallProcToClass(IN OUT PCLS Class
,
362 IN PCALLPROCDATA CallProc
)
366 ASSERT(CallProc
->spcpdNext
== NULL
);
368 BaseClass
= Class
->pclsBase
;
369 ASSERT(CallProc
->spcpdNext
== NULL
);
370 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
371 BaseClass
->spcpdFirst
= CallProc
;
373 /* Update all clones */
374 Class
= Class
->pclsClone
;
375 while (Class
!= NULL
)
377 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
378 Class
= Class
->pclsNext
;
383 IntSetClassAtom(IN OUT PCLS Class
,
384 IN PUNICODE_STRING ClassName
)
386 RTL_ATOM Atom
= (RTL_ATOM
)0;
388 /* Update the base class first */
389 Class
= Class
->pclsBase
;
391 if (!IntRegisterClassAtom(ClassName
,
397 IntDeregisterClassAtom(Class
->atomClassName
);
399 Class
->atomClassName
= Atom
;
401 /* Update the clones */
402 Class
= Class
->pclsClone
;
403 while (Class
!= NULL
)
405 Class
->atomClassName
= Atom
;
407 Class
= Class
->pclsNext
;
414 // Same as User32:IntGetClsWndProc.
417 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
420 WNDPROC gcpd
= NULL
, Ret
= NULL
;
422 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
424 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
426 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
429 Ret
= GETPFNCLIENTA(i
);
431 Ret
= GETPFNCLIENTW(i
);
436 Ret
= Class
->lpfnWndProc
;
438 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
442 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
443 Ret
= GETPFNCLIENTA(Class
->fnid
);
447 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
448 Ret
= GETPFNCLIENTW(Class
->fnid
);
452 if ( Ret
!= Class
->lpfnWndProc
||
453 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
456 gcpd
= (WNDPROC
)UserGetCPD( Class
,
457 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
460 return (gcpd
? gcpd
: Ret
);
466 IntSetClassWndProc(IN OUT PCLS Class
,
472 WNDPROC Ret
, chWndProc
;
474 Ret
= IntGetClassWndProc(Class
, Ansi
);
476 // If Server Side, downgrade to Client Side.
477 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
479 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
480 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
481 Class
->Unicode
= !Ansi
;
484 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
488 // Check if CallProc handle and retrieve previous call proc address and set.
489 if (IsCallProcHandle(WndProc
))
491 pcpd
= UserGetObject(gHandleTable
, WndProc
, TYPE_CALLPROC
);
492 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
495 Class
->lpfnWndProc
= chWndProc
;
500 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
501 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
503 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
505 chWndProc
= GETPFNSERVER(i
);
508 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
510 chWndProc
= GETPFNSERVER(i
);
514 // If match, set/reset to Server Side and clear ansi.
517 Class
->lpfnWndProc
= chWndProc
;
518 Class
->Unicode
= TRUE
;
519 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
520 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
524 Class
->Unicode
= !Ansi
;
527 Class
->CSF_flags
|= CSF_ANSIPROC
;
529 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
532 /* Update the clones */
533 chWndProc
= Class
->lpfnWndProc
;
535 Class
= Class
->pclsClone
;
536 while (Class
!= NULL
)
538 Class
->Unicode
= !Ansi
;
539 Class
->lpfnWndProc
= chWndProc
;
541 Class
= Class
->pclsNext
;
548 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
549 IN OUT PCLS
*ClassLink
,
555 ASSERT(Desktop
!= NULL
);
556 ASSERT(BaseClass
->pclsBase
== BaseClass
);
558 if (BaseClass
->rpdeskParent
== Desktop
)
560 /* It is most likely that a window is created on the same
561 desktop as the window class. */
566 if (BaseClass
->rpdeskParent
== NULL
)
568 ASSERT(BaseClass
->cWndReferenceCount
== 0);
569 ASSERT(BaseClass
->pclsClone
== NULL
);
571 /* Classes are also located in the shared heap when the class
572 was created before the thread attached to a desktop. As soon
573 as a window is created for such a class located on the shared
574 heap, the class is cloned into the desktop heap on which the
575 window is created. */
580 /* The user is asking for a class object on a different desktop,
582 Class
= BaseClass
->pclsClone
;
583 while (Class
!= NULL
)
585 if (Class
->rpdeskParent
== Desktop
)
587 ASSERT(Class
->pclsBase
== BaseClass
);
588 ASSERT(Class
->pclsClone
== NULL
);
592 Class
= Class
->pclsNext
;
598 /* The window is created on a different desktop, we need to
599 clone the class object to the desktop heap of the window! */
600 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
602 Class
= DesktopHeapAlloc(Desktop
,
607 /* Simply clone the class */
608 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
610 #ifdef NEW_CURSORICON
611 /* Reference our objects */
613 UserReferenceObject(Class
->spcur
);
615 UserReferenceObject(Class
->spicn
);
617 UserReferenceObject(Class
->spicnSm
);
620 TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
622 /* Restore module address if default user class Ref: Bug 4778 */
623 if ( Class
->hModule
!= hModClient
&&
624 Class
->fnid
<= FNID_GHOST
&&
625 Class
->fnid
>= FNID_BUTTON
)
627 Class
->hModule
= hModClient
;
628 TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class
, Class
->hModule
);
631 /* Update some pointers and link the class */
632 Class
->rpdeskParent
= Desktop
;
633 Class
->cWndReferenceCount
= 0;
635 if (BaseClass
->rpdeskParent
== NULL
)
637 /* We don't really need the base class on the shared
638 heap anymore, delete it so the only class left is
639 the clone we just created, which now serves as the
641 ASSERT(BaseClass
->pclsClone
== NULL
);
642 ASSERT(Class
->pclsClone
== NULL
);
643 Class
->pclsBase
= Class
;
644 Class
->pclsNext
= BaseClass
->pclsNext
;
646 /* Replace the base class */
647 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
650 /* Destroy the obsolete copy on the shared heap */
651 BaseClass
->pclsBase
= NULL
;
652 BaseClass
->pclsClone
= NULL
;
653 IntDestroyClass(BaseClass
);
657 /* Link in the clone */
658 Class
->pclsClone
= NULL
;
659 Class
->pclsBase
= BaseClass
;
660 Class
->pclsNext
= BaseClass
->pclsClone
;
661 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
667 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
674 IntReferenceClass(IN OUT PCLS BaseClass
,
675 IN OUT PCLS
*ClassLink
,
679 ASSERT(BaseClass
->pclsBase
== BaseClass
);
683 Class
= IntGetClassForDesktop(BaseClass
,
694 Class
->cWndReferenceCount
++;
702 IntMakeCloneBaseClass(IN OUT PCLS Class
,
703 IN OUT PCLS
*BaseClassLink
,
704 IN OUT PCLS
*CloneLink
)
708 ASSERT(Class
->pclsBase
!= Class
);
709 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
710 ASSERT(Class
->rpdeskParent
!= NULL
);
711 ASSERT(Class
->cWndReferenceCount
!= 0);
712 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
713 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
715 /* Unlink the clone */
716 *CloneLink
= Class
->pclsNext
;
717 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
719 /* Update the class information to make it a base class */
720 Class
->pclsBase
= Class
;
721 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
723 /* Update all clones */
724 Clone
= Class
->pclsClone
;
725 while (Clone
!= NULL
)
727 ASSERT(Clone
->pclsClone
== NULL
);
728 Clone
->pclsBase
= Class
;
730 Clone
= Clone
->pclsNext
;
733 /* Link in the new base class */
734 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
740 IntDereferenceClass(IN OUT PCLS Class
,
741 IN PDESKTOPINFO Desktop
,
744 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
746 ASSERT(Class
->cWndReferenceCount
>= 1);
748 BaseClass
= Class
->pclsBase
;
750 if (--Class
->cWndReferenceCount
== 0)
752 if (BaseClass
== Class
)
754 ASSERT(Class
->pclsBase
== Class
);
756 TRACE("IntDereferenceClass 0x%p\n", Class
);
757 /* Check if there are clones of the class on other desktops,
758 link the first clone in if possible. If there are no clones
759 then leave the class on the desktop heap. It will get moved
760 to the shared heap when the thread detaches. */
761 if (BaseClass
->pclsClone
!= NULL
)
763 if (BaseClass
->Global
)
764 PrevLink
= &pi
->pclsPublicList
;
766 PrevLink
= &pi
->pclsPrivateList
;
768 CurrentClass
= *PrevLink
;
769 while (CurrentClass
!= BaseClass
)
771 ASSERT(CurrentClass
!= NULL
);
773 PrevLink
= &CurrentClass
->pclsNext
;
774 CurrentClass
= CurrentClass
->pclsNext
;
777 ASSERT(*PrevLink
== BaseClass
);
779 /* Make the first clone become the new base class */
780 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
782 &BaseClass
->pclsClone
);
784 /* Destroy the class, there's still another clone of the class
785 that now serves as a base class. Make sure we don't destruct
786 resources shared by all classes (Base = NULL)! */
787 BaseClass
->pclsBase
= NULL
;
788 BaseClass
->pclsClone
= NULL
;
789 IntDestroyClass(BaseClass
);
794 TRACE("IntDereferenceClass1 0x%p\n", Class
);
796 /* Locate the cloned class and unlink it */
797 PrevLink
= &BaseClass
->pclsClone
;
798 CurrentClass
= BaseClass
->pclsClone
;
799 while (CurrentClass
!= Class
)
801 ASSERT(CurrentClass
!= NULL
);
803 PrevLink
= &CurrentClass
->pclsNext
;
804 CurrentClass
= CurrentClass
->pclsNext
;
807 ASSERT(CurrentClass
== Class
);
809 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
812 ASSERT(Class
->pclsBase
== BaseClass
);
813 ASSERT(Class
->pclsClone
== NULL
);
815 /* The class was just a clone, we don't need it anymore */
816 IntDestroyClass(Class
);
822 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
823 IN OUT PCLS
**ClassLinkPtr
)
828 ASSERT(Class
->pclsBase
== Class
);
829 ASSERT(Class
->rpdeskParent
!= NULL
);
830 ASSERT(Class
->cWndReferenceCount
== 0);
831 ASSERT(Class
->pclsClone
== NULL
);
833 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
835 /* Allocate the new base class on the shared heap */
836 NewClass
= UserHeapAlloc(ClassSize
);
837 if (NewClass
!= NULL
)
839 RtlCopyMemory(NewClass
,
843 NewClass
->rpdeskParent
= NULL
;
844 NewClass
->pclsBase
= NewClass
;
846 #ifdef NEW_CURSORICON
848 UserReferenceObject(NewClass
->spcur
);
850 UserReferenceObject(NewClass
->spicn
);
851 if (NewClass
->spicnSm
)
852 UserReferenceObject(NewClass
->spicnSm
);
856 /* Replace the class in the list */
857 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
859 *ClassLinkPtr
= &NewClass
->pclsNext
;
861 /* Free the obsolete class on the desktop heap */
862 Class
->pclsBase
= NULL
;
863 IntDestroyClass(Class
);
871 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
872 IN OUT PCLS
*ClassList
,
873 IN BOOL FreeOnFailure
,
876 PCLS Class
, NextClass
, *Link
;
878 /* NOTE: We only need to check base classes! When classes are no longer needed
879 on a desktop, the clones will be freed automatically as soon as possible.
880 However, we need to move base classes to the shared heap, as soon as
881 the last desktop heap where a class is allocated on is about to be destroyed.
882 If we didn't move the class to the shared heap, the class would become
885 ASSERT(Desktop
!= NULL
);
889 while (Class
!= NULL
)
891 NextClass
= Class
->pclsNext
;
893 ASSERT(Class
->pclsBase
== Class
);
895 if (Class
->rpdeskParent
== Desktop
&&
896 Class
->cWndReferenceCount
== 0)
898 /* There shouldn't be any clones around anymore! */
899 ASSERT(Class
->pclsClone
== NULL
);
901 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
902 /* FIXME: We could move the class to another desktop heap if there's still desktops
903 mapped into the process... */
905 /* Move the class to the shared heap */
906 if (IntMoveClassToSharedHeap(Class
,
909 ASSERT(*Link
== NextClass
);
913 ASSERT(NextClass
== Class
->pclsNext
);
917 /* Unlink the base class */
918 (void)InterlockedExchangePointer((PVOID
*)Link
,
921 /* We can free the old base class now */
922 Class
->pclsBase
= NULL
;
923 IntDestroyClass(Class
);
927 Link
= &Class
->pclsNext
;
933 Link
= &Class
->pclsNext
;
940 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
941 IN BOOL FreeOnFailure
)
946 pi
= GetW32ProcessInfo();
948 /* Check all local classes */
949 IntCheckDesktopClasses(Desktop
,
950 &pi
->pclsPrivateList
,
954 /* Check all global classes */
955 IntCheckDesktopClasses(Desktop
,
961 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
962 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
970 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
971 IN PUNICODE_STRING ClassName
,
972 IN PUNICODE_STRING MenuName
,
982 PWSTR pszMenuName
= NULL
;
983 NTSTATUS Status
= STATUS_SUCCESS
;
985 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
986 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
988 if (!IntRegisterClassAtom(ClassName
,
991 ERR("Failed to register class atom!\n");
995 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
996 if (MenuName
->Length
!= 0)
998 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
999 RtlUnicodeStringToAnsiSize(MenuName
));
1000 if (pszMenuName
== NULL
)
1004 if (Desktop
!= NULL
)
1006 Class
= DesktopHeapAlloc(Desktop
,
1011 /* FIXME: The class was created before being connected
1012 to a desktop. It is possible for the desktop window,
1013 but should it be allowed for any other case? */
1014 Class
= UserHeapAlloc(ClassSize
);
1021 RtlZeroMemory(Class
, ClassSize
);
1023 Class
->rpdeskParent
= Desktop
;
1024 Class
->pclsBase
= Class
;
1025 Class
->atomClassName
= Atom
;
1027 Class
->CSF_flags
= dwFlags
;
1029 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
1031 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1036 PWSTR pszMenuNameBuffer
= pszMenuName
;
1038 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1039 and string buffers might raise an exception! We don't want to
1041 // What?! If the user interface was written correctly this would not be an issue!
1042 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
1043 Class
->style
= lpwcx
->style
;
1044 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
1045 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
1046 Class
->hModule
= lpwcx
->hInstance
;
1047 #ifdef NEW_CURSORICON
1048 Class
->spicn
= lpwcx
->hIcon
? UserGetCurIconObject(lpwcx
->hIcon
) : NULL
;
1049 Class
->spcur
= lpwcx
->hCursor
? UserGetCurIconObject(lpwcx
->hCursor
) : NULL
;
1050 Class
->spicnSm
= lpwcx
->hIconSm
? UserGetCurIconObject(lpwcx
->hIconSm
) : NULL
;
1052 Class
->hIcon
= lpwcx
->hIcon
;
1053 Class
->hIconSm
= lpwcx
->hIconSm
;
1054 Class
->hCursor
= lpwcx
->hCursor
;
1057 Class
->hbrBackground
= lpwcx
->hbrBackground
;
1059 /* Make a copy of the string */
1060 if (pszMenuNameBuffer
!= NULL
)
1062 Class
->MenuNameIsString
= TRUE
;
1064 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
1065 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
1068 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1070 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
1073 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1075 /* Save an ANSI copy of the string */
1076 if (pszMenuNameBuffer
!= NULL
)
1078 ANSI_STRING AnsiString
;
1080 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
1081 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1082 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
1083 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1086 if (!NT_SUCCESS(Status
))
1088 ERR("Failed to convert unicode menu name to ansi!\n");
1090 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1095 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1097 /* Save kernel use menu name and ansi class name */
1098 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
1099 //Class->lpszAnsiClassName = FIXME
1101 /* Server Side overrides class calling type (A/W)!
1102 User32 whine test_builtinproc: "deftest"
1103 built-in winproc - window A/W type automatically detected */
1104 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
1108 /* Due to the wine class "deftest" and most likely no FNID to reference
1109 from, sort through the Server Side list and compare proc addresses
1110 for match. This method will be used in related code.
1112 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
1113 { // Open ANSI or Unicode, just match, set and break.
1114 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
1116 WndProc
= GETPFNSERVER(i
);
1119 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
1121 WndProc
= GETPFNSERVER(i
);
1126 { // If a hit, we are Server Side so set the right flags and proc.
1127 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
1128 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
1129 Class
->lpfnWndProc
= WndProc
;
1133 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1134 Class
->Unicode
= TRUE
;
1136 if (Class
->style
& CS_GLOBALCLASS
)
1137 Class
->Global
= TRUE
;
1139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1141 Status
= _SEH2_GetExceptionCode();
1145 if (!NT_SUCCESS(Status
))
1147 ERR("Failed creating the class: 0x%x\n", Status
);
1149 SetLastNtError(Status
);
1151 if (pszMenuName
!= NULL
)
1152 UserHeapFree(pszMenuName
);
1154 DesktopHeapFree(Desktop
,
1158 IntDeregisterClassAtom(Atom
);
1164 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1166 if (pszMenuName
!= NULL
)
1167 UserHeapFree(pszMenuName
);
1169 IntDeregisterClassAtom(Atom
);
1171 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1174 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
1175 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1181 IntFindClass(IN RTL_ATOM Atom
,
1182 IN HINSTANCE hInstance
,
1184 OUT PCLS
**Link OPTIONAL
)
1186 PCLS Class
, *PrevLink
= ClassList
;
1189 while (Class
!= NULL
)
1191 if (Class
->atomClassName
== Atom
&&
1192 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1193 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1195 ASSERT(Class
->pclsBase
== Class
);
1202 PrevLink
= &Class
->pclsNext
;
1203 Class
= Class
->pclsNext
;
1211 IntGetAtomFromStringOrAtom(
1212 _In_ PUNICODE_STRING ClassName
,
1213 _Out_ RTL_ATOM
*Atom
)
1217 if (ClassName
->Length
!= 0)
1225 /* NOTE: Caller has to protect the call with SEH! */
1227 if (ClassName
->Length
!= 0)
1229 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1230 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1232 EngSetLastError(ERROR_INVALID_PARAMETER
);
1236 /* We need to make a local copy of the class name! The caller could
1237 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1238 We're protected by SEH, but the ranges that might be accessed were
1240 RtlCopyMemory(szBuf
,
1243 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1247 AtomName
= ClassName
->Buffer
;
1249 /* Lookup the atom */
1250 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1253 if (NT_SUCCESS(Status
))
1259 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1261 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1265 SetLastNtError(Status
);
1271 ASSERT(IS_ATOM(ClassName
->Buffer
));
1272 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1281 _In_ PUNICODE_STRING ClassName
,
1282 IN HINSTANCE hInstance OPTIONAL
,
1283 IN PPROCESSINFO pi OPTIONAL
,
1284 OUT PCLS
*BaseClass OPTIONAL
,
1285 OUT PCLS
**Link OPTIONAL
)
1287 RTL_ATOM Atom
= (RTL_ATOM
)0;
1289 ASSERT(BaseClass
!= NULL
);
1291 if (IntGetAtomFromStringOrAtom(ClassName
,
1293 Atom
!= (RTL_ATOM
)0)
1297 /* Attempt to locate the class object */
1301 /* Step 1: Try to find an exact match of locally registered classes */
1302 Class
= IntFindClass(Atom
,
1304 &pi
->pclsPrivateList
,
1307 { TRACE("Step 1: 0x%p\n",Class
);
1311 /* Step 2: Try to find any globally registered class. The hInstance
1312 is not relevant for global classes */
1313 Class
= IntFindClass(Atom
,
1315 &pi
->pclsPublicList
,
1318 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1322 /* Step 3: Try to find any local class registered by user32 */
1323 Class
= IntFindClass(Atom
,
1325 &pi
->pclsPrivateList
,
1328 { TRACE("Step 3: 0x%p\n",Class
);
1332 /* Step 4: Try to find any global class registered by user32 */
1333 Class
= IntFindClass(Atom
,
1335 &pi
->pclsPublicList
,
1339 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1341 }else{TRACE("Step 4: 0x%p\n",Class
);}
1351 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1353 PCLS
*ClassLink
, Class
= NULL
;
1358 pti
= gptiDesktopThread
;
1360 pti
= PsGetCurrentThreadWin32Thread();
1362 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1364 UserRegisterSystemClasses();
1367 /* Check the class. */
1369 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1371 ClassAtom
= IntGetClassAtom(ClassName
,
1377 if (ClassAtom
== (RTL_ATOM
)0)
1379 if (IS_ATOM(ClassName
->Buffer
))
1381 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1385 ERR("Class \"%wZ\" not found\n", ClassName
);
1388 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1392 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1393 Class
= IntReferenceClass(Class
,
1398 ERR("Failed to reference window class!\n");
1406 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1407 IN PUNICODE_STRING ClassName
,
1408 IN PUNICODE_STRING MenuName
,
1416 RTL_ATOM Ret
= (RTL_ATOM
)0;
1418 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1420 pti
= GetW32ThreadInfo();
1424 // Need only to test for two conditions not four....... Fix more whine tests....
1425 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1426 ClassAtom
!= (RTL_ATOM
)0 &&
1427 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1429 Class
= IntFindClass( ClassAtom
,
1431 &pi
->pclsPrivateList
,
1434 if (Class
!= NULL
&& !Class
->Global
)
1436 // Local class already exists
1437 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1438 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1442 if (lpwcx
->style
& CS_GLOBALCLASS
)
1444 Class
= IntFindClass( ClassAtom
,
1446 &pi
->pclsPublicList
,
1449 if (Class
!= NULL
&& Class
->Global
)
1451 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1452 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1458 Class
= IntCreateClass(lpwcx
,
1470 /* Register the class */
1472 List
= &pi
->pclsPublicList
;
1474 List
= &pi
->pclsPrivateList
;
1476 Class
->pclsNext
= *List
;
1477 (void)InterlockedExchangePointer((PVOID
*)List
,
1480 Ret
= Class
->atomClassName
;
1484 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1491 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1492 IN HINSTANCE hInstance
,
1493 OUT PCLSMENUNAME pClassMenuName
)
1500 pi
= GetW32ProcessInfo();
1502 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1504 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1505 ClassAtom
= IntGetClassAtom(ClassName
,
1510 if (ClassAtom
== (RTL_ATOM
)0)
1512 TRACE("UserUnregisterClass: No Class found.\n");
1516 ASSERT(Class
!= NULL
);
1518 if (Class
->cWndReferenceCount
!= 0 ||
1519 Class
->pclsClone
!= NULL
)
1521 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1522 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1526 /* Must be a base class! */
1527 ASSERT(Class
->pclsBase
== Class
);
1529 /* Unlink the class */
1530 *Link
= Class
->pclsNext
;
1532 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1534 TRACE("Class 0x%p\n", Class
);
1535 TRACE("UserUnregisterClass: Good Exit!\n");
1536 Class
->atomClassName
= 0; // Don't let it linger...
1537 /* Finally free the resources */
1538 IntDestroyClass(Class
);
1541 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1546 UserGetClassName(IN PCLS Class
,
1547 IN OUT PUNICODE_STRING ClassName
,
1551 NTSTATUS Status
= STATUS_SUCCESS
;
1552 WCHAR szStaticTemp
[32];
1553 PWSTR szTemp
= NULL
;
1554 ULONG BufLen
= sizeof(szStaticTemp
);
1557 /* Note: Accessing the buffer in ClassName may raise an exception! */
1563 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1564 UNICODE_STRING UnicodeClassName
;
1566 /* Limit the size of the static buffer on the stack to the
1567 size of the buffer provided by the caller */
1568 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1570 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1573 /* Find out how big the buffer needs to be */
1574 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1575 Class
->atomClassName
,
1580 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1582 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1584 /* The buffer required exceeds the ansi buffer provided,
1585 pretend like we're using the ansi buffer and limit the
1586 size to the buffer size provided */
1587 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1590 /* Allocate a temporary buffer that can hold the unicode class name */
1591 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1596 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1600 /* Query the class name */
1601 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1602 Atom
? Atom
: Class
->atomClassName
,
1609 szTemp
= szStaticTemp
;
1611 if (NT_SUCCESS(Status
))
1613 /* Convert the atom name to ansi */
1615 RtlInitUnicodeString(&UnicodeClassName
,
1618 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1621 if (!NT_SUCCESS(Status
))
1623 SetLastNtError(Status
);
1628 Ret
= BufLen
/ sizeof(WCHAR
);
1632 BufLen
= ClassName
->MaximumLength
;
1634 /* Query the atom name */
1635 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1636 Atom
? Atom
: Class
->atomClassName
,
1642 if (!NT_SUCCESS(Status
))
1644 SetLastNtError(Status
);
1648 Ret
= BufLen
/ sizeof(WCHAR
);
1651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1653 SetLastNtError(_SEH2_GetExceptionCode());
1657 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1659 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1666 IntSetClassMenuName(IN PCLS Class
,
1667 IN PUNICODE_STRING MenuName
)
1671 /* Change the base class first */
1672 Class
= Class
->pclsBase
;
1674 if (MenuName
->Length
!= 0)
1676 ANSI_STRING AnsiString
;
1679 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1681 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1682 AnsiString
.MaximumLength
);
1683 if (strBufW
!= NULL
)
1689 /* Copy the unicode string */
1690 RtlCopyMemory(strBufW
,
1693 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1695 /* Create an ANSI copy of the string */
1696 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1697 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1700 if (!NT_SUCCESS(Status
))
1702 SetLastNtError(Status
);
1708 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1710 SetLastNtError(_SEH2_GetExceptionCode());
1716 /* Update the base class */
1717 IntFreeClassMenuName(Class
);
1718 Class
->lpszClientUnicodeMenuName
= strBufW
;
1719 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1720 Class
->MenuNameIsString
= TRUE
;
1722 /* Update the clones */
1723 Class
= Class
->pclsClone
;
1724 while (Class
!= NULL
)
1726 Class
->lpszClientUnicodeMenuName
= strBufW
;
1727 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1728 Class
->MenuNameIsString
= TRUE
;
1730 Class
= Class
->pclsNext
;
1735 ERR("Failed to copy class menu name!\n");
1736 UserHeapFree(strBufW
);
1740 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1744 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1746 /* Update the base class */
1747 IntFreeClassMenuName(Class
);
1748 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1749 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1750 Class
->MenuNameIsString
= FALSE
;
1752 /* Update the clones */
1753 Class
= Class
->pclsClone
;
1754 while (Class
!= NULL
)
1756 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1757 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1758 Class
->MenuNameIsString
= FALSE
;
1760 Class
= Class
->pclsNext
;
1769 #ifndef NEW_CURSORICON
1771 IntClassDestroyIcon(HANDLE hCurIcon
)
1773 PCURICON_OBJECT CurIcon
;
1776 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1779 ERR("hCurIcon was not found!\n");
1782 /* Note: IntDestroyCurIconObject will remove our reference for us! */
1783 Ret
= IntDestroyCurIconObject(CurIcon
, GetW32ProcessInfo());
1786 ERR("hCurIcon was not Destroyed!\n");
1793 UserSetClassLongPtr(IN PCLS Class
,
1795 IN ULONG_PTR NewLong
,
1799 #ifndef NEW_CURSORICON
1800 HANDLE hIconSmIntern
= NULL
;
1803 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1805 /* Change the information in the base class first, then update the clones */
1806 Class
= Class
->pclsBase
;
1812 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1814 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1815 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1817 EngSetLastError(ERROR_INVALID_PARAMETER
);
1821 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1823 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1824 certain architectures, maybe using RtlCopyMemory is a
1825 better choice for those architectures! */
1829 /* Update the clones */
1830 Class
= Class
->pclsClone
;
1831 while (Class
!= NULL
)
1833 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1834 Class
= Class
->pclsNext
;
1842 case GCL_CBWNDEXTRA
:
1843 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1844 Class
->cbwndExtra
= (INT
)NewLong
;
1846 /* Update the clones */
1847 Class
= Class
->pclsClone
;
1848 while (Class
!= NULL
)
1850 Class
->cbwndExtra
= (INT
)NewLong
;
1851 Class
= Class
->pclsNext
;
1856 case GCL_CBCLSEXTRA
:
1857 EngSetLastError(ERROR_INVALID_PARAMETER
);
1860 case GCLP_HBRBACKGROUND
:
1861 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1862 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1864 /* Update the clones */
1865 Class
= Class
->pclsClone
;
1866 while (Class
!= NULL
)
1868 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1869 Class
= Class
->pclsNext
;
1873 #ifdef NEW_CURSORICON
1876 PCURICON_OBJECT NewCursor
= NULL
;
1880 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1883 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1890 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1891 UserDereferenceObject(Class
->spcur
);
1904 Class
->spcur
= NewCursor
;
1906 /* Update the clones */
1907 Class
= Class
->pclsClone
;
1908 while (Class
!= NULL
)
1911 UserDereferenceObject(Class
->spcur
);
1913 UserReferenceObject(NewCursor
);
1914 Class
->spcur
= NewCursor
;
1915 Class
= Class
->pclsNext
;
1922 /* FIXME: Get handle from pointer to CURSOR object */
1923 Ret
= (ULONG_PTR
)Class
->hCursor
;
1924 Class
->hCursor
= (HANDLE
)NewLong
;
1926 /* Update the clones */
1927 Class
= Class
->pclsClone
;
1928 while (Class
!= NULL
)
1930 Class
->hCursor
= (HANDLE
)NewLong
;
1931 Class
= Class
->pclsNext
;
1937 // hIconSm, A handle to a small icon that is associated with the window class.
1938 // If this member is NULL, the system searches the icon resource specified by
1939 // the hIcon member for an icon of the appropriate size to use as the small icon.
1942 #ifdef NEW_CURSORICON
1944 PCURICON_OBJECT NewIcon
= NULL
;
1945 PCURICON_OBJECT NewSmallIcon
= NULL
;
1949 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1952 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1959 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1960 UserDereferenceObject(Class
->spicn
);
1973 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1975 /* We will change the small icon */
1976 UserDereferenceObject(Class
->spicnSm
);
1977 IntDestroyCurIconObject(Class
->spicnSm
);
1978 Class
->spicnSm
= NULL
;
1979 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1982 if (NewLong
&& !Class
->spicnSm
)
1984 /* Create the new small icon from the new large(?) one */
1985 HICON SmallIconHandle
= NULL
;
1986 if((NewIcon
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1987 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1989 SmallIconHandle
= co_IntCopyImage(
1992 UserGetSystemMetrics( SM_CXSMICON
),
1993 UserGetSystemMetrics( SM_CYSMICON
),
1994 LR_COPYFROMRESOURCE
);
1996 if (!SmallIconHandle
)
1998 /* Retry without copying from resource */
1999 SmallIconHandle
= co_IntCopyImage(
2002 UserGetSystemMetrics( SM_CXSMICON
),
2003 UserGetSystemMetrics( SM_CYSMICON
),
2006 if (SmallIconHandle
)
2009 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
2010 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2014 Class
->spicn
= NewIcon
;
2016 /* Update the clones */
2017 Class
= Class
->pclsClone
;
2018 while (Class
!= NULL
)
2021 UserDereferenceObject(Class
->spicn
);
2023 UserReferenceObject(NewIcon
);
2024 Class
->spicn
= NewIcon
;
2028 UserDereferenceObject(Class
->spicnSm
);
2029 UserReferenceObject(NewSmallIcon
);
2030 Class
->spicnSm
= NewSmallIcon
;
2031 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2033 Class
= Class
->pclsNext
;
2038 /* FIXME: Get handle from pointer to ICON object */
2039 Ret
= (ULONG_PTR
)Class
->hIcon
;
2040 if (Class
->hIcon
== (HANDLE
)NewLong
) break;
2041 if (Ret
&& Class
->hIconSmIntern
)
2043 IntClassDestroyIcon(Class
->hIconSmIntern
);
2044 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2045 Class
->hIconSmIntern
= NULL
;
2047 if (NewLong
&& !Class
->hIconSm
)
2049 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( (HICON
)NewLong
, IMAGE_ICON
,
2050 UserGetSystemMetrics( SM_CXSMICON
),
2051 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2052 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2054 Class
->hIcon
= (HANDLE
)NewLong
;
2056 /* Update the clones */
2057 Class
= Class
->pclsClone
;
2058 while (Class
!= NULL
)
2060 Class
->hIcon
= (HANDLE
)NewLong
;
2061 Class
->hIconSmIntern
= hIconSmIntern
;
2062 Class
= Class
->pclsNext
;
2068 #ifdef NEW_CURSORICON
2070 PCURICON_OBJECT NewSmallIcon
= NULL
;
2071 BOOLEAN NewIconFromCache
= FALSE
;
2075 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2078 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2084 /* Create the new small icon from the large one */
2085 HICON SmallIconHandle
= NULL
;
2086 if((Class
->spicn
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2087 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2089 SmallIconHandle
= co_IntCopyImage(
2090 UserHMGetHandle(Class
->spicn
),
2092 UserGetSystemMetrics( SM_CXSMICON
),
2093 UserGetSystemMetrics( SM_CYSMICON
),
2094 LR_COPYFROMRESOURCE
);
2096 if (!SmallIconHandle
)
2098 /* Retry without copying from resource */
2099 SmallIconHandle
= co_IntCopyImage(
2100 UserHMGetHandle(Class
->spicn
),
2102 UserGetSystemMetrics( SM_CXSMICON
),
2103 UserGetSystemMetrics( SM_CYSMICON
),
2106 if (SmallIconHandle
)
2109 NewSmallIcon
= UserGetCurIconObject(SmallIconHandle
);
2110 NewIconFromCache
= TRUE
;
2114 ERR("Failed getting a small icon for the class.\n");
2120 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2122 /* We must destroy the icon if we own it */
2123 IntDestroyCurIconObject(Class
->spicnSm
);
2128 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2130 UserDereferenceObject(Class
->spicnSm
);
2137 if (NewIconFromCache
)
2138 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2140 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2141 Class
->spicnSm
= NewSmallIcon
;
2143 /* Update the clones */
2144 Class
= Class
->pclsClone
;
2145 while (Class
!= NULL
)
2148 UserDereferenceObject(Class
->spicnSm
);
2150 UserReferenceObject(NewSmallIcon
);
2151 if (NewIconFromCache
)
2152 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2154 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2155 Class
->spicnSm
= NewSmallIcon
;
2156 Class
= Class
->pclsNext
;
2161 /* FIXME: Get handle from pointer to ICON object */
2162 Ret
= (ULONG_PTR
)Class
->hIconSm
;
2163 if (Class
->hIconSm
== (HANDLE
)NewLong
) break;
2164 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2166 if (Class
->hIconSmIntern
)
2168 IntClassDestroyIcon(Class
->hIconSmIntern
);
2169 Class
->hIconSmIntern
= NULL
;
2171 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2173 if (Class
->hIcon
&& !Class
->hIconSmIntern
)
2175 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( Class
->hIcon
, IMAGE_ICON
,
2176 UserGetSystemMetrics( SM_CXSMICON
),
2177 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2179 if (hIconSmIntern
) Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2180 //// FIXME: Very hacky here but it passes the tests....
2181 Ret
= 0; // Fixes 1009
2183 Class
->hIconSm
= (HANDLE
)NewLong
;
2185 /* Update the clones */
2186 Class
= Class
->pclsClone
;
2187 while (Class
!= NULL
)
2189 Class
->hIconSm
= (HANDLE
)NewLong
;
2190 Class
->hIconSmIntern
= hIconSmIntern
;
2191 Class
= Class
->pclsNext
;
2197 Ret
= (ULONG_PTR
)Class
->hModule
;
2198 Class
->hModule
= (HINSTANCE
)NewLong
;
2200 /* Update the clones */
2201 Class
= Class
->pclsClone
;
2202 while (Class
!= NULL
)
2204 Class
->hModule
= (HINSTANCE
)NewLong
;
2205 Class
= Class
->pclsNext
;
2211 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2213 if (!IntSetClassMenuName(Class
,
2216 ERR("Setting the class menu name failed!\n");
2219 /* FIXME: Really return NULL? Wine does so... */
2224 Ret
= (ULONG_PTR
)Class
->style
;
2225 Class
->style
= (UINT
)NewLong
;
2227 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2228 move the class to the appropriate list? For now, we save
2229 the original value in Class->Global, so we can always
2230 locate the appropriate list */
2232 /* Update the clones */
2233 Class
= Class
->pclsClone
;
2234 while (Class
!= NULL
)
2236 Class
->style
= (UINT
)NewLong
;
2237 Class
= Class
->pclsNext
;
2242 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2249 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2251 Ret
= (ULONG_PTR
)Class
->atomClassName
;
2252 if (!IntSetClassAtom(Class
,
2261 EngSetLastError(ERROR_INVALID_INDEX
);
2269 UserGetClassInfo(IN PCLS Class
,
2270 OUT PWNDCLASSEXW lpwcx
,
2272 HINSTANCE hInstance
)
2274 if (!Class
) return FALSE
;
2276 lpwcx
->style
= Class
->style
;
2278 // If fnId is set, clear the global bit. See wine class test check_style.
2280 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2282 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2284 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2285 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2286 #ifdef NEW_CURSORICON
2287 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2288 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2289 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2291 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME: Get handle from pointer */
2292 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME: Get handle from pointer */
2293 /* FIXME: Get handle from pointer */
2294 lpwcx
->hIconSm
= Class
->hIconSm
? Class
->hIconSm
: Class
->hIconSmIntern
;
2296 lpwcx
->hbrBackground
= Class
->hbrBackground
;
2298 /* Copy non-string to user first. */
2300 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
2302 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
2304 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2305 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2306 * lpszClientXxxMenuName should already be mapped to user space.
2308 /* Copy string ptr to user. */
2309 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
2310 Class
->MenuNameIsString
)
2312 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2313 (PVOID
)Class
->lpszClientAnsiMenuName
:
2314 (PVOID
)Class
->lpszClientUnicodeMenuName
);
2317 if (hInstance
== hModClient
)
2318 lpwcx
->hInstance
= NULL
;
2320 lpwcx
->hInstance
= hInstance
;
2322 /* FIXME: Return the string? Okay! This is performed in User32! */
2323 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2333 UserRegisterSystemClasses(VOID
)
2336 UNICODE_STRING ClassName
, MenuName
;
2337 PPROCESSINFO ppi
= GetW32ProcessInfo();
2344 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
2347 if ( hModClient
== NULL
)
2350 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
2351 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
2353 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
2355 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
2357 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
2361 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
2362 ClassName
.Length
= 0;
2363 ClassName
.MaximumLength
= 0;
2366 wc
.cbSize
= sizeof(wc
);
2367 wc
.style
= DefaultServerClasses
[i
].Style
;
2369 Flags
|= CSF_SERVERSIDEPROC
;
2371 if (DefaultServerClasses
[i
].ProcW
)
2373 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
2374 wc
.hInstance
= hModuleWin
;
2378 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
2379 wc
.hInstance
= hModClient
;
2383 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
2385 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
2386 hBrush
= DefaultServerClasses
[i
].hBrush
;
2387 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2389 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2391 wc
.hbrBackground
= hBrush
;
2392 wc
.lpszMenuName
= NULL
;
2393 wc
.lpszClassName
= ClassName
.Buffer
;
2396 Class
= IntCreateClass( &wc
,
2399 DefaultServerClasses
[i
].fiId
,
2405 Class
->pclsNext
= ppi
->pclsPublicList
;
2406 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2409 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2413 ERR("!!! Registering system class failed!\n");
2417 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2421 /* SYSCALLS *****************************************************************/
2425 NtUserRegisterClassExWOW(
2427 PUNICODE_STRING ClassName
,
2428 PUNICODE_STRING ClsNVersion
,
2429 PCLSMENUNAME pClassMenuName
,
2435 * Registers a new class with the window manager
2437 * lpwcx = Win32 extended window class structure
2438 * bUnicodeClass = Whether to send ANSI or unicode strings
2439 * to window procedures
2441 * Atom identifying the new class
2444 WNDCLASSEXW CapturedClassInfo
= {0};
2445 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2446 RTL_ATOM Ret
= (RTL_ATOM
)0;
2447 PPROCESSINFO ppi
= GetW32ProcessInfo();
2448 BOOL Exception
= FALSE
;
2450 if (Flags
& ~(CSF_ANSIPROC
))
2452 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2453 EngSetLastError(ERROR_INVALID_FLAGS
);
2457 UserEnterExclusive();
2459 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2461 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2463 UserRegisterSystemClasses();
2468 /* Probe the parameters and basic parameter checks */
2469 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2471 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2472 goto InvalidParameter
;
2476 sizeof(WNDCLASSEXW
),
2478 RtlCopyMemory(&CapturedClassInfo
,
2480 sizeof(WNDCLASSEXW
));
2482 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2484 ProbeForRead(pClassMenuName
,
2485 sizeof(CLSMENUNAME
),
2488 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2490 if ( (CapturedName
.Length
& 1) ||
2491 (CapturedMenuName
.Length
& 1) ||
2492 (CapturedClassInfo
.cbClsExtra
< 0) ||
2493 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2494 CapturedMenuName
.Length
+ sizeof(CLS
))
2495 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2496 (CapturedClassInfo
.cbWndExtra
< 0) ||
2497 (CapturedClassInfo
.hInstance
== NULL
) )
2499 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2500 goto InvalidParameter
;
2503 if (CapturedName
.Length
!= 0)
2505 ProbeForRead(CapturedName
.Buffer
,
2506 CapturedName
.Length
,
2511 if (!IS_ATOM(CapturedName
.Buffer
))
2513 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2514 goto InvalidParameter
;
2518 if (CapturedMenuName
.Length
!= 0)
2520 ProbeForRead(CapturedMenuName
.Buffer
,
2521 CapturedMenuName
.Length
,
2524 else if (CapturedMenuName
.Buffer
!= NULL
&&
2525 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2527 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2529 EngSetLastError(ERROR_INVALID_PARAMETER
);
2533 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2534 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2535 // If this pops up we know what todo!
2536 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2539 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2543 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2544 SetLastNtError(_SEH2_GetExceptionCode());
2551 /* Register the class */
2552 Ret
= UserRegisterClass(&CapturedClassInfo
,
2561 TRACE("NtUserRegisterClassExWOW Null Return!\n");
2570 NtUserSetClassLong(HWND hWnd
,
2572 ULONG_PTR dwNewLong
,
2579 UserEnterExclusive();
2581 pi
= GetW32ProcessInfo();
2583 Window
= UserGetWindowObject(hWnd
);
2586 if (Window
->head
.pti
->ppi
!= pi
)
2588 EngSetLastError(ERROR_ACCESS_DENIED
);
2594 UNICODE_STRING Value
;
2596 /* Probe the parameters */
2597 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2599 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2600 if (Value
.Length
& 1)
2602 goto InvalidParameter
;
2605 if (Value
.Length
!= 0)
2607 ProbeForRead(Value
.Buffer
,
2613 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2615 goto InvalidParameter
;
2617 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2620 EngSetLastError(ERROR_INVALID_PARAMETER
);
2625 dwNewLong
= (ULONG_PTR
)&Value
;
2628 Ret
= UserSetClassLongPtr(Window
->pcls
,
2633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2635 SetLastNtError(_SEH2_GetExceptionCode());
2654 * NOTE: Obsoleted in 32-bit windows
2661 NtUserUnregisterClass(
2662 IN PUNICODE_STRING ClassNameOrAtom
,
2663 IN HINSTANCE hInstance
,
2664 OUT PCLSMENUNAME pClassMenuName
)
2666 UNICODE_STRING SafeClassName
;
2670 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2671 if (!NT_SUCCESS(Status
))
2673 ERR("Error capturing the class name\n");
2674 SetLastNtError(Status
);
2678 UserEnterExclusive();
2680 /* Unregister the class */
2681 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2685 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2686 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2692 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2696 HINSTANCE hInstance
,
2697 PUNICODE_STRING ClassName
,
2698 LPWNDCLASSEXW lpWndClassEx
,
2699 LPWSTR
*ppszMenuName
,
2702 UNICODE_STRING SafeClassName
;
2703 WNDCLASSEXW Safewcexw
;
2705 RTL_ATOM ClassAtom
= 0;
2712 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2713 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2717 SetLastNtError(_SEH2_GetExceptionCode());
2718 _SEH2_YIELD(return FALSE
);
2722 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2723 if (!NT_SUCCESS(Status
))
2725 ERR("Error capturing the class name\n");
2726 SetLastNtError(Status
);
2730 // If null instance use client.
2731 if (!hInstance
) hInstance
= hModClient
;
2733 TRACE("GetClassInfo(%wZ, %p)\n", SafeClassName
, hInstance
);
2735 /* NOTE: Need exclusive lock because getting the wndproc might require the
2736 creation of a call procedure handle */
2737 UserEnterExclusive();
2739 ppi
= GetW32ProcessInfo();
2740 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2742 UserRegisterSystemClasses();
2745 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2750 if (ClassAtom
!= (RTL_ATOM
)0)
2752 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2756 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2766 /* Emulate Function. */
2767 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2769 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2772 /* We must return the atom of the class here instead of just TRUE. */
2773 /* Undocumented behavior! Return the class atom as a BOOL! */
2774 Ret
= (BOOL
)ClassAtom
;
2776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2778 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2784 if (!IS_ATOM(SafeClassName
.Buffer
))
2785 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2792 NtUserGetClassName (IN HWND hWnd
,
2794 OUT PUNICODE_STRING ClassName
)
2797 UNICODE_STRING CapturedClassName
;
2803 Window
= UserGetWindowObject(hWnd
);
2806 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2808 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2810 Atom
= gpsi
->atomSysClass
[iCls
];
2816 ProbeForWriteUnicodeString(ClassName
);
2817 CapturedClassName
= *ClassName
;
2819 /* Get the class name */
2820 Ret
= UserGetClassName(Window
->pcls
,
2827 /* Update the Length field */
2828 ClassName
->Length
= CapturedClassName
.Length
;
2831 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2833 SetLastNtError(_SEH2_GetExceptionCode());
2843 /* Return Pointer to Class structure. */
2847 HINSTANCE hInstance
,
2848 PUNICODE_STRING ClassName
)
2850 UNICODE_STRING SafeClassName
;
2853 RTL_ATOM ClassAtom
= 0;
2856 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2857 if (!NT_SUCCESS(Status
))
2859 ERR("Error capturing the class name\n");
2860 SetLastNtError(Status
);
2864 UserEnterExclusive();
2866 pi
= GetW32ProcessInfo();
2868 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2875 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2879 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2880 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2884 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.