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
);
258 // Dereference non-versioned class name
259 if (Class
->atomNVClassName
)
260 IntDeregisterClassAtom(Class
->atomNVClassName
);
264 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
268 IntFreeClassMenuName(Class
);
272 UserDereferenceObject(Class
->spicn
);
274 UserDereferenceObject(Class
->spcur
);
277 UserDereferenceObject(Class
->spicnSm
);
278 /* Destroy the icon if we own it */
279 if ((Class
->CSF_flags
& CSF_CACHEDSMICON
)
280 && !(UserObjectInDestroy(UserHMGetHandle(Class
->spicnSm
))))
281 IntDestroyCurIconObject(Class
->spicnSm
);
284 pDesk
= Class
->rpdeskParent
;
285 Class
->rpdeskParent
= NULL
;
287 /* Free the structure */
290 DesktopHeapFree(pDesk
, Class
);
299 /* Clean all process classes. all process windows must cleaned first!! */
300 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
303 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
307 /* Free all local classes */
308 Class
= pi
->pclsPrivateList
;
309 while (Class
!= NULL
)
311 pi
->pclsPrivateList
= Class
->pclsNext
;
313 ASSERT(Class
->pclsBase
== Class
);
314 IntDestroyClass(Class
);
316 Class
= pi
->pclsPrivateList
;
319 /* Free all global classes */
320 Class
= pi
->pclsPublicList
;
321 while (Class
!= NULL
)
323 pi
->pclsPublicList
= Class
->pclsNext
;
325 ASSERT(Class
->pclsBase
== Class
);
326 IntDestroyClass(Class
);
328 Class
= pi
->pclsPublicList
;
334 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
341 if (ClassName
->Length
!= 0)
343 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
344 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
346 EngSetLastError(ERROR_INVALID_PARAMETER
);
353 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
357 AtomName
= ClassName
->Buffer
;
359 Status
= RtlAddAtomToAtomTable(gAtomTable
,
363 if (!NT_SUCCESS(Status
))
365 SetLastNtError(Status
);
373 RegisterControlAtoms(VOID
)
376 UNICODE_STRING ClassName
;
379 while ( i
< ICLS_DESKTOP
)
381 RtlInitUnicodeString(&ClassName
, ControlsList
[i
]);
382 if (IntRegisterClassAtom(&ClassName
, &Atom
))
384 gpsi
->atomSysClass
[i
] = Atom
;
385 TRACE("Reg Control Atom %ls: 0x%x\n", ControlsList
[i
], Atom
);
393 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
395 return RtlDeleteAtomFromAtomTable(gAtomTable
,
400 UserAddCallProcToClass(IN OUT PCLS Class
,
401 IN PCALLPROCDATA CallProc
)
405 ASSERT(CallProc
->spcpdNext
== NULL
);
407 BaseClass
= Class
->pclsBase
;
408 ASSERT(CallProc
->spcpdNext
== NULL
);
409 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
410 BaseClass
->spcpdFirst
= CallProc
;
412 /* Update all clones */
413 Class
= Class
->pclsClone
;
414 while (Class
!= NULL
)
416 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
417 Class
= Class
->pclsNext
;
422 IntSetClassAtom(IN OUT PCLS Class
,
423 IN PUNICODE_STRING ClassName
)
425 RTL_ATOM Atom
= (RTL_ATOM
)0;
427 /* Update the base class first */
428 Class
= Class
->pclsBase
;
429 if (ClassName
->Length
> 0)
431 if (!IntRegisterClassAtom(ClassName
,
434 ERR("RegisterClassAtom failed ! %x\n", EngGetLastError());
440 if (IS_ATOM(ClassName
->Buffer
))
442 Atom
= (ATOM
)((ULONG_PTR
)ClassName
->Buffer
& 0xffff); // XXX: are we missing refcount here ?
446 EngSetLastError(ERROR_INVALID_PARAMETER
);
451 IntDeregisterClassAtom(Class
->atomNVClassName
);
453 Class
->atomNVClassName
= Atom
;
455 /* Update the clones */
456 Class
= Class
->pclsClone
;
457 while (Class
!= NULL
)
459 Class
->atomNVClassName
= Atom
;
461 Class
= Class
->pclsNext
;
468 // Same as User32:IntGetClsWndProc.
471 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
474 WNDPROC gcpd
= NULL
, Ret
= NULL
;
476 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
478 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
480 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
483 Ret
= GETPFNCLIENTA(i
);
485 Ret
= GETPFNCLIENTW(i
);
490 Ret
= Class
->lpfnWndProc
;
492 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
496 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
497 Ret
= GETPFNCLIENTA(Class
->fnid
);
501 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
502 Ret
= GETPFNCLIENTW(Class
->fnid
);
506 if ( Ret
!= Class
->lpfnWndProc
||
507 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
510 gcpd
= (WNDPROC
)UserGetCPD( Class
,
511 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
514 return (gcpd
? gcpd
: Ret
);
520 IntSetClassWndProc(IN OUT PCLS Class
,
526 WNDPROC Ret
, chWndProc
;
528 Ret
= IntGetClassWndProc(Class
, Ansi
);
530 // If Server Side, downgrade to Client Side.
531 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
533 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
534 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
535 Class
->Unicode
= !Ansi
;
538 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
542 // Check if CallProc handle and retrieve previous call proc address and set.
543 if (IsCallProcHandle(WndProc
))
545 pcpd
= UserGetObject(gHandleTable
, WndProc
, TYPE_CALLPROC
);
546 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
549 Class
->lpfnWndProc
= chWndProc
;
554 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
555 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
557 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
559 chWndProc
= GETPFNSERVER(i
);
562 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
564 chWndProc
= GETPFNSERVER(i
);
568 // If match, set/reset to Server Side and clear ansi.
571 Class
->lpfnWndProc
= chWndProc
;
572 Class
->Unicode
= TRUE
;
573 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
574 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
578 Class
->Unicode
= !Ansi
;
581 Class
->CSF_flags
|= CSF_ANSIPROC
;
583 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
586 /* Update the clones */
587 chWndProc
= Class
->lpfnWndProc
;
589 Class
= Class
->pclsClone
;
590 while (Class
!= NULL
)
592 Class
->Unicode
= !Ansi
;
593 Class
->lpfnWndProc
= chWndProc
;
595 Class
= Class
->pclsNext
;
602 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
603 IN OUT PCLS
*ClassLink
,
609 ASSERT(Desktop
!= NULL
);
610 ASSERT(BaseClass
->pclsBase
== BaseClass
);
612 if (BaseClass
->rpdeskParent
== Desktop
)
614 /* It is most likely that a window is created on the same
615 desktop as the window class. */
620 if (BaseClass
->rpdeskParent
== NULL
)
622 ASSERT(BaseClass
->cWndReferenceCount
== 0);
623 ASSERT(BaseClass
->pclsClone
== NULL
);
625 /* Classes are also located in the shared heap when the class
626 was created before the thread attached to a desktop. As soon
627 as a window is created for such a class located on the shared
628 heap, the class is cloned into the desktop heap on which the
629 window is created. */
634 /* The user is asking for a class object on a different desktop,
636 Class
= BaseClass
->pclsClone
;
637 while (Class
!= NULL
)
639 if (Class
->rpdeskParent
== Desktop
)
641 ASSERT(Class
->pclsBase
== BaseClass
);
642 ASSERT(Class
->pclsClone
== NULL
);
646 Class
= Class
->pclsNext
;
652 /* The window is created on a different desktop, we need to
653 clone the class object to the desktop heap of the window! */
654 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
656 Class
= DesktopHeapAlloc(Desktop
,
661 /* Simply clone the class */
662 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
664 /* Reference our objects */
666 UserReferenceObject(Class
->spcur
);
668 UserReferenceObject(Class
->spicn
);
670 UserReferenceObject(Class
->spicnSm
);
672 TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
674 /* Restore module address if default user class Ref: Bug 4778 */
675 if ( Class
->hModule
!= hModClient
&&
676 Class
->fnid
<= FNID_GHOST
&&
677 Class
->fnid
>= FNID_BUTTON
)
679 Class
->hModule
= hModClient
;
680 TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class
, Class
->hModule
);
683 /* Update some pointers and link the class */
684 Class
->rpdeskParent
= Desktop
;
685 Class
->cWndReferenceCount
= 0;
687 if (BaseClass
->rpdeskParent
== NULL
)
689 /* We don't really need the base class on the shared
690 heap anymore, delete it so the only class left is
691 the clone we just created, which now serves as the
693 ASSERT(BaseClass
->pclsClone
== NULL
);
694 ASSERT(Class
->pclsClone
== NULL
);
695 Class
->pclsBase
= Class
;
696 Class
->pclsNext
= BaseClass
->pclsNext
;
698 /* Replace the base class */
699 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
702 /* Destroy the obsolete copy on the shared heap */
703 BaseClass
->pclsBase
= NULL
;
704 BaseClass
->pclsClone
= NULL
;
705 IntDestroyClass(BaseClass
);
709 /* Link in the clone */
710 Class
->pclsClone
= NULL
;
711 Class
->pclsBase
= BaseClass
;
712 Class
->pclsNext
= BaseClass
->pclsClone
;
713 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
719 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
726 IntReferenceClass(IN OUT PCLS BaseClass
,
727 IN OUT PCLS
*ClassLink
,
731 ASSERT(BaseClass
->pclsBase
== BaseClass
);
735 Class
= IntGetClassForDesktop(BaseClass
,
746 Class
->cWndReferenceCount
++;
754 IntMakeCloneBaseClass(IN OUT PCLS Class
,
755 IN OUT PCLS
*BaseClassLink
,
756 IN OUT PCLS
*CloneLink
)
760 ASSERT(Class
->pclsBase
!= Class
);
761 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
762 ASSERT(Class
->rpdeskParent
!= NULL
);
763 ASSERT(Class
->cWndReferenceCount
!= 0);
764 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
765 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
767 /* Unlink the clone */
768 *CloneLink
= Class
->pclsNext
;
769 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
771 /* Update the class information to make it a base class */
772 Class
->pclsBase
= Class
;
773 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
775 /* Update all clones */
776 Clone
= Class
->pclsClone
;
777 while (Clone
!= NULL
)
779 ASSERT(Clone
->pclsClone
== NULL
);
780 Clone
->pclsBase
= Class
;
782 Clone
= Clone
->pclsNext
;
785 /* Link in the new base class */
786 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
792 IntDereferenceClass(IN OUT PCLS Class
,
793 IN PDESKTOPINFO Desktop
,
796 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
798 ASSERT(Class
->cWndReferenceCount
>= 1);
800 BaseClass
= Class
->pclsBase
;
802 if (--Class
->cWndReferenceCount
== 0)
804 if (BaseClass
== Class
)
806 ASSERT(Class
->pclsBase
== Class
);
808 TRACE("IntDereferenceClass 0x%p\n", Class
);
809 /* Check if there are clones of the class on other desktops,
810 link the first clone in if possible. If there are no clones
811 then leave the class on the desktop heap. It will get moved
812 to the shared heap when the thread detaches. */
813 if (BaseClass
->pclsClone
!= NULL
)
815 if (BaseClass
->Global
)
816 PrevLink
= &pi
->pclsPublicList
;
818 PrevLink
= &pi
->pclsPrivateList
;
820 CurrentClass
= *PrevLink
;
821 while (CurrentClass
!= BaseClass
)
823 ASSERT(CurrentClass
!= NULL
);
825 PrevLink
= &CurrentClass
->pclsNext
;
826 CurrentClass
= CurrentClass
->pclsNext
;
829 ASSERT(*PrevLink
== BaseClass
);
831 /* Make the first clone become the new base class */
832 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
834 &BaseClass
->pclsClone
);
836 /* Destroy the class, there's still another clone of the class
837 that now serves as a base class. Make sure we don't destruct
838 resources shared by all classes (Base = NULL)! */
839 BaseClass
->pclsBase
= NULL
;
840 BaseClass
->pclsClone
= NULL
;
841 IntDestroyClass(BaseClass
);
846 TRACE("IntDereferenceClass1 0x%p\n", Class
);
848 /* Locate the cloned class and unlink it */
849 PrevLink
= &BaseClass
->pclsClone
;
850 CurrentClass
= BaseClass
->pclsClone
;
851 while (CurrentClass
!= Class
)
853 ASSERT(CurrentClass
!= NULL
);
855 PrevLink
= &CurrentClass
->pclsNext
;
856 CurrentClass
= CurrentClass
->pclsNext
;
859 ASSERT(CurrentClass
== Class
);
861 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
864 ASSERT(Class
->pclsBase
== BaseClass
);
865 ASSERT(Class
->pclsClone
== NULL
);
867 /* The class was just a clone, we don't need it anymore */
868 IntDestroyClass(Class
);
874 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
875 IN OUT PCLS
**ClassLinkPtr
)
880 ASSERT(Class
->pclsBase
== Class
);
881 ASSERT(Class
->rpdeskParent
!= NULL
);
882 ASSERT(Class
->cWndReferenceCount
== 0);
883 ASSERT(Class
->pclsClone
== NULL
);
885 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
887 /* Allocate the new base class on the shared heap */
888 NewClass
= UserHeapAlloc(ClassSize
);
889 if (NewClass
!= NULL
)
891 RtlCopyMemory(NewClass
,
895 NewClass
->rpdeskParent
= NULL
;
896 NewClass
->pclsBase
= NewClass
;
899 UserReferenceObject(NewClass
->spcur
);
901 UserReferenceObject(NewClass
->spicn
);
902 if (NewClass
->spicnSm
)
903 UserReferenceObject(NewClass
->spicnSm
);
905 /* Replace the class in the list */
906 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
908 *ClassLinkPtr
= &NewClass
->pclsNext
;
910 /* Free the obsolete class on the desktop heap */
911 Class
->pclsBase
= NULL
;
912 IntDestroyClass(Class
);
920 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
921 IN OUT PCLS
*ClassList
,
922 IN BOOL FreeOnFailure
,
925 PCLS Class
, NextClass
, *Link
;
927 /* NOTE: We only need to check base classes! When classes are no longer needed
928 on a desktop, the clones will be freed automatically as soon as possible.
929 However, we need to move base classes to the shared heap, as soon as
930 the last desktop heap where a class is allocated on is about to be destroyed.
931 If we didn't move the class to the shared heap, the class would become
934 ASSERT(Desktop
!= NULL
);
938 while (Class
!= NULL
)
940 NextClass
= Class
->pclsNext
;
942 ASSERT(Class
->pclsBase
== Class
);
944 if (Class
->rpdeskParent
== Desktop
&&
945 Class
->cWndReferenceCount
== 0)
947 /* There shouldn't be any clones around anymore! */
948 ASSERT(Class
->pclsClone
== NULL
);
950 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
951 /* FIXME: We could move the class to another desktop heap if there's still desktops
952 mapped into the process... */
954 /* Move the class to the shared heap */
955 if (IntMoveClassToSharedHeap(Class
,
958 ASSERT(*Link
== NextClass
);
962 ASSERT(NextClass
== Class
->pclsNext
);
966 /* Unlink the base class */
967 (void)InterlockedExchangePointer((PVOID
*)Link
,
970 /* We can free the old base class now */
971 Class
->pclsBase
= NULL
;
972 IntDestroyClass(Class
);
976 Link
= &Class
->pclsNext
;
982 Link
= &Class
->pclsNext
;
989 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
990 IN BOOL FreeOnFailure
)
995 pi
= GetW32ProcessInfo();
997 /* Check all local classes */
998 IntCheckDesktopClasses(Desktop
,
999 &pi
->pclsPrivateList
,
1003 /* Check all global classes */
1004 IntCheckDesktopClasses(Desktop
,
1005 &pi
->pclsPublicList
,
1010 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
1011 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1019 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
1020 IN PUNICODE_STRING ClassName
,
1021 IN PUNICODE_STRING ClassVersion
,
1022 IN PUNICODE_STRING MenuName
,
1025 IN PDESKTOP Desktop
,
1030 RTL_ATOM Atom
, verAtom
;
1032 PWSTR pszMenuName
= NULL
;
1033 NTSTATUS Status
= STATUS_SUCCESS
;
1035 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
1036 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
1038 if (!IntRegisterClassAtom(ClassName
,
1041 ERR("Failed to register class atom!\n");
1045 if (!IntRegisterClassAtom(ClassVersion
,
1048 ERR("Failed to register version class atom!\n");
1049 IntDeregisterClassAtom(Atom
);
1053 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
1054 if (MenuName
->Length
!= 0)
1056 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1057 RtlUnicodeStringToAnsiSize(MenuName
));
1058 if (pszMenuName
== NULL
)
1062 if (Desktop
!= NULL
)
1064 Class
= DesktopHeapAlloc(Desktop
,
1069 /* FIXME: The class was created before being connected
1070 to a desktop. It is possible for the desktop window,
1071 but should it be allowed for any other case? */
1072 TRACE("This CLASS has no Desktop to heap from! Atom %u\n",Atom
);
1073 Class
= UserHeapAlloc(ClassSize
);
1080 RtlZeroMemory(Class
, ClassSize
);
1082 Class
->rpdeskParent
= Desktop
;
1083 Class
->pclsBase
= Class
;
1084 Class
->atomClassName
= verAtom
;
1085 Class
->atomNVClassName
= Atom
;
1087 Class
->CSF_flags
= dwFlags
;
1089 if (LookupFnIdToiCls(Class
->fnid
, &iCls
) && gpsi
->atomSysClass
[iCls
] == 0)
1091 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1096 PWSTR pszMenuNameBuffer
= pszMenuName
;
1098 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1099 and string buffers might raise an exception! We don't want to
1101 // What?! If the user interface was written correctly this would not be an issue!
1102 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
1103 Class
->style
= lpwcx
->style
;
1104 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
1105 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
1106 Class
->hModule
= lpwcx
->hInstance
;
1107 Class
->spicn
= lpwcx
->hIcon
? UserGetCurIconObject(lpwcx
->hIcon
) : NULL
;
1108 Class
->spcur
= lpwcx
->hCursor
? UserGetCurIconObject(lpwcx
->hCursor
) : NULL
;
1109 Class
->spicnSm
= lpwcx
->hIconSm
? UserGetCurIconObject(lpwcx
->hIconSm
) : NULL
;
1111 Class
->hbrBackground
= lpwcx
->hbrBackground
;
1113 /* Make a copy of the string */
1114 if (pszMenuNameBuffer
!= NULL
)
1116 Class
->MenuNameIsString
= TRUE
;
1118 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
1119 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
1122 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1124 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
1127 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1129 /* Save an ANSI copy of the string */
1130 if (pszMenuNameBuffer
!= NULL
)
1132 ANSI_STRING AnsiString
;
1134 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
1135 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1136 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
1137 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1140 if (!NT_SUCCESS(Status
))
1142 ERR("Failed to convert unicode menu name to ansi!\n");
1144 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1149 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1151 /* Save kernel use menu name and ansi class name */
1152 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
1153 //Class->lpszAnsiClassName = FIXME
1155 /* Server Side overrides class calling type (A/W)!
1156 User32 whine test_builtinproc: "deftest"
1157 built-in winproc - window A/W type automatically detected */
1158 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
1162 /* Due to the wine class "deftest" and most likely no FNID to reference
1163 from, sort through the Server Side list and compare proc addresses
1164 for match. This method will be used in related code.
1166 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
1167 { // Open ANSI or Unicode, just match, set and break.
1168 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
1170 WndProc
= GETPFNSERVER(i
);
1173 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
1175 WndProc
= GETPFNSERVER(i
);
1180 { // If a hit, we are Server Side so set the right flags and proc.
1181 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
1182 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
1183 Class
->lpfnWndProc
= WndProc
;
1187 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1188 Class
->Unicode
= TRUE
;
1190 if (Class
->style
& CS_GLOBALCLASS
)
1191 Class
->Global
= TRUE
;
1193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1195 Status
= _SEH2_GetExceptionCode();
1199 if (!NT_SUCCESS(Status
))
1201 ERR("Failed creating the class: 0x%x\n", Status
);
1203 SetLastNtError(Status
);
1205 if (pszMenuName
!= NULL
)
1206 UserHeapFree(pszMenuName
);
1208 DesktopHeapFree(Desktop
,
1212 IntDeregisterClassAtom(verAtom
);
1213 IntDeregisterClassAtom(Atom
);
1219 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1221 if (pszMenuName
!= NULL
)
1222 UserHeapFree(pszMenuName
);
1224 IntDeregisterClassAtom(Atom
);
1225 IntDeregisterClassAtom(verAtom
);
1227 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1230 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and version atom 0x%x and hInstance 0x%p, global %u\n",
1231 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, verAtom
, Class
->hModule
, Class
->Global
);
1237 IntFindClass(IN RTL_ATOM Atom
,
1238 IN HINSTANCE hInstance
,
1240 OUT PCLS
**Link OPTIONAL
)
1242 PCLS Class
, *PrevLink
= ClassList
;
1245 while (Class
!= NULL
)
1247 if (Class
->atomClassName
== Atom
&&
1248 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1249 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1251 ASSERT(Class
->pclsBase
== Class
);
1258 PrevLink
= &Class
->pclsNext
;
1259 Class
= Class
->pclsNext
;
1268 IntGetAtomFromStringOrAtom(
1269 _In_ PUNICODE_STRING ClassName
,
1270 _Out_ RTL_ATOM
*Atom
)
1274 if (ClassName
->Length
!= 0)
1282 /* NOTE: Caller has to protect the call with SEH! */
1284 if (ClassName
->Length
!= 0)
1286 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1287 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1289 EngSetLastError(ERROR_INVALID_PARAMETER
);
1293 /* We need to make a local copy of the class name! The caller could
1294 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1295 We're protected by SEH, but the ranges that might be accessed were
1297 RtlCopyMemory(szBuf
,
1300 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1304 AtomName
= ClassName
->Buffer
;
1306 /* Lookup the atom */
1307 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1310 if (NT_SUCCESS(Status
))
1316 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1318 SetLastNtError(Status
);
1324 ASSERT(IS_ATOM(ClassName
->Buffer
));
1325 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1334 _In_ PUNICODE_STRING ClassName
,
1335 IN HINSTANCE hInstance OPTIONAL
,
1336 IN PPROCESSINFO pi OPTIONAL
,
1337 OUT PCLS
*BaseClass OPTIONAL
,
1338 OUT PCLS
**Link OPTIONAL
)
1340 RTL_ATOM Atom
= (RTL_ATOM
)0;
1342 ASSERT(BaseClass
!= NULL
);
1344 if (IntGetAtomFromStringOrAtom(ClassName
, &Atom
) &&
1345 Atom
!= (RTL_ATOM
)0)
1349 /* Attempt to locate the class object */
1353 /* Step 1: Try to find an exact match of locally registered classes */
1354 Class
= IntFindClass(Atom
,
1356 &pi
->pclsPrivateList
,
1359 { TRACE("Step 1: 0x%p\n",Class
);
1363 /* Step 2: Try to find any globally registered class. The hInstance
1364 is not relevant for global classes */
1365 Class
= IntFindClass(Atom
,
1367 &pi
->pclsPublicList
,
1370 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1374 /* Step 3: Try to find any local class registered by user32 */
1375 Class
= IntFindClass(Atom
,
1377 &pi
->pclsPrivateList
,
1380 { TRACE("Step 3: 0x%p\n",Class
);
1384 /* Step 4: Try to find any global class registered by user32 */
1385 Class
= IntFindClass(Atom
,
1387 &pi
->pclsPublicList
,
1392 }else{TRACE("Step 4: 0x%p\n",Class
);}
1406 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1408 PCLS
*ClassLink
, Class
= NULL
;
1413 pti
= gptiDesktopThread
;
1415 pti
= PsGetCurrentThreadWin32Thread();
1417 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1419 UserRegisterSystemClasses();
1422 /* Check the class. */
1424 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1426 ClassAtom
= IntGetClassAtom(ClassName
,
1432 if (ClassAtom
== (RTL_ATOM
)0)
1434 if (IS_ATOM(ClassName
->Buffer
))
1436 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1440 ERR("Class \"%wZ\" not found\n", ClassName
);
1446 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1447 Class
= IntReferenceClass(Class
,
1452 ERR("Failed to reference window class!\n");
1460 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1461 IN PUNICODE_STRING ClassName
,
1462 IN PUNICODE_STRING ClassVersion
,
1463 IN PUNICODE_STRING MenuName
,
1471 RTL_ATOM Ret
= (RTL_ATOM
)0;
1473 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1475 pti
= GetW32ThreadInfo();
1479 // Need only to test for two conditions not four....... Fix more whine tests....
1480 if ( IntGetAtomFromStringOrAtom( ClassVersion
, &ClassAtom
) &&
1481 ClassAtom
!= (RTL_ATOM
)0 &&
1482 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1484 Class
= IntFindClass( ClassAtom
,
1486 &pi
->pclsPrivateList
,
1489 if (Class
!= NULL
&& !Class
->Global
)
1491 // Local class already exists
1492 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1493 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1497 if (lpwcx
->style
& CS_GLOBALCLASS
)
1499 Class
= IntFindClass( ClassAtom
,
1501 &pi
->pclsPublicList
,
1504 if (Class
!= NULL
&& Class
->Global
)
1506 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1507 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1513 Class
= IntCreateClass(lpwcx
,
1526 /* Register the class */
1528 List
= &pi
->pclsPublicList
;
1530 List
= &pi
->pclsPrivateList
;
1532 Class
->pclsNext
= *List
;
1533 (void)InterlockedExchangePointer((PVOID
*)List
,
1536 Ret
= Class
->atomNVClassName
;
1540 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1547 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1548 IN HINSTANCE hInstance
,
1549 OUT PCLSMENUNAME pClassMenuName
)
1556 pi
= GetW32ProcessInfo();
1558 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1560 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1561 ClassAtom
= IntGetClassAtom(ClassName
,
1566 if (ClassAtom
== (RTL_ATOM
)0)
1568 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1569 TRACE("UserUnregisterClass: No Class found.\n");
1573 ASSERT(Class
!= NULL
);
1575 if (Class
->cWndReferenceCount
!= 0 ||
1576 Class
->pclsClone
!= NULL
)
1578 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1579 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1583 /* Must be a base class! */
1584 ASSERT(Class
->pclsBase
== Class
);
1586 /* Unlink the class */
1587 *Link
= Class
->pclsNext
;
1589 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1591 TRACE("Class 0x%p\n", Class
);
1592 TRACE("UserUnregisterClass: Good Exit!\n");
1593 Class
->atomClassName
= 0; // Don't let it linger...
1594 /* Finally free the resources */
1595 IntDestroyClass(Class
);
1598 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1603 UserGetClassName(IN PCLS Class
,
1604 IN OUT PUNICODE_STRING ClassName
,
1608 NTSTATUS Status
= STATUS_SUCCESS
;
1609 WCHAR szStaticTemp
[32];
1610 PWSTR szTemp
= NULL
;
1611 ULONG BufLen
= sizeof(szStaticTemp
);
1614 /* Note: Accessing the buffer in ClassName may raise an exception! */
1620 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1621 UNICODE_STRING UnicodeClassName
;
1623 /* Limit the size of the static buffer on the stack to the
1624 size of the buffer provided by the caller */
1625 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1627 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1630 /* Find out how big the buffer needs to be */
1631 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1632 Class
->atomClassName
,
1637 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1639 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1641 /* The buffer required exceeds the ansi buffer provided,
1642 pretend like we're using the ansi buffer and limit the
1643 size to the buffer size provided */
1644 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1647 /* Allocate a temporary buffer that can hold the unicode class name */
1648 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1653 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1657 /* Query the class name */
1658 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1659 Atom
? Atom
: Class
->atomNVClassName
,
1666 szTemp
= szStaticTemp
;
1668 if (NT_SUCCESS(Status
))
1670 /* Convert the atom name to ansi */
1672 RtlInitUnicodeString(&UnicodeClassName
,
1675 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1678 if (!NT_SUCCESS(Status
))
1680 SetLastNtError(Status
);
1685 Ret
= BufLen
/ sizeof(WCHAR
);
1689 BufLen
= ClassName
->MaximumLength
;
1691 /* Query the atom name */
1692 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1693 Atom
? Atom
: Class
->atomNVClassName
,
1699 if (!NT_SUCCESS(Status
))
1701 SetLastNtError(Status
);
1705 Ret
= BufLen
/ sizeof(WCHAR
);
1708 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1710 SetLastNtError(_SEH2_GetExceptionCode());
1714 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1716 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1723 IntSetClassMenuName(IN PCLS Class
,
1724 IN PUNICODE_STRING MenuName
)
1728 /* Change the base class first */
1729 Class
= Class
->pclsBase
;
1731 if (MenuName
->Length
!= 0)
1733 ANSI_STRING AnsiString
;
1736 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1738 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1739 AnsiString
.MaximumLength
);
1740 if (strBufW
!= NULL
)
1746 /* Copy the unicode string */
1747 RtlCopyMemory(strBufW
,
1750 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1752 /* Create an ANSI copy of the string */
1753 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1754 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1757 if (!NT_SUCCESS(Status
))
1759 SetLastNtError(Status
);
1765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1767 SetLastNtError(_SEH2_GetExceptionCode());
1773 /* Update the base class */
1774 IntFreeClassMenuName(Class
);
1775 Class
->lpszClientUnicodeMenuName
= strBufW
;
1776 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1777 Class
->MenuNameIsString
= TRUE
;
1779 /* Update the clones */
1780 Class
= Class
->pclsClone
;
1781 while (Class
!= NULL
)
1783 Class
->lpszClientUnicodeMenuName
= strBufW
;
1784 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1785 Class
->MenuNameIsString
= TRUE
;
1787 Class
= Class
->pclsNext
;
1792 ERR("Failed to copy class menu name!\n");
1793 UserHeapFree(strBufW
);
1797 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1801 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1803 /* Update the base class */
1804 IntFreeClassMenuName(Class
);
1805 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1806 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1807 Class
->MenuNameIsString
= FALSE
;
1809 /* Update the clones */
1810 Class
= Class
->pclsClone
;
1811 while (Class
!= NULL
)
1813 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1814 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1815 Class
->MenuNameIsString
= FALSE
;
1817 Class
= Class
->pclsNext
;
1827 UserSetClassLongPtr(IN PCLS Class
,
1829 IN ULONG_PTR NewLong
,
1834 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1836 /* Change the information in the base class first, then update the clones */
1837 Class
= Class
->pclsBase
;
1843 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1845 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1846 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1848 EngSetLastError(ERROR_INVALID_PARAMETER
);
1852 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1854 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1855 certain architectures, maybe using RtlCopyMemory is a
1856 better choice for those architectures! */
1860 /* Update the clones */
1861 Class
= Class
->pclsClone
;
1862 while (Class
!= NULL
)
1864 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1865 Class
= Class
->pclsNext
;
1873 case GCL_CBWNDEXTRA
:
1874 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1875 Class
->cbwndExtra
= (INT
)NewLong
;
1877 /* Update the clones */
1878 Class
= Class
->pclsClone
;
1879 while (Class
!= NULL
)
1881 Class
->cbwndExtra
= (INT
)NewLong
;
1882 Class
= Class
->pclsNext
;
1887 case GCL_CBCLSEXTRA
:
1888 EngSetLastError(ERROR_INVALID_PARAMETER
);
1891 case GCLP_HBRBACKGROUND
:
1892 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1893 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1895 /* Update the clones */
1896 Class
= Class
->pclsClone
;
1897 while (Class
!= NULL
)
1899 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1900 Class
= Class
->pclsNext
;
1906 PCURICON_OBJECT NewCursor
= NULL
;
1910 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1913 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1920 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1921 UserDereferenceObject(Class
->spcur
);
1934 Class
->spcur
= NewCursor
;
1936 /* Update the clones */
1937 Class
= Class
->pclsClone
;
1938 while (Class
!= NULL
)
1941 UserDereferenceObject(Class
->spcur
);
1943 UserReferenceObject(NewCursor
);
1944 Class
->spcur
= NewCursor
;
1945 Class
= Class
->pclsNext
;
1952 // hIconSm, A handle to a small icon that is associated with the window class.
1953 // If this member is NULL, the system searches the icon resource specified by
1954 // the hIcon member for an icon of the appropriate size to use as the small icon.
1958 PCURICON_OBJECT NewIcon
= NULL
;
1959 PCURICON_OBJECT NewSmallIcon
= NULL
;
1963 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1966 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1973 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1974 UserDereferenceObject(Class
->spicn
);
1987 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1989 /* We will change the small icon */
1990 UserDereferenceObject(Class
->spicnSm
);
1991 IntDestroyCurIconObject(Class
->spicnSm
);
1992 Class
->spicnSm
= NULL
;
1993 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1996 if (NewLong
&& !Class
->spicnSm
)
1998 /* Create the new small icon from the new large(?) one */
1999 HICON SmallIconHandle
= NULL
;
2000 if((NewIcon
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2001 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2003 SmallIconHandle
= co_IntCopyImage(
2006 UserGetSystemMetrics( SM_CXSMICON
),
2007 UserGetSystemMetrics( SM_CYSMICON
),
2008 LR_COPYFROMRESOURCE
);
2010 if (!SmallIconHandle
)
2012 /* Retry without copying from resource */
2013 SmallIconHandle
= co_IntCopyImage(
2016 UserGetSystemMetrics( SM_CXSMICON
),
2017 UserGetSystemMetrics( SM_CYSMICON
),
2020 if (SmallIconHandle
)
2023 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
2024 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2028 Class
->spicn
= NewIcon
;
2030 /* Update the clones */
2031 Class
= Class
->pclsClone
;
2032 while (Class
!= NULL
)
2035 UserDereferenceObject(Class
->spicn
);
2037 UserReferenceObject(NewIcon
);
2038 Class
->spicn
= NewIcon
;
2042 UserDereferenceObject(Class
->spicnSm
);
2043 UserReferenceObject(NewSmallIcon
);
2044 Class
->spicnSm
= NewSmallIcon
;
2045 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2047 Class
= Class
->pclsNext
;
2054 PCURICON_OBJECT NewSmallIcon
= NULL
;
2055 BOOLEAN NewIconFromCache
= FALSE
;
2059 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2062 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2068 /* Create the new small icon from the large one */
2069 HICON SmallIconHandle
= NULL
;
2070 if((Class
->spicn
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2071 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2073 SmallIconHandle
= co_IntCopyImage(
2074 UserHMGetHandle(Class
->spicn
),
2076 UserGetSystemMetrics( SM_CXSMICON
),
2077 UserGetSystemMetrics( SM_CYSMICON
),
2078 LR_COPYFROMRESOURCE
);
2080 if (!SmallIconHandle
)
2082 /* Retry without copying from resource */
2083 SmallIconHandle
= co_IntCopyImage(
2084 UserHMGetHandle(Class
->spicn
),
2086 UserGetSystemMetrics( SM_CXSMICON
),
2087 UserGetSystemMetrics( SM_CYSMICON
),
2090 if (SmallIconHandle
)
2093 NewSmallIcon
= UserGetCurIconObject(SmallIconHandle
);
2094 NewIconFromCache
= TRUE
;
2098 ERR("Failed getting a small icon for the class.\n");
2104 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2106 /* We must destroy the icon if we own it */
2107 IntDestroyCurIconObject(Class
->spicnSm
);
2112 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2114 UserDereferenceObject(Class
->spicnSm
);
2121 if (NewIconFromCache
)
2122 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2124 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2125 Class
->spicnSm
= NewSmallIcon
;
2127 /* Update the clones */
2128 Class
= Class
->pclsClone
;
2129 while (Class
!= NULL
)
2132 UserDereferenceObject(Class
->spicnSm
);
2134 UserReferenceObject(NewSmallIcon
);
2135 if (NewIconFromCache
)
2136 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2138 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2139 Class
->spicnSm
= NewSmallIcon
;
2140 Class
= Class
->pclsNext
;
2146 Ret
= (ULONG_PTR
)Class
->hModule
;
2147 Class
->hModule
= (HINSTANCE
)NewLong
;
2149 /* Update the clones */
2150 Class
= Class
->pclsClone
;
2151 while (Class
!= NULL
)
2153 Class
->hModule
= (HINSTANCE
)NewLong
;
2154 Class
= Class
->pclsNext
;
2160 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2162 if (!IntSetClassMenuName(Class
,
2165 ERR("Setting the class menu name failed!\n");
2168 /* FIXME: Really return NULL? Wine does so... */
2173 Ret
= (ULONG_PTR
)Class
->style
;
2174 Class
->style
= (UINT
)NewLong
;
2176 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2177 move the class to the appropriate list? For now, we save
2178 the original value in Class->Global, so we can always
2179 locate the appropriate list */
2181 /* Update the clones */
2182 Class
= Class
->pclsClone
;
2183 while (Class
!= NULL
)
2185 Class
->style
= (UINT
)NewLong
;
2186 Class
= Class
->pclsNext
;
2191 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2198 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2200 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
2201 if (!IntSetClassAtom(Class
,
2210 EngSetLastError(ERROR_INVALID_INDEX
);
2218 UserGetClassInfo(IN PCLS Class
,
2219 OUT PWNDCLASSEXW lpwcx
,
2221 HINSTANCE hInstance
)
2223 if (!Class
) return FALSE
;
2225 lpwcx
->style
= Class
->style
;
2227 // If fnId is set, clear the global bit. See wine class test check_style.
2229 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2231 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2233 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2234 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2235 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2236 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2237 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2238 lpwcx
->hbrBackground
= Class
->hbrBackground
;
2240 /* Copy non-string to user first. */
2242 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
2244 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
2246 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2247 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2248 * lpszClientXxxMenuName should already be mapped to user space.
2250 /* Copy string ptr to user. */
2251 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
2252 Class
->MenuNameIsString
)
2254 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2255 (PVOID
)Class
->lpszClientAnsiMenuName
:
2256 (PVOID
)Class
->lpszClientUnicodeMenuName
);
2259 if (hInstance
== hModClient
)
2260 lpwcx
->hInstance
= NULL
;
2262 lpwcx
->hInstance
= hInstance
;
2264 /* FIXME: Return the string? Okay! This is performed in User32! */
2265 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2271 // Register System Classes....
2275 UserRegisterSystemClasses(VOID
)
2278 UNICODE_STRING ClassName
, MenuName
;
2279 PPROCESSINFO ppi
= GetW32ProcessInfo();
2286 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
2289 if ( hModClient
== NULL
)
2292 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
2293 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
2295 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
2297 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
2299 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
2303 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
2304 ClassName
.Length
= 0;
2305 ClassName
.MaximumLength
= 0;
2308 wc
.cbSize
= sizeof(wc
);
2309 wc
.style
= DefaultServerClasses
[i
].Style
;
2311 Flags
|= CSF_SERVERSIDEPROC
;
2313 if (DefaultServerClasses
[i
].ProcW
)
2315 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
2316 wc
.hInstance
= hModuleWin
;
2320 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
2321 wc
.hInstance
= hModClient
;
2325 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
2328 //// System Cursors should be initilized!!!
2330 if (DefaultServerClasses
[i
].hCursor
== (HICON
)OCR_NORMAL
)
2332 if (SYSTEMCUR(ARROW
) == NULL
)
2334 ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n");
2338 wc
.hCursor
= UserHMGetHandle(SYSTEMCUR(ARROW
));
2342 hBrush
= DefaultServerClasses
[i
].hBrush
;
2343 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2345 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2347 wc
.hbrBackground
= hBrush
;
2348 wc
.lpszMenuName
= NULL
;
2349 wc
.lpszClassName
= ClassName
.Buffer
;
2352 Class
= IntCreateClass( &wc
,
2356 DefaultServerClasses
[i
].fiId
,
2362 Class
->pclsNext
= ppi
->pclsPublicList
;
2363 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2366 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2370 ERR("!!! Registering system class failed!\n");
2374 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2378 /* SYSCALLS *****************************************************************/
2382 NtUserRegisterClassExWOW(
2384 PUNICODE_STRING ClassName
,
2385 PUNICODE_STRING ClsNVersion
,
2386 PCLSMENUNAME pClassMenuName
,
2392 * Registers a new class with the window manager
2394 * lpwcx = Win32 extended window class structure
2395 * bUnicodeClass = Whether to send ANSI or unicode strings
2396 * to window procedures
2398 * Atom identifying the new class
2401 WNDCLASSEXW CapturedClassInfo
= {0};
2402 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0}, CapturedVersion
= {0};
2403 RTL_ATOM Ret
= (RTL_ATOM
)0;
2404 PPROCESSINFO ppi
= GetW32ProcessInfo();
2405 BOOL Exception
= FALSE
;
2407 if (Flags
& ~(CSF_ANSIPROC
))
2409 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2410 EngSetLastError(ERROR_INVALID_FLAGS
);
2414 UserEnterExclusive();
2416 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2418 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2420 UserRegisterSystemClasses();
2425 /* Probe the parameters and basic parameter checks */
2426 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2428 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2429 goto InvalidParameter
;
2433 sizeof(WNDCLASSEXW
),
2435 RtlCopyMemory(&CapturedClassInfo
,
2437 sizeof(WNDCLASSEXW
));
2439 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2440 CapturedVersion
= ProbeForReadUnicodeString(ClsNVersion
);
2442 ProbeForRead(pClassMenuName
,
2443 sizeof(CLSMENUNAME
),
2446 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2448 if ( (CapturedName
.Length
& 1) ||
2449 (CapturedMenuName
.Length
& 1) ||
2450 (CapturedClassInfo
.cbClsExtra
< 0) ||
2451 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2452 CapturedMenuName
.Length
+ sizeof(CLS
))
2453 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2454 (CapturedClassInfo
.cbWndExtra
< 0) ||
2455 (CapturedClassInfo
.hInstance
== NULL
) )
2457 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2458 goto InvalidParameter
;
2461 if (CapturedName
.Length
!= 0)
2463 ProbeForRead(CapturedName
.Buffer
,
2464 CapturedName
.Length
,
2469 if (!IS_ATOM(CapturedName
.Buffer
))
2471 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2472 goto InvalidParameter
;
2476 if (CapturedVersion
.Length
!= 0)
2478 ProbeForRead(CapturedVersion
.Buffer
,
2479 CapturedVersion
.Length
,
2484 if (!IS_ATOM(CapturedVersion
.Buffer
))
2486 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2487 goto InvalidParameter
;
2491 if (CapturedMenuName
.Length
!= 0)
2493 ProbeForRead(CapturedMenuName
.Buffer
,
2494 CapturedMenuName
.Length
,
2497 else if (CapturedMenuName
.Buffer
!= NULL
&&
2498 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2500 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2502 EngSetLastError(ERROR_INVALID_PARAMETER
);
2506 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2507 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2508 // If this pops up we know what todo!
2509 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2512 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2516 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2517 SetLastNtError(_SEH2_GetExceptionCode());
2524 /* Register the class */
2525 Ret
= UserRegisterClass(&CapturedClassInfo
,
2535 TRACE("NtUserRegisterClassExWOW Null Return!\n");
2544 NtUserSetClassLong(HWND hWnd
,
2546 ULONG_PTR dwNewLong
,
2553 UserEnterExclusive();
2555 pi
= GetW32ProcessInfo();
2557 Window
= UserGetWindowObject(hWnd
);
2560 if (Window
->head
.pti
->ppi
!= pi
)
2562 EngSetLastError(ERROR_ACCESS_DENIED
);
2568 UNICODE_STRING Value
;
2570 /* Probe the parameters */
2571 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2573 /* FIXME: Resource ID can be passed directly without UNICODE_STRING ? */
2574 if (IS_ATOM(dwNewLong
))
2576 Value
.MaximumLength
= 0;
2578 Value
.Buffer
= (PWSTR
)dwNewLong
;
2582 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2585 if (Value
.Length
& 1)
2587 goto InvalidParameter
;
2590 if (Value
.Length
!= 0)
2592 ProbeForRead(Value
.Buffer
,
2598 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2600 goto InvalidParameter
;
2602 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2605 EngSetLastError(ERROR_INVALID_PARAMETER
);
2610 dwNewLong
= (ULONG_PTR
)&Value
;
2613 Ret
= UserSetClassLongPtr(Window
->pcls
,
2622 if (Ret
&& Ret
!= dwNewLong
)
2623 UserPaintCaption(Window
, DC_ICON
);
2627 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2629 SetLastNtError(_SEH2_GetExceptionCode());
2648 * NOTE: Obsoleted in 32-bit windows
2655 NtUserUnregisterClass(
2656 IN PUNICODE_STRING ClassNameOrAtom
,
2657 IN HINSTANCE hInstance
,
2658 OUT PCLSMENUNAME pClassMenuName
)
2660 UNICODE_STRING SafeClassName
;
2664 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2665 if (!NT_SUCCESS(Status
))
2667 ERR("Error capturing the class name\n");
2668 SetLastNtError(Status
);
2672 UserEnterExclusive();
2674 /* Unregister the class */
2675 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2679 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2680 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2686 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2690 HINSTANCE hInstance
,
2691 PUNICODE_STRING ClassName
,
2692 LPWNDCLASSEXW lpWndClassEx
,
2693 LPWSTR
*ppszMenuName
,
2696 UNICODE_STRING SafeClassName
;
2697 WNDCLASSEXW Safewcexw
;
2699 RTL_ATOM ClassAtom
= 0;
2706 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2707 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2711 SetLastNtError(_SEH2_GetExceptionCode());
2712 _SEH2_YIELD(return FALSE
);
2716 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2717 if (!NT_SUCCESS(Status
))
2719 ERR("Error capturing the class name\n");
2720 SetLastNtError(Status
);
2724 // If null instance use client.
2725 if (!hInstance
) hInstance
= hModClient
;
2727 TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName
, hInstance
);
2729 /* NOTE: Need exclusive lock because getting the wndproc might require the
2730 creation of a call procedure handle */
2731 UserEnterExclusive();
2733 ppi
= GetW32ProcessInfo();
2734 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2736 UserRegisterSystemClasses();
2739 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2744 if (ClassAtom
!= (RTL_ATOM
)0)
2746 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2750 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2760 /* Emulate Function. */
2761 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2763 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2766 /* We must return the atom of the class here instead of just TRUE. */
2767 /* Undocumented behavior! Return the class atom as a BOOL! */
2768 Ret
= (BOOL
)ClassAtom
;
2770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2772 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2778 if (!IS_ATOM(SafeClassName
.Buffer
))
2779 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2786 NtUserGetClassName (IN HWND hWnd
,
2788 OUT PUNICODE_STRING ClassName
)
2791 UNICODE_STRING CapturedClassName
;
2797 Window
= UserGetWindowObject(hWnd
);
2800 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2802 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2804 Atom
= gpsi
->atomSysClass
[iCls
];
2810 ProbeForWriteUnicodeString(ClassName
);
2811 CapturedClassName
= *ClassName
;
2813 /* Get the class name */
2814 Ret
= UserGetClassName(Window
->pcls
,
2821 /* Update the Length field */
2822 ClassName
->Length
= CapturedClassName
.Length
;
2825 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2827 SetLastNtError(_SEH2_GetExceptionCode());
2837 /* Return Pointer to Class structure. */
2841 HINSTANCE hInstance
,
2842 PUNICODE_STRING ClassName
)
2844 UNICODE_STRING SafeClassName
;
2847 RTL_ATOM ClassAtom
= 0;
2850 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2851 if (!NT_SUCCESS(Status
))
2853 ERR("Error capturing the class name\n");
2854 SetLastNtError(Status
);
2858 UserEnterExclusive();
2860 pi
= GetW32ProcessInfo();
2862 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2869 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2873 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2874 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2878 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.