2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: win32ss/user/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
10 DBG_DEFAULT_CHANNEL(UserClass
);
12 static PWSTR ControlsList
[] =
26 L
"DDEMLUnicodeClient",
28 L
"DDEMLUnicodeServer",
33 static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom
);
35 REGISTER_SYSCLASS DefaultServerClasses
[] =
37 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
38 CS_GLOBALCLASS
|CS_DBLCLKS
,
39 NULL
, // Use User32 procs
42 (HBRUSH
)(COLOR_BACKGROUND
),
46 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
47 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
48 NULL
, // Use User32 procs
55 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
56 CS_DBLCLKS
|CS_SAVEBITS
,
57 NULL
, // Use User32 procs
60 (HBRUSH
)(COLOR_MENU
+ 1),
65 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
66 NULL
, // Use User32 procs
67 sizeof(SBWND
)-sizeof(WND
),
74 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8006))), // Tooltips
75 CS_PARENTDC
|CS_DBLCLKS
,
76 NULL
, // Use User32 procs
84 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
86 NULL
, // Use User32 procs
95 NULL
, // Use User32 procs
109 { /* Function Ids to Class indexes. */
110 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
111 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
112 { FNID_MENU
, ICLS_MENU
},
113 { FNID_DESKTOP
, ICLS_DESKTOP
},
114 { FNID_SWITCH
, ICLS_SWITCH
},
115 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
116 { FNID_BUTTON
, ICLS_BUTTON
},
117 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
118 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
119 { FNID_DIALOG
, ICLS_DIALOG
},
120 { FNID_EDIT
, ICLS_EDIT
},
121 { FNID_LISTBOX
, ICLS_LISTBOX
},
122 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
123 { FNID_STATIC
, ICLS_STATIC
},
124 { FNID_IME
, ICLS_IME
},
125 { FNID_GHOST
, ICLS_GHOST
},
126 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
131 LookupFnIdToiCls(int FnId
, int *iCls
)
135 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
137 if (FnidToiCls
[i
].FnId
== FnId
)
139 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
147 _Must_inspect_result_
150 ProbeAndCaptureUnicodeStringOrAtom(
151 _Out_
_When_(return>=0, _At_(pustrOut
->Buffer
, _Post_ _Notnull_
)) PUNICODE_STRING pustrOut
,
152 __in_data_source(USER_MODE
) _In_ PUNICODE_STRING pustrUnsafe
)
154 NTSTATUS Status
= STATUS_SUCCESS
;
156 /* Default to NULL */
157 pustrOut
->Buffer
= NULL
;
161 ProbeForRead(pustrUnsafe
, sizeof(UNICODE_STRING
), 1);
163 /* Validate the string */
164 if ((pustrUnsafe
->Length
& 1) || (pustrUnsafe
->Buffer
== NULL
))
166 /* This is not legal */
167 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
170 /* Check if this is an atom */
171 if (IS_ATOM(pustrUnsafe
->Buffer
))
173 /* Copy the atom, length is 0 */
174 pustrOut
->MaximumLength
= pustrOut
->Length
= 0;
175 pustrOut
->Buffer
= pustrUnsafe
->Buffer
;
179 /* Get the length, maximum length includes zero termination */
180 pustrOut
->Length
= pustrUnsafe
->Length
;
181 pustrOut
->MaximumLength
= pustrOut
->Length
+ sizeof(WCHAR
);
183 /* Allocate a buffer */
184 pustrOut
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
185 pustrOut
->MaximumLength
,
187 if (!pustrOut
->Buffer
)
189 _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES
);
192 /* Copy the string and zero terminate it */
193 ProbeForRead(pustrUnsafe
->Buffer
, pustrOut
->Length
, 1);
194 RtlCopyMemory(pustrOut
->Buffer
, pustrUnsafe
->Buffer
, pustrOut
->Length
);
195 pustrOut
->Buffer
[pustrOut
->Length
/ sizeof(WCHAR
)] = L
'\0';
198 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
200 /* Check if we already allocated a buffer */
201 if (pustrOut
->Buffer
)
203 /* Free the buffer */
204 ExFreePoolWithTag(pustrOut
->Buffer
, TAG_STRING
);
205 Status
= _SEH2_GetExceptionCode();
213 /* WINDOWCLASS ***************************************************************/
216 IntFreeClassMenuName(IN OUT PCLS Class
)
218 /* Free the menu name, if it was changed and allocated */
219 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
221 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
222 Class
->lpszClientUnicodeMenuName
= NULL
;
223 Class
->lpszClientAnsiMenuName
= NULL
;
228 IntDestroyClass(IN OUT PCLS Class
)
232 /* There shouldn't be any clones anymore */
233 ASSERT(Class
->cWndReferenceCount
== 0);
234 ASSERT(Class
->pclsClone
== NULL
);
236 if (Class
->pclsBase
== Class
)
238 PCALLPROCDATA CallProc
, NextCallProc
;
240 /* Destroy allocated callproc handles */
241 CallProc
= Class
->spcpdFirst
;
242 while (CallProc
!= NULL
)
244 NextCallProc
= CallProc
->spcpdNext
;
246 CallProc
->spcpdNext
= NULL
;
247 DestroyCallProc(CallProc
);
249 CallProc
= NextCallProc
;
252 // Fixes running the static test then run class test issue.
253 // Some applications do not use UnregisterClass before exiting.
254 // Keep from reusing the same atom with case insensitive
255 // comparisons, remove registration of the atom if not zeroed.
256 if (Class
->atomClassName
)
257 IntDeregisterClassAtom(Class
->atomClassName
);
261 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
265 IntFreeClassMenuName(Class
);
269 UserDereferenceObject(Class
->spicn
);
271 UserDereferenceObject(Class
->spcur
);
274 UserDereferenceObject(Class
->spicnSm
);
275 /* Destroy the icon if we own it */
276 if ((Class
->CSF_flags
& CSF_CACHEDSMICON
)
277 && !(UserObjectInDestroy(UserHMGetHandle(Class
->spicnSm
))))
278 IntDestroyCurIconObject(Class
->spicnSm
);
281 pDesk
= Class
->rpdeskParent
;
282 Class
->rpdeskParent
= NULL
;
284 /* Free the structure */
287 DesktopHeapFree(pDesk
, Class
);
296 /* Clean all process classes. all process windows must cleaned first!! */
297 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
300 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
304 /* Free all local classes */
305 Class
= pi
->pclsPrivateList
;
306 while (Class
!= NULL
)
308 pi
->pclsPrivateList
= Class
->pclsNext
;
310 ASSERT(Class
->pclsBase
== Class
);
311 IntDestroyClass(Class
);
313 Class
= pi
->pclsPrivateList
;
316 /* Free all global classes */
317 Class
= pi
->pclsPublicList
;
318 while (Class
!= NULL
)
320 pi
->pclsPublicList
= Class
->pclsNext
;
322 ASSERT(Class
->pclsBase
== Class
);
323 IntDestroyClass(Class
);
325 Class
= pi
->pclsPublicList
;
331 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
338 if (ClassName
->Length
!= 0)
340 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
341 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
343 EngSetLastError(ERROR_INVALID_PARAMETER
);
350 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
354 AtomName
= ClassName
->Buffer
;
356 Status
= RtlAddAtomToAtomTable(gAtomTable
,
360 if (!NT_SUCCESS(Status
))
362 SetLastNtError(Status
);
370 RegisterControlAtoms(VOID
)
373 UNICODE_STRING ClassName
;
376 while ( i
< ICLS_DESKTOP
)
378 RtlInitUnicodeString(&ClassName
, ControlsList
[i
]);
379 if (IntRegisterClassAtom(&ClassName
, &Atom
))
381 gpsi
->atomSysClass
[i
] = Atom
;
382 TRACE("Reg Control Atom %ls: 0x%x\n", ControlsList
[i
], Atom
);
390 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
392 return RtlDeleteAtomFromAtomTable(gAtomTable
,
397 UserAddCallProcToClass(IN OUT PCLS Class
,
398 IN PCALLPROCDATA CallProc
)
402 ASSERT(CallProc
->spcpdNext
== NULL
);
404 BaseClass
= Class
->pclsBase
;
405 ASSERT(CallProc
->spcpdNext
== NULL
);
406 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
407 BaseClass
->spcpdFirst
= CallProc
;
409 /* Update all clones */
410 Class
= Class
->pclsClone
;
411 while (Class
!= NULL
)
413 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
414 Class
= Class
->pclsNext
;
419 IntSetClassAtom(IN OUT PCLS Class
,
420 IN PUNICODE_STRING ClassName
)
422 RTL_ATOM Atom
= (RTL_ATOM
)0;
424 /* Update the base class first */
425 Class
= Class
->pclsBase
;
427 if (!IntRegisterClassAtom(ClassName
,
433 IntDeregisterClassAtom(Class
->atomClassName
);
435 Class
->atomClassName
= Atom
;
437 /* Update the clones */
438 Class
= Class
->pclsClone
;
439 while (Class
!= NULL
)
441 Class
->atomClassName
= Atom
;
443 Class
= Class
->pclsNext
;
450 // Same as User32:IntGetClsWndProc.
453 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
456 WNDPROC gcpd
= NULL
, Ret
= NULL
;
458 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
460 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
462 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
465 Ret
= GETPFNCLIENTA(i
);
467 Ret
= GETPFNCLIENTW(i
);
472 Ret
= Class
->lpfnWndProc
;
474 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
478 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
479 Ret
= GETPFNCLIENTA(Class
->fnid
);
483 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
484 Ret
= GETPFNCLIENTW(Class
->fnid
);
488 if ( Ret
!= Class
->lpfnWndProc
||
489 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
492 gcpd
= (WNDPROC
)UserGetCPD( Class
,
493 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
496 return (gcpd
? gcpd
: Ret
);
502 IntSetClassWndProc(IN OUT PCLS Class
,
508 WNDPROC Ret
, chWndProc
;
510 Ret
= IntGetClassWndProc(Class
, Ansi
);
512 // If Server Side, downgrade to Client Side.
513 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
515 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
516 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
517 Class
->Unicode
= !Ansi
;
520 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
524 // Check if CallProc handle and retrieve previous call proc address and set.
525 if (IsCallProcHandle(WndProc
))
527 pcpd
= UserGetObject(gHandleTable
, WndProc
, TYPE_CALLPROC
);
528 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
531 Class
->lpfnWndProc
= chWndProc
;
536 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
537 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
539 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
541 chWndProc
= GETPFNSERVER(i
);
544 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
546 chWndProc
= GETPFNSERVER(i
);
550 // If match, set/reset to Server Side and clear ansi.
553 Class
->lpfnWndProc
= chWndProc
;
554 Class
->Unicode
= TRUE
;
555 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
556 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
560 Class
->Unicode
= !Ansi
;
563 Class
->CSF_flags
|= CSF_ANSIPROC
;
565 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
568 /* Update the clones */
569 chWndProc
= Class
->lpfnWndProc
;
571 Class
= Class
->pclsClone
;
572 while (Class
!= NULL
)
574 Class
->Unicode
= !Ansi
;
575 Class
->lpfnWndProc
= chWndProc
;
577 Class
= Class
->pclsNext
;
584 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
585 IN OUT PCLS
*ClassLink
,
591 ASSERT(Desktop
!= NULL
);
592 ASSERT(BaseClass
->pclsBase
== BaseClass
);
594 if (BaseClass
->rpdeskParent
== Desktop
)
596 /* It is most likely that a window is created on the same
597 desktop as the window class. */
602 if (BaseClass
->rpdeskParent
== NULL
)
604 ASSERT(BaseClass
->cWndReferenceCount
== 0);
605 ASSERT(BaseClass
->pclsClone
== NULL
);
607 /* Classes are also located in the shared heap when the class
608 was created before the thread attached to a desktop. As soon
609 as a window is created for such a class located on the shared
610 heap, the class is cloned into the desktop heap on which the
611 window is created. */
616 /* The user is asking for a class object on a different desktop,
618 Class
= BaseClass
->pclsClone
;
619 while (Class
!= NULL
)
621 if (Class
->rpdeskParent
== Desktop
)
623 ASSERT(Class
->pclsBase
== BaseClass
);
624 ASSERT(Class
->pclsClone
== NULL
);
628 Class
= Class
->pclsNext
;
634 /* The window is created on a different desktop, we need to
635 clone the class object to the desktop heap of the window! */
636 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
638 Class
= DesktopHeapAlloc(Desktop
,
643 /* Simply clone the class */
644 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
646 /* Reference our objects */
648 UserReferenceObject(Class
->spcur
);
650 UserReferenceObject(Class
->spicn
);
652 UserReferenceObject(Class
->spicnSm
);
654 TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
656 /* Restore module address if default user class Ref: Bug 4778 */
657 if ( Class
->hModule
!= hModClient
&&
658 Class
->fnid
<= FNID_GHOST
&&
659 Class
->fnid
>= FNID_BUTTON
)
661 Class
->hModule
= hModClient
;
662 TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class
, Class
->hModule
);
665 /* Update some pointers and link the class */
666 Class
->rpdeskParent
= Desktop
;
667 Class
->cWndReferenceCount
= 0;
669 if (BaseClass
->rpdeskParent
== NULL
)
671 /* We don't really need the base class on the shared
672 heap anymore, delete it so the only class left is
673 the clone we just created, which now serves as the
675 ASSERT(BaseClass
->pclsClone
== NULL
);
676 ASSERT(Class
->pclsClone
== NULL
);
677 Class
->pclsBase
= Class
;
678 Class
->pclsNext
= BaseClass
->pclsNext
;
680 /* Replace the base class */
681 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
684 /* Destroy the obsolete copy on the shared heap */
685 BaseClass
->pclsBase
= NULL
;
686 BaseClass
->pclsClone
= NULL
;
687 IntDestroyClass(BaseClass
);
691 /* Link in the clone */
692 Class
->pclsClone
= NULL
;
693 Class
->pclsBase
= BaseClass
;
694 Class
->pclsNext
= BaseClass
->pclsClone
;
695 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
701 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
708 IntReferenceClass(IN OUT PCLS BaseClass
,
709 IN OUT PCLS
*ClassLink
,
713 ASSERT(BaseClass
->pclsBase
== BaseClass
);
717 Class
= IntGetClassForDesktop(BaseClass
,
728 Class
->cWndReferenceCount
++;
736 IntMakeCloneBaseClass(IN OUT PCLS Class
,
737 IN OUT PCLS
*BaseClassLink
,
738 IN OUT PCLS
*CloneLink
)
742 ASSERT(Class
->pclsBase
!= Class
);
743 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
744 ASSERT(Class
->rpdeskParent
!= NULL
);
745 ASSERT(Class
->cWndReferenceCount
!= 0);
746 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
747 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
749 /* Unlink the clone */
750 *CloneLink
= Class
->pclsNext
;
751 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
753 /* Update the class information to make it a base class */
754 Class
->pclsBase
= Class
;
755 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
757 /* Update all clones */
758 Clone
= Class
->pclsClone
;
759 while (Clone
!= NULL
)
761 ASSERT(Clone
->pclsClone
== NULL
);
762 Clone
->pclsBase
= Class
;
764 Clone
= Clone
->pclsNext
;
767 /* Link in the new base class */
768 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
774 IntDereferenceClass(IN OUT PCLS Class
,
775 IN PDESKTOPINFO Desktop
,
778 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
780 ASSERT(Class
->cWndReferenceCount
>= 1);
782 BaseClass
= Class
->pclsBase
;
784 if (--Class
->cWndReferenceCount
== 0)
786 if (BaseClass
== Class
)
788 ASSERT(Class
->pclsBase
== Class
);
790 TRACE("IntDereferenceClass 0x%p\n", Class
);
791 /* Check if there are clones of the class on other desktops,
792 link the first clone in if possible. If there are no clones
793 then leave the class on the desktop heap. It will get moved
794 to the shared heap when the thread detaches. */
795 if (BaseClass
->pclsClone
!= NULL
)
797 if (BaseClass
->Global
)
798 PrevLink
= &pi
->pclsPublicList
;
800 PrevLink
= &pi
->pclsPrivateList
;
802 CurrentClass
= *PrevLink
;
803 while (CurrentClass
!= BaseClass
)
805 ASSERT(CurrentClass
!= NULL
);
807 PrevLink
= &CurrentClass
->pclsNext
;
808 CurrentClass
= CurrentClass
->pclsNext
;
811 ASSERT(*PrevLink
== BaseClass
);
813 /* Make the first clone become the new base class */
814 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
816 &BaseClass
->pclsClone
);
818 /* Destroy the class, there's still another clone of the class
819 that now serves as a base class. Make sure we don't destruct
820 resources shared by all classes (Base = NULL)! */
821 BaseClass
->pclsBase
= NULL
;
822 BaseClass
->pclsClone
= NULL
;
823 IntDestroyClass(BaseClass
);
828 TRACE("IntDereferenceClass1 0x%p\n", Class
);
830 /* Locate the cloned class and unlink it */
831 PrevLink
= &BaseClass
->pclsClone
;
832 CurrentClass
= BaseClass
->pclsClone
;
833 while (CurrentClass
!= Class
)
835 ASSERT(CurrentClass
!= NULL
);
837 PrevLink
= &CurrentClass
->pclsNext
;
838 CurrentClass
= CurrentClass
->pclsNext
;
841 ASSERT(CurrentClass
== Class
);
843 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
846 ASSERT(Class
->pclsBase
== BaseClass
);
847 ASSERT(Class
->pclsClone
== NULL
);
849 /* The class was just a clone, we don't need it anymore */
850 IntDestroyClass(Class
);
856 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
857 IN OUT PCLS
**ClassLinkPtr
)
862 ASSERT(Class
->pclsBase
== Class
);
863 ASSERT(Class
->rpdeskParent
!= NULL
);
864 ASSERT(Class
->cWndReferenceCount
== 0);
865 ASSERT(Class
->pclsClone
== NULL
);
867 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
869 /* Allocate the new base class on the shared heap */
870 NewClass
= UserHeapAlloc(ClassSize
);
871 if (NewClass
!= NULL
)
873 RtlCopyMemory(NewClass
,
877 NewClass
->rpdeskParent
= NULL
;
878 NewClass
->pclsBase
= NewClass
;
881 UserReferenceObject(NewClass
->spcur
);
883 UserReferenceObject(NewClass
->spicn
);
884 if (NewClass
->spicnSm
)
885 UserReferenceObject(NewClass
->spicnSm
);
887 /* Replace the class in the list */
888 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
890 *ClassLinkPtr
= &NewClass
->pclsNext
;
892 /* Free the obsolete class on the desktop heap */
893 Class
->pclsBase
= NULL
;
894 IntDestroyClass(Class
);
902 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
903 IN OUT PCLS
*ClassList
,
904 IN BOOL FreeOnFailure
,
907 PCLS Class
, NextClass
, *Link
;
909 /* NOTE: We only need to check base classes! When classes are no longer needed
910 on a desktop, the clones will be freed automatically as soon as possible.
911 However, we need to move base classes to the shared heap, as soon as
912 the last desktop heap where a class is allocated on is about to be destroyed.
913 If we didn't move the class to the shared heap, the class would become
916 ASSERT(Desktop
!= NULL
);
920 while (Class
!= NULL
)
922 NextClass
= Class
->pclsNext
;
924 ASSERT(Class
->pclsBase
== Class
);
926 if (Class
->rpdeskParent
== Desktop
&&
927 Class
->cWndReferenceCount
== 0)
929 /* There shouldn't be any clones around anymore! */
930 ASSERT(Class
->pclsClone
== NULL
);
932 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
933 /* FIXME: We could move the class to another desktop heap if there's still desktops
934 mapped into the process... */
936 /* Move the class to the shared heap */
937 if (IntMoveClassToSharedHeap(Class
,
940 ASSERT(*Link
== NextClass
);
944 ASSERT(NextClass
== Class
->pclsNext
);
948 /* Unlink the base class */
949 (void)InterlockedExchangePointer((PVOID
*)Link
,
952 /* We can free the old base class now */
953 Class
->pclsBase
= NULL
;
954 IntDestroyClass(Class
);
958 Link
= &Class
->pclsNext
;
964 Link
= &Class
->pclsNext
;
971 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
972 IN BOOL FreeOnFailure
)
977 pi
= GetW32ProcessInfo();
979 /* Check all local classes */
980 IntCheckDesktopClasses(Desktop
,
981 &pi
->pclsPrivateList
,
985 /* Check all global classes */
986 IntCheckDesktopClasses(Desktop
,
992 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
993 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1001 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
1002 IN PUNICODE_STRING ClassName
,
1003 IN PUNICODE_STRING MenuName
,
1006 IN PDESKTOP Desktop
,
1013 PWSTR pszMenuName
= NULL
;
1014 NTSTATUS Status
= STATUS_SUCCESS
;
1016 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
1017 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
1019 if (!IntRegisterClassAtom(ClassName
,
1022 ERR("Failed to register class atom!\n");
1026 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
1027 if (MenuName
->Length
!= 0)
1029 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1030 RtlUnicodeStringToAnsiSize(MenuName
));
1031 if (pszMenuName
== NULL
)
1035 if (Desktop
!= NULL
)
1037 Class
= DesktopHeapAlloc(Desktop
,
1042 /* FIXME: The class was created before being connected
1043 to a desktop. It is possible for the desktop window,
1044 but should it be allowed for any other case? */
1045 TRACE("This CLASS has no Desktop to heap from! Atom %u\n",Atom
);
1046 Class
= UserHeapAlloc(ClassSize
);
1053 RtlZeroMemory(Class
, ClassSize
);
1055 Class
->rpdeskParent
= Desktop
;
1056 Class
->pclsBase
= Class
;
1057 Class
->atomClassName
= Atom
;
1059 Class
->CSF_flags
= dwFlags
;
1061 if (LookupFnIdToiCls(Class
->fnid
, &iCls
) && gpsi
->atomSysClass
[iCls
] == 0)
1063 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1068 PWSTR pszMenuNameBuffer
= pszMenuName
;
1070 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1071 and string buffers might raise an exception! We don't want to
1073 // What?! If the user interface was written correctly this would not be an issue!
1074 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
1075 Class
->style
= lpwcx
->style
;
1076 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
1077 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
1078 Class
->hModule
= lpwcx
->hInstance
;
1079 Class
->spicn
= lpwcx
->hIcon
? UserGetCurIconObject(lpwcx
->hIcon
) : NULL
;
1080 Class
->spcur
= lpwcx
->hCursor
? UserGetCurIconObject(lpwcx
->hCursor
) : NULL
;
1081 Class
->spicnSm
= lpwcx
->hIconSm
? UserGetCurIconObject(lpwcx
->hIconSm
) : NULL
;
1083 Class
->hbrBackground
= lpwcx
->hbrBackground
;
1085 /* Make a copy of the string */
1086 if (pszMenuNameBuffer
!= NULL
)
1088 Class
->MenuNameIsString
= TRUE
;
1090 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
1091 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
1094 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1096 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
1099 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1101 /* Save an ANSI copy of the string */
1102 if (pszMenuNameBuffer
!= NULL
)
1104 ANSI_STRING AnsiString
;
1106 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
1107 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1108 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
1109 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1112 if (!NT_SUCCESS(Status
))
1114 ERR("Failed to convert unicode menu name to ansi!\n");
1116 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1121 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1123 /* Save kernel use menu name and ansi class name */
1124 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
1125 //Class->lpszAnsiClassName = FIXME
1127 /* Server Side overrides class calling type (A/W)!
1128 User32 whine test_builtinproc: "deftest"
1129 built-in winproc - window A/W type automatically detected */
1130 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
1134 /* Due to the wine class "deftest" and most likely no FNID to reference
1135 from, sort through the Server Side list and compare proc addresses
1136 for match. This method will be used in related code.
1138 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
1139 { // Open ANSI or Unicode, just match, set and break.
1140 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
1142 WndProc
= GETPFNSERVER(i
);
1145 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
1147 WndProc
= GETPFNSERVER(i
);
1152 { // If a hit, we are Server Side so set the right flags and proc.
1153 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
1154 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
1155 Class
->lpfnWndProc
= WndProc
;
1159 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1160 Class
->Unicode
= TRUE
;
1162 if (Class
->style
& CS_GLOBALCLASS
)
1163 Class
->Global
= TRUE
;
1165 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1167 Status
= _SEH2_GetExceptionCode();
1171 if (!NT_SUCCESS(Status
))
1173 ERR("Failed creating the class: 0x%x\n", Status
);
1175 SetLastNtError(Status
);
1177 if (pszMenuName
!= NULL
)
1178 UserHeapFree(pszMenuName
);
1180 DesktopHeapFree(Desktop
,
1184 IntDeregisterClassAtom(Atom
);
1190 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1192 if (pszMenuName
!= NULL
)
1193 UserHeapFree(pszMenuName
);
1195 IntDeregisterClassAtom(Atom
);
1197 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1200 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
1201 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1207 IntFindClass(IN RTL_ATOM Atom
,
1208 IN HINSTANCE hInstance
,
1210 OUT PCLS
**Link OPTIONAL
)
1212 PCLS Class
, *PrevLink
= ClassList
;
1215 while (Class
!= NULL
)
1217 if (Class
->atomClassName
== Atom
&&
1218 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1219 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1221 ASSERT(Class
->pclsBase
== Class
);
1228 PrevLink
= &Class
->pclsNext
;
1229 Class
= Class
->pclsNext
;
1238 IntGetAtomFromStringOrAtom(
1239 _In_ PUNICODE_STRING ClassName
,
1240 _Out_ RTL_ATOM
*Atom
)
1244 if (ClassName
->Length
!= 0)
1252 /* NOTE: Caller has to protect the call with SEH! */
1254 if (ClassName
->Length
!= 0)
1256 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1257 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1259 EngSetLastError(ERROR_INVALID_PARAMETER
);
1263 /* We need to make a local copy of the class name! The caller could
1264 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1265 We're protected by SEH, but the ranges that might be accessed were
1267 RtlCopyMemory(szBuf
,
1270 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1274 AtomName
= ClassName
->Buffer
;
1276 /* Lookup the atom */
1277 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1280 if (NT_SUCCESS(Status
))
1286 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1288 SetLastNtError(Status
);
1294 ASSERT(IS_ATOM(ClassName
->Buffer
));
1295 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1304 _In_ PUNICODE_STRING ClassName
,
1305 IN HINSTANCE hInstance OPTIONAL
,
1306 IN PPROCESSINFO pi OPTIONAL
,
1307 OUT PCLS
*BaseClass OPTIONAL
,
1308 OUT PCLS
**Link OPTIONAL
)
1310 RTL_ATOM Atom
= (RTL_ATOM
)0;
1312 ASSERT(BaseClass
!= NULL
);
1314 if (IntGetAtomFromStringOrAtom(ClassName
, &Atom
) &&
1315 Atom
!= (RTL_ATOM
)0)
1319 /* Attempt to locate the class object */
1323 /* Step 1: Try to find an exact match of locally registered classes */
1324 Class
= IntFindClass(Atom
,
1326 &pi
->pclsPrivateList
,
1329 { TRACE("Step 1: 0x%p\n",Class
);
1333 /* Step 2: Try to find any globally registered class. The hInstance
1334 is not relevant for global classes */
1335 Class
= IntFindClass(Atom
,
1337 &pi
->pclsPublicList
,
1340 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1344 /* Step 3: Try to find any local class registered by user32 */
1345 Class
= IntFindClass(Atom
,
1347 &pi
->pclsPrivateList
,
1350 { TRACE("Step 3: 0x%p\n",Class
);
1354 /* Step 4: Try to find any global class registered by user32 */
1355 Class
= IntFindClass(Atom
,
1357 &pi
->pclsPublicList
,
1362 }else{TRACE("Step 4: 0x%p\n",Class
);}
1376 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1378 PCLS
*ClassLink
, Class
= NULL
;
1383 pti
= gptiDesktopThread
;
1385 pti
= PsGetCurrentThreadWin32Thread();
1387 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1389 UserRegisterSystemClasses();
1392 /* Check the class. */
1394 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1396 ClassAtom
= IntGetClassAtom(ClassName
,
1402 if (ClassAtom
== (RTL_ATOM
)0)
1404 if (IS_ATOM(ClassName
->Buffer
))
1406 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1410 ERR("Class \"%wZ\" not found\n", ClassName
);
1416 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1417 Class
= IntReferenceClass(Class
,
1422 ERR("Failed to reference window class!\n");
1430 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1431 IN PUNICODE_STRING ClassName
,
1432 IN PUNICODE_STRING MenuName
,
1440 RTL_ATOM Ret
= (RTL_ATOM
)0;
1442 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1444 pti
= GetW32ThreadInfo();
1448 // Need only to test for two conditions not four....... Fix more whine tests....
1449 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1450 ClassAtom
!= (RTL_ATOM
)0 &&
1451 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1453 Class
= IntFindClass( ClassAtom
,
1455 &pi
->pclsPrivateList
,
1458 if (Class
!= NULL
&& !Class
->Global
)
1460 // Local class already exists
1461 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1462 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1466 if (lpwcx
->style
& CS_GLOBALCLASS
)
1468 Class
= IntFindClass( ClassAtom
,
1470 &pi
->pclsPublicList
,
1473 if (Class
!= NULL
&& Class
->Global
)
1475 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1476 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1482 Class
= IntCreateClass(lpwcx
,
1494 /* Register the class */
1496 List
= &pi
->pclsPublicList
;
1498 List
= &pi
->pclsPrivateList
;
1500 Class
->pclsNext
= *List
;
1501 (void)InterlockedExchangePointer((PVOID
*)List
,
1504 Ret
= Class
->atomClassName
;
1508 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1515 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1516 IN HINSTANCE hInstance
,
1517 OUT PCLSMENUNAME pClassMenuName
)
1524 pi
= GetW32ProcessInfo();
1526 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1528 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1529 ClassAtom
= IntGetClassAtom(ClassName
,
1534 if (ClassAtom
== (RTL_ATOM
)0)
1536 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1537 TRACE("UserUnregisterClass: No Class found.\n");
1541 ASSERT(Class
!= NULL
);
1543 if (Class
->cWndReferenceCount
!= 0 ||
1544 Class
->pclsClone
!= NULL
)
1546 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1547 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1551 /* Must be a base class! */
1552 ASSERT(Class
->pclsBase
== Class
);
1554 /* Unlink the class */
1555 *Link
= Class
->pclsNext
;
1557 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1559 TRACE("Class 0x%p\n", Class
);
1560 TRACE("UserUnregisterClass: Good Exit!\n");
1561 Class
->atomClassName
= 0; // Don't let it linger...
1562 /* Finally free the resources */
1563 IntDestroyClass(Class
);
1566 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1571 UserGetClassName(IN PCLS Class
,
1572 IN OUT PUNICODE_STRING ClassName
,
1576 NTSTATUS Status
= STATUS_SUCCESS
;
1577 WCHAR szStaticTemp
[32];
1578 PWSTR szTemp
= NULL
;
1579 ULONG BufLen
= sizeof(szStaticTemp
);
1582 /* Note: Accessing the buffer in ClassName may raise an exception! */
1588 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1589 UNICODE_STRING UnicodeClassName
;
1591 /* Limit the size of the static buffer on the stack to the
1592 size of the buffer provided by the caller */
1593 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1595 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1598 /* Find out how big the buffer needs to be */
1599 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1600 Class
->atomClassName
,
1605 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1607 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1609 /* The buffer required exceeds the ansi buffer provided,
1610 pretend like we're using the ansi buffer and limit the
1611 size to the buffer size provided */
1612 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1615 /* Allocate a temporary buffer that can hold the unicode class name */
1616 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1621 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1625 /* Query the class name */
1626 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1627 Atom
? Atom
: Class
->atomClassName
,
1634 szTemp
= szStaticTemp
;
1636 if (NT_SUCCESS(Status
))
1638 /* Convert the atom name to ansi */
1640 RtlInitUnicodeString(&UnicodeClassName
,
1643 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1646 if (!NT_SUCCESS(Status
))
1648 SetLastNtError(Status
);
1653 Ret
= BufLen
/ sizeof(WCHAR
);
1657 BufLen
= ClassName
->MaximumLength
;
1659 /* Query the atom name */
1660 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1661 Atom
? Atom
: Class
->atomClassName
,
1667 if (!NT_SUCCESS(Status
))
1669 SetLastNtError(Status
);
1673 Ret
= BufLen
/ sizeof(WCHAR
);
1676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1678 SetLastNtError(_SEH2_GetExceptionCode());
1682 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1684 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1691 IntSetClassMenuName(IN PCLS Class
,
1692 IN PUNICODE_STRING MenuName
)
1696 /* Change the base class first */
1697 Class
= Class
->pclsBase
;
1699 if (MenuName
->Length
!= 0)
1701 ANSI_STRING AnsiString
;
1704 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1706 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1707 AnsiString
.MaximumLength
);
1708 if (strBufW
!= NULL
)
1714 /* Copy the unicode string */
1715 RtlCopyMemory(strBufW
,
1718 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1720 /* Create an ANSI copy of the string */
1721 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1722 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1725 if (!NT_SUCCESS(Status
))
1727 SetLastNtError(Status
);
1733 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1735 SetLastNtError(_SEH2_GetExceptionCode());
1741 /* Update the base class */
1742 IntFreeClassMenuName(Class
);
1743 Class
->lpszClientUnicodeMenuName
= strBufW
;
1744 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1745 Class
->MenuNameIsString
= TRUE
;
1747 /* Update the clones */
1748 Class
= Class
->pclsClone
;
1749 while (Class
!= NULL
)
1751 Class
->lpszClientUnicodeMenuName
= strBufW
;
1752 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1753 Class
->MenuNameIsString
= TRUE
;
1755 Class
= Class
->pclsNext
;
1760 ERR("Failed to copy class menu name!\n");
1761 UserHeapFree(strBufW
);
1765 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1769 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1771 /* Update the base class */
1772 IntFreeClassMenuName(Class
);
1773 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1774 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1775 Class
->MenuNameIsString
= FALSE
;
1777 /* Update the clones */
1778 Class
= Class
->pclsClone
;
1779 while (Class
!= NULL
)
1781 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1782 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1783 Class
->MenuNameIsString
= FALSE
;
1785 Class
= Class
->pclsNext
;
1795 UserSetClassLongPtr(IN PCLS Class
,
1797 IN ULONG_PTR NewLong
,
1802 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1804 /* Change the information in the base class first, then update the clones */
1805 Class
= Class
->pclsBase
;
1811 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1813 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1814 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1816 EngSetLastError(ERROR_INVALID_PARAMETER
);
1820 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1822 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1823 certain architectures, maybe using RtlCopyMemory is a
1824 better choice for those architectures! */
1828 /* Update the clones */
1829 Class
= Class
->pclsClone
;
1830 while (Class
!= NULL
)
1832 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1833 Class
= Class
->pclsNext
;
1841 case GCL_CBWNDEXTRA
:
1842 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1843 Class
->cbwndExtra
= (INT
)NewLong
;
1845 /* Update the clones */
1846 Class
= Class
->pclsClone
;
1847 while (Class
!= NULL
)
1849 Class
->cbwndExtra
= (INT
)NewLong
;
1850 Class
= Class
->pclsNext
;
1855 case GCL_CBCLSEXTRA
:
1856 EngSetLastError(ERROR_INVALID_PARAMETER
);
1859 case GCLP_HBRBACKGROUND
:
1860 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1861 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1863 /* Update the clones */
1864 Class
= Class
->pclsClone
;
1865 while (Class
!= NULL
)
1867 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1868 Class
= Class
->pclsNext
;
1874 PCURICON_OBJECT NewCursor
= NULL
;
1878 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1881 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1888 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1889 UserDereferenceObject(Class
->spcur
);
1902 Class
->spcur
= NewCursor
;
1904 /* Update the clones */
1905 Class
= Class
->pclsClone
;
1906 while (Class
!= NULL
)
1909 UserDereferenceObject(Class
->spcur
);
1911 UserReferenceObject(NewCursor
);
1912 Class
->spcur
= NewCursor
;
1913 Class
= Class
->pclsNext
;
1920 // hIconSm, A handle to a small icon that is associated with the window class.
1921 // If this member is NULL, the system searches the icon resource specified by
1922 // the hIcon member for an icon of the appropriate size to use as the small icon.
1926 PCURICON_OBJECT NewIcon
= NULL
;
1927 PCURICON_OBJECT NewSmallIcon
= NULL
;
1931 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1934 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1941 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1942 UserDereferenceObject(Class
->spicn
);
1955 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1957 /* We will change the small icon */
1958 UserDereferenceObject(Class
->spicnSm
);
1959 IntDestroyCurIconObject(Class
->spicnSm
);
1960 Class
->spicnSm
= NULL
;
1961 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1964 if (NewLong
&& !Class
->spicnSm
)
1966 /* Create the new small icon from the new large(?) one */
1967 HICON SmallIconHandle
= NULL
;
1968 if((NewIcon
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1969 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1971 SmallIconHandle
= co_IntCopyImage(
1974 UserGetSystemMetrics( SM_CXSMICON
),
1975 UserGetSystemMetrics( SM_CYSMICON
),
1976 LR_COPYFROMRESOURCE
);
1978 if (!SmallIconHandle
)
1980 /* Retry without copying from resource */
1981 SmallIconHandle
= co_IntCopyImage(
1984 UserGetSystemMetrics( SM_CXSMICON
),
1985 UserGetSystemMetrics( SM_CYSMICON
),
1988 if (SmallIconHandle
)
1991 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
1992 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
1996 Class
->spicn
= NewIcon
;
1998 /* Update the clones */
1999 Class
= Class
->pclsClone
;
2000 while (Class
!= NULL
)
2003 UserDereferenceObject(Class
->spicn
);
2005 UserReferenceObject(NewIcon
);
2006 Class
->spicn
= NewIcon
;
2010 UserDereferenceObject(Class
->spicnSm
);
2011 UserReferenceObject(NewSmallIcon
);
2012 Class
->spicnSm
= NewSmallIcon
;
2013 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2015 Class
= Class
->pclsNext
;
2022 PCURICON_OBJECT NewSmallIcon
= NULL
;
2023 BOOLEAN NewIconFromCache
= FALSE
;
2027 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2030 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2036 /* Create the new small icon from the large one */
2037 HICON SmallIconHandle
= NULL
;
2038 if((Class
->spicn
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2039 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2041 SmallIconHandle
= co_IntCopyImage(
2042 UserHMGetHandle(Class
->spicn
),
2044 UserGetSystemMetrics( SM_CXSMICON
),
2045 UserGetSystemMetrics( SM_CYSMICON
),
2046 LR_COPYFROMRESOURCE
);
2048 if (!SmallIconHandle
)
2050 /* Retry without copying from resource */
2051 SmallIconHandle
= co_IntCopyImage(
2052 UserHMGetHandle(Class
->spicn
),
2054 UserGetSystemMetrics( SM_CXSMICON
),
2055 UserGetSystemMetrics( SM_CYSMICON
),
2058 if (SmallIconHandle
)
2061 NewSmallIcon
= UserGetCurIconObject(SmallIconHandle
);
2062 NewIconFromCache
= TRUE
;
2066 ERR("Failed getting a small icon for the class.\n");
2072 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2074 /* We must destroy the icon if we own it */
2075 IntDestroyCurIconObject(Class
->spicnSm
);
2080 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2082 UserDereferenceObject(Class
->spicnSm
);
2089 if (NewIconFromCache
)
2090 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2092 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2093 Class
->spicnSm
= NewSmallIcon
;
2095 /* Update the clones */
2096 Class
= Class
->pclsClone
;
2097 while (Class
!= NULL
)
2100 UserDereferenceObject(Class
->spicnSm
);
2102 UserReferenceObject(NewSmallIcon
);
2103 if (NewIconFromCache
)
2104 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2106 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2107 Class
->spicnSm
= NewSmallIcon
;
2108 Class
= Class
->pclsNext
;
2114 Ret
= (ULONG_PTR
)Class
->hModule
;
2115 Class
->hModule
= (HINSTANCE
)NewLong
;
2117 /* Update the clones */
2118 Class
= Class
->pclsClone
;
2119 while (Class
!= NULL
)
2121 Class
->hModule
= (HINSTANCE
)NewLong
;
2122 Class
= Class
->pclsNext
;
2128 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2130 if (!IntSetClassMenuName(Class
,
2133 ERR("Setting the class menu name failed!\n");
2136 /* FIXME: Really return NULL? Wine does so... */
2141 Ret
= (ULONG_PTR
)Class
->style
;
2142 Class
->style
= (UINT
)NewLong
;
2144 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2145 move the class to the appropriate list? For now, we save
2146 the original value in Class->Global, so we can always
2147 locate the appropriate list */
2149 /* Update the clones */
2150 Class
= Class
->pclsClone
;
2151 while (Class
!= NULL
)
2153 Class
->style
= (UINT
)NewLong
;
2154 Class
= Class
->pclsNext
;
2159 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2166 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2168 Ret
= (ULONG_PTR
)Class
->atomClassName
;
2169 if (!IntSetClassAtom(Class
,
2178 EngSetLastError(ERROR_INVALID_INDEX
);
2186 UserGetClassInfo(IN PCLS Class
,
2187 OUT PWNDCLASSEXW lpwcx
,
2189 HINSTANCE hInstance
)
2191 if (!Class
) return FALSE
;
2193 lpwcx
->style
= Class
->style
;
2195 // If fnId is set, clear the global bit. See wine class test check_style.
2197 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2199 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2201 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2202 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2203 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2204 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2205 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2206 lpwcx
->hbrBackground
= Class
->hbrBackground
;
2208 /* Copy non-string to user first. */
2210 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
2212 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
2214 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2215 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2216 * lpszClientXxxMenuName should already be mapped to user space.
2218 /* Copy string ptr to user. */
2219 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
2220 Class
->MenuNameIsString
)
2222 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2223 (PVOID
)Class
->lpszClientAnsiMenuName
:
2224 (PVOID
)Class
->lpszClientUnicodeMenuName
);
2227 if (hInstance
== hModClient
)
2228 lpwcx
->hInstance
= NULL
;
2230 lpwcx
->hInstance
= hInstance
;
2232 /* FIXME: Return the string? Okay! This is performed in User32! */
2233 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2239 // Register System Classes....
2243 UserRegisterSystemClasses(VOID
)
2246 UNICODE_STRING ClassName
, MenuName
;
2247 PPROCESSINFO ppi
= GetW32ProcessInfo();
2254 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
2257 if ( hModClient
== NULL
)
2260 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
2261 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
2263 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
2265 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
2267 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
2271 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
2272 ClassName
.Length
= 0;
2273 ClassName
.MaximumLength
= 0;
2276 wc
.cbSize
= sizeof(wc
);
2277 wc
.style
= DefaultServerClasses
[i
].Style
;
2279 Flags
|= CSF_SERVERSIDEPROC
;
2281 if (DefaultServerClasses
[i
].ProcW
)
2283 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
2284 wc
.hInstance
= hModuleWin
;
2288 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
2289 wc
.hInstance
= hModClient
;
2293 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
2296 //// System Cursors should be initilized!!!
2298 if (DefaultServerClasses
[i
].hCursor
== (HICON
)OCR_NORMAL
)
2300 if (SYSTEMCUR(ARROW
) == NULL
)
2302 ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n");
2306 wc
.hCursor
= UserHMGetHandle(SYSTEMCUR(ARROW
));
2310 hBrush
= DefaultServerClasses
[i
].hBrush
;
2311 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2313 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2315 wc
.hbrBackground
= hBrush
;
2316 wc
.lpszMenuName
= NULL
;
2317 wc
.lpszClassName
= ClassName
.Buffer
;
2320 Class
= IntCreateClass( &wc
,
2323 DefaultServerClasses
[i
].fiId
,
2329 Class
->pclsNext
= ppi
->pclsPublicList
;
2330 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2333 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2337 ERR("!!! Registering system class failed!\n");
2341 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2345 /* SYSCALLS *****************************************************************/
2349 NtUserRegisterClassExWOW(
2351 PUNICODE_STRING ClassName
,
2352 PUNICODE_STRING ClsNVersion
,
2353 PCLSMENUNAME pClassMenuName
,
2359 * Registers a new class with the window manager
2361 * lpwcx = Win32 extended window class structure
2362 * bUnicodeClass = Whether to send ANSI or unicode strings
2363 * to window procedures
2365 * Atom identifying the new class
2368 WNDCLASSEXW CapturedClassInfo
= {0};
2369 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2370 RTL_ATOM Ret
= (RTL_ATOM
)0;
2371 PPROCESSINFO ppi
= GetW32ProcessInfo();
2372 BOOL Exception
= FALSE
;
2374 if (Flags
& ~(CSF_ANSIPROC
))
2376 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2377 EngSetLastError(ERROR_INVALID_FLAGS
);
2381 UserEnterExclusive();
2383 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2385 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2387 UserRegisterSystemClasses();
2392 /* Probe the parameters and basic parameter checks */
2393 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2395 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2396 goto InvalidParameter
;
2400 sizeof(WNDCLASSEXW
),
2402 RtlCopyMemory(&CapturedClassInfo
,
2404 sizeof(WNDCLASSEXW
));
2406 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2408 ProbeForRead(pClassMenuName
,
2409 sizeof(CLSMENUNAME
),
2412 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2414 if ( (CapturedName
.Length
& 1) ||
2415 (CapturedMenuName
.Length
& 1) ||
2416 (CapturedClassInfo
.cbClsExtra
< 0) ||
2417 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2418 CapturedMenuName
.Length
+ sizeof(CLS
))
2419 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2420 (CapturedClassInfo
.cbWndExtra
< 0) ||
2421 (CapturedClassInfo
.hInstance
== NULL
) )
2423 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2424 goto InvalidParameter
;
2427 if (CapturedName
.Length
!= 0)
2429 ProbeForRead(CapturedName
.Buffer
,
2430 CapturedName
.Length
,
2435 if (!IS_ATOM(CapturedName
.Buffer
))
2437 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2438 goto InvalidParameter
;
2442 if (CapturedMenuName
.Length
!= 0)
2444 ProbeForRead(CapturedMenuName
.Buffer
,
2445 CapturedMenuName
.Length
,
2448 else if (CapturedMenuName
.Buffer
!= NULL
&&
2449 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2451 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2453 EngSetLastError(ERROR_INVALID_PARAMETER
);
2457 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2458 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2459 // If this pops up we know what todo!
2460 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2463 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2467 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2468 SetLastNtError(_SEH2_GetExceptionCode());
2475 /* Register the class */
2476 Ret
= UserRegisterClass(&CapturedClassInfo
,
2485 TRACE("NtUserRegisterClassExWOW Null Return!\n");
2494 NtUserSetClassLong(HWND hWnd
,
2496 ULONG_PTR dwNewLong
,
2503 UserEnterExclusive();
2505 pi
= GetW32ProcessInfo();
2507 Window
= UserGetWindowObject(hWnd
);
2510 if (Window
->head
.pti
->ppi
!= pi
)
2512 EngSetLastError(ERROR_ACCESS_DENIED
);
2518 UNICODE_STRING Value
;
2520 /* Probe the parameters */
2521 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2523 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2524 if (Value
.Length
& 1)
2526 goto InvalidParameter
;
2529 if (Value
.Length
!= 0)
2531 ProbeForRead(Value
.Buffer
,
2537 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2539 goto InvalidParameter
;
2541 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2544 EngSetLastError(ERROR_INVALID_PARAMETER
);
2549 dwNewLong
= (ULONG_PTR
)&Value
;
2552 Ret
= UserSetClassLongPtr(Window
->pcls
,
2561 if (Ret
&& Ret
!= dwNewLong
)
2562 UserPaintCaption(Window
, DC_ICON
);
2566 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2568 SetLastNtError(_SEH2_GetExceptionCode());
2587 * NOTE: Obsoleted in 32-bit windows
2594 NtUserUnregisterClass(
2595 IN PUNICODE_STRING ClassNameOrAtom
,
2596 IN HINSTANCE hInstance
,
2597 OUT PCLSMENUNAME pClassMenuName
)
2599 UNICODE_STRING SafeClassName
;
2603 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2604 if (!NT_SUCCESS(Status
))
2606 ERR("Error capturing the class name\n");
2607 SetLastNtError(Status
);
2611 UserEnterExclusive();
2613 /* Unregister the class */
2614 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2618 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2619 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2625 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2629 HINSTANCE hInstance
,
2630 PUNICODE_STRING ClassName
,
2631 LPWNDCLASSEXW lpWndClassEx
,
2632 LPWSTR
*ppszMenuName
,
2635 UNICODE_STRING SafeClassName
;
2636 WNDCLASSEXW Safewcexw
;
2638 RTL_ATOM ClassAtom
= 0;
2645 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2646 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2650 SetLastNtError(_SEH2_GetExceptionCode());
2651 _SEH2_YIELD(return FALSE
);
2655 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2656 if (!NT_SUCCESS(Status
))
2658 ERR("Error capturing the class name\n");
2659 SetLastNtError(Status
);
2663 // If null instance use client.
2664 if (!hInstance
) hInstance
= hModClient
;
2666 TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName
, hInstance
);
2668 /* NOTE: Need exclusive lock because getting the wndproc might require the
2669 creation of a call procedure handle */
2670 UserEnterExclusive();
2672 ppi
= GetW32ProcessInfo();
2673 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2675 UserRegisterSystemClasses();
2678 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2683 if (ClassAtom
!= (RTL_ATOM
)0)
2685 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2689 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2699 /* Emulate Function. */
2700 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2702 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2705 /* We must return the atom of the class here instead of just TRUE. */
2706 /* Undocumented behavior! Return the class atom as a BOOL! */
2707 Ret
= (BOOL
)ClassAtom
;
2709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2711 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2717 if (!IS_ATOM(SafeClassName
.Buffer
))
2718 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2725 NtUserGetClassName (IN HWND hWnd
,
2727 OUT PUNICODE_STRING ClassName
)
2730 UNICODE_STRING CapturedClassName
;
2736 Window
= UserGetWindowObject(hWnd
);
2739 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2741 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2743 Atom
= gpsi
->atomSysClass
[iCls
];
2749 ProbeForWriteUnicodeString(ClassName
);
2750 CapturedClassName
= *ClassName
;
2752 /* Get the class name */
2753 Ret
= UserGetClassName(Window
->pcls
,
2760 /* Update the Length field */
2761 ClassName
->Length
= CapturedClassName
.Length
;
2764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2766 SetLastNtError(_SEH2_GetExceptionCode());
2776 /* Return Pointer to Class structure. */
2780 HINSTANCE hInstance
,
2781 PUNICODE_STRING ClassName
)
2783 UNICODE_STRING SafeClassName
;
2786 RTL_ATOM ClassAtom
= 0;
2789 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2790 if (!NT_SUCCESS(Status
))
2792 ERR("Error capturing the class name\n");
2793 SetLastNtError(Status
);
2797 UserEnterExclusive();
2799 pi
= GetW32ProcessInfo();
2801 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2808 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2812 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2813 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2817 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.