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
? Class
->lpfnWndProc
: NULL
, Atom
, verAtom
,
1232 Class
? Class
->hModule
: NULL
, Class
? Class
->Global
: 0);
1238 IntFindClass(IN RTL_ATOM Atom
,
1239 IN HINSTANCE hInstance
,
1241 OUT PCLS
**Link OPTIONAL
)
1243 PCLS Class
, *PrevLink
= ClassList
;
1246 while (Class
!= NULL
)
1248 if (Class
->atomClassName
== Atom
&&
1249 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1250 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1252 ASSERT(Class
->pclsBase
== Class
);
1259 PrevLink
= &Class
->pclsNext
;
1260 Class
= Class
->pclsNext
;
1269 IntGetAtomFromStringOrAtom(
1270 _In_ PUNICODE_STRING ClassName
,
1271 _Out_ RTL_ATOM
*Atom
)
1275 if (ClassName
->Length
!= 0)
1283 /* NOTE: Caller has to protect the call with SEH! */
1285 if (ClassName
->Length
!= 0)
1287 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1288 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1290 EngSetLastError(ERROR_INVALID_PARAMETER
);
1294 /* We need to make a local copy of the class name! The caller could
1295 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1296 We're protected by SEH, but the ranges that might be accessed were
1298 RtlCopyMemory(szBuf
,
1301 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1305 AtomName
= ClassName
->Buffer
;
1307 /* Lookup the atom */
1308 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1311 if (NT_SUCCESS(Status
))
1317 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1319 SetLastNtError(Status
);
1325 ASSERT(IS_ATOM(ClassName
->Buffer
));
1326 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1335 _In_ PUNICODE_STRING ClassName
,
1336 IN HINSTANCE hInstance OPTIONAL
,
1337 IN PPROCESSINFO pi OPTIONAL
,
1338 OUT PCLS
*BaseClass OPTIONAL
,
1339 OUT PCLS
**Link OPTIONAL
)
1341 RTL_ATOM Atom
= (RTL_ATOM
)0;
1343 ASSERT(BaseClass
!= NULL
);
1345 if (IntGetAtomFromStringOrAtom(ClassName
, &Atom
) &&
1346 Atom
!= (RTL_ATOM
)0)
1350 /* Attempt to locate the class object */
1354 /* Step 1: Try to find an exact match of locally registered classes */
1355 Class
= IntFindClass(Atom
,
1357 &pi
->pclsPrivateList
,
1360 { TRACE("Step 1: 0x%p\n",Class
);
1364 /* Step 2: Try to find any globally registered class. The hInstance
1365 is not relevant for global classes */
1366 Class
= IntFindClass(Atom
,
1368 &pi
->pclsPublicList
,
1371 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1375 /* Step 3: Try to find any local class registered by user32 */
1376 Class
= IntFindClass(Atom
,
1378 &pi
->pclsPrivateList
,
1381 { TRACE("Step 3: 0x%p\n",Class
);
1385 /* Step 4: Try to find any global class registered by user32 */
1386 Class
= IntFindClass(Atom
,
1388 &pi
->pclsPublicList
,
1393 }else{TRACE("Step 4: 0x%p\n",Class
);}
1407 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1409 PCLS
*ClassLink
, Class
= NULL
;
1414 pti
= gptiDesktopThread
;
1416 pti
= PsGetCurrentThreadWin32Thread();
1418 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1420 UserRegisterSystemClasses();
1423 /* Check the class. */
1425 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1427 ClassAtom
= IntGetClassAtom(ClassName
,
1433 if (ClassAtom
== (RTL_ATOM
)0)
1435 if (IS_ATOM(ClassName
->Buffer
))
1437 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1441 ERR("Class \"%wZ\" not found\n", ClassName
);
1447 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1448 Class
= IntReferenceClass(Class
,
1453 ERR("Failed to reference window class!\n");
1461 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1462 IN PUNICODE_STRING ClassName
,
1463 IN PUNICODE_STRING ClassVersion
,
1464 IN PUNICODE_STRING MenuName
,
1472 RTL_ATOM Ret
= (RTL_ATOM
)0;
1474 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1476 pti
= GetW32ThreadInfo();
1480 // Need only to test for two conditions not four....... Fix more whine tests....
1481 if ( IntGetAtomFromStringOrAtom( ClassVersion
, &ClassAtom
) &&
1482 ClassAtom
!= (RTL_ATOM
)0 &&
1483 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1485 Class
= IntFindClass( ClassAtom
,
1487 &pi
->pclsPrivateList
,
1490 if (Class
!= NULL
&& !Class
->Global
)
1492 // Local class already exists
1493 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1494 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1498 if (lpwcx
->style
& CS_GLOBALCLASS
)
1500 Class
= IntFindClass( ClassAtom
,
1502 &pi
->pclsPublicList
,
1505 if (Class
!= NULL
&& Class
->Global
)
1507 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1508 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1514 Class
= IntCreateClass(lpwcx
,
1527 /* Register the class */
1529 List
= &pi
->pclsPublicList
;
1531 List
= &pi
->pclsPrivateList
;
1533 Class
->pclsNext
= *List
;
1534 (void)InterlockedExchangePointer((PVOID
*)List
,
1537 Ret
= Class
->atomNVClassName
;
1541 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1548 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1549 IN HINSTANCE hInstance
,
1550 OUT PCLSMENUNAME pClassMenuName
)
1557 pi
= GetW32ProcessInfo();
1559 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1561 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1562 ClassAtom
= IntGetClassAtom(ClassName
,
1567 if (ClassAtom
== (RTL_ATOM
)0)
1569 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1570 TRACE("UserUnregisterClass: No Class found.\n");
1574 ASSERT(Class
!= NULL
);
1576 if (Class
->cWndReferenceCount
!= 0 ||
1577 Class
->pclsClone
!= NULL
)
1579 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1580 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1584 /* Must be a base class! */
1585 ASSERT(Class
->pclsBase
== Class
);
1587 /* Unlink the class */
1588 *Link
= Class
->pclsNext
;
1590 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1592 TRACE("Class 0x%p\n", Class
);
1593 TRACE("UserUnregisterClass: Good Exit!\n");
1594 Class
->atomClassName
= 0; // Don't let it linger...
1595 /* Finally free the resources */
1596 IntDestroyClass(Class
);
1599 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1604 UserGetClassName(IN PCLS Class
,
1605 IN OUT PUNICODE_STRING ClassName
,
1609 NTSTATUS Status
= STATUS_SUCCESS
;
1610 WCHAR szStaticTemp
[32];
1611 PWSTR szTemp
= NULL
;
1612 ULONG BufLen
= sizeof(szStaticTemp
);
1615 /* Note: Accessing the buffer in ClassName may raise an exception! */
1621 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1622 UNICODE_STRING UnicodeClassName
;
1624 /* Limit the size of the static buffer on the stack to the
1625 size of the buffer provided by the caller */
1626 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1628 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1631 /* Find out how big the buffer needs to be */
1632 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1633 Class
->atomClassName
,
1638 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1640 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1642 /* The buffer required exceeds the ansi buffer provided,
1643 pretend like we're using the ansi buffer and limit the
1644 size to the buffer size provided */
1645 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1648 /* Allocate a temporary buffer that can hold the unicode class name */
1649 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1654 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1658 /* Query the class name */
1659 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1660 Atom
? Atom
: Class
->atomNVClassName
,
1667 szTemp
= szStaticTemp
;
1669 if (NT_SUCCESS(Status
))
1671 /* Convert the atom name to ansi */
1673 RtlInitUnicodeString(&UnicodeClassName
,
1676 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1679 if (!NT_SUCCESS(Status
))
1681 SetLastNtError(Status
);
1686 Ret
= BufLen
/ sizeof(WCHAR
);
1690 BufLen
= ClassName
->MaximumLength
;
1692 /* Query the atom name */
1693 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1694 Atom
? Atom
: Class
->atomNVClassName
,
1700 if (!NT_SUCCESS(Status
))
1702 SetLastNtError(Status
);
1706 Ret
= BufLen
/ sizeof(WCHAR
);
1709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1711 SetLastNtError(_SEH2_GetExceptionCode());
1715 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1717 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1724 IntSetClassMenuName(IN PCLS Class
,
1725 IN PUNICODE_STRING MenuName
)
1729 /* Change the base class first */
1730 Class
= Class
->pclsBase
;
1732 if (MenuName
->Length
!= 0)
1734 ANSI_STRING AnsiString
;
1737 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1739 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1740 AnsiString
.MaximumLength
);
1741 if (strBufW
!= NULL
)
1747 /* Copy the unicode string */
1748 RtlCopyMemory(strBufW
,
1751 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1753 /* Create an ANSI copy of the string */
1754 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1755 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1758 if (!NT_SUCCESS(Status
))
1760 SetLastNtError(Status
);
1766 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1768 SetLastNtError(_SEH2_GetExceptionCode());
1774 /* Update the base class */
1775 IntFreeClassMenuName(Class
);
1776 Class
->lpszClientUnicodeMenuName
= strBufW
;
1777 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1778 Class
->MenuNameIsString
= TRUE
;
1780 /* Update the clones */
1781 Class
= Class
->pclsClone
;
1782 while (Class
!= NULL
)
1784 Class
->lpszClientUnicodeMenuName
= strBufW
;
1785 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1786 Class
->MenuNameIsString
= TRUE
;
1788 Class
= Class
->pclsNext
;
1793 ERR("Failed to copy class menu name!\n");
1794 UserHeapFree(strBufW
);
1798 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1802 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1804 /* Update the base class */
1805 IntFreeClassMenuName(Class
);
1806 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1807 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1808 Class
->MenuNameIsString
= FALSE
;
1810 /* Update the clones */
1811 Class
= Class
->pclsClone
;
1812 while (Class
!= NULL
)
1814 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1815 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1816 Class
->MenuNameIsString
= FALSE
;
1818 Class
= Class
->pclsNext
;
1828 UserSetClassLongPtr(IN PCLS Class
,
1830 IN ULONG_PTR NewLong
,
1835 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1837 /* Change the information in the base class first, then update the clones */
1838 Class
= Class
->pclsBase
;
1844 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1846 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1847 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1849 EngSetLastError(ERROR_INVALID_PARAMETER
);
1853 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1855 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1856 certain architectures, maybe using RtlCopyMemory is a
1857 better choice for those architectures! */
1861 /* Update the clones */
1862 Class
= Class
->pclsClone
;
1863 while (Class
!= NULL
)
1865 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1866 Class
= Class
->pclsNext
;
1874 case GCL_CBWNDEXTRA
:
1875 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1876 Class
->cbwndExtra
= (INT
)NewLong
;
1878 /* Update the clones */
1879 Class
= Class
->pclsClone
;
1880 while (Class
!= NULL
)
1882 Class
->cbwndExtra
= (INT
)NewLong
;
1883 Class
= Class
->pclsNext
;
1888 case GCL_CBCLSEXTRA
:
1889 EngSetLastError(ERROR_INVALID_PARAMETER
);
1892 case GCLP_HBRBACKGROUND
:
1893 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1894 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1896 /* Update the clones */
1897 Class
= Class
->pclsClone
;
1898 while (Class
!= NULL
)
1900 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1901 Class
= Class
->pclsNext
;
1907 PCURICON_OBJECT NewCursor
= NULL
;
1911 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1914 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1921 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1922 UserDereferenceObject(Class
->spcur
);
1935 Class
->spcur
= NewCursor
;
1937 /* Update the clones */
1938 Class
= Class
->pclsClone
;
1939 while (Class
!= NULL
)
1942 UserDereferenceObject(Class
->spcur
);
1944 UserReferenceObject(NewCursor
);
1945 Class
->spcur
= NewCursor
;
1946 Class
= Class
->pclsNext
;
1953 // hIconSm, A handle to a small icon that is associated with the window class.
1954 // If this member is NULL, the system searches the icon resource specified by
1955 // the hIcon member for an icon of the appropriate size to use as the small icon.
1959 PCURICON_OBJECT NewIcon
= NULL
;
1960 PCURICON_OBJECT NewSmallIcon
= NULL
;
1964 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1967 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1974 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1975 UserDereferenceObject(Class
->spicn
);
1988 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1990 /* We will change the small icon */
1991 UserDereferenceObject(Class
->spicnSm
);
1992 IntDestroyCurIconObject(Class
->spicnSm
);
1993 Class
->spicnSm
= NULL
;
1994 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1997 if (NewLong
&& !Class
->spicnSm
)
1999 /* Create the new small icon from the new large(?) one */
2000 HICON SmallIconHandle
= NULL
;
2001 if((NewIcon
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2002 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2004 SmallIconHandle
= co_IntCopyImage(
2007 UserGetSystemMetrics( SM_CXSMICON
),
2008 UserGetSystemMetrics( SM_CYSMICON
),
2009 LR_COPYFROMRESOURCE
);
2011 if (!SmallIconHandle
)
2013 /* Retry without copying from resource */
2014 SmallIconHandle
= co_IntCopyImage(
2017 UserGetSystemMetrics( SM_CXSMICON
),
2018 UserGetSystemMetrics( SM_CYSMICON
),
2021 if (SmallIconHandle
)
2024 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
2025 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2029 Class
->spicn
= NewIcon
;
2031 /* Update the clones */
2032 Class
= Class
->pclsClone
;
2033 while (Class
!= NULL
)
2036 UserDereferenceObject(Class
->spicn
);
2038 UserReferenceObject(NewIcon
);
2039 Class
->spicn
= NewIcon
;
2043 UserDereferenceObject(Class
->spicnSm
);
2044 UserReferenceObject(NewSmallIcon
);
2045 Class
->spicnSm
= NewSmallIcon
;
2046 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2048 Class
= Class
->pclsNext
;
2055 PCURICON_OBJECT NewSmallIcon
= NULL
;
2056 BOOLEAN NewIconFromCache
= FALSE
;
2060 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2063 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2069 /* Create the new small icon from the large one */
2070 HICON SmallIconHandle
= NULL
;
2071 if((Class
->spicn
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2072 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
2074 SmallIconHandle
= co_IntCopyImage(
2075 UserHMGetHandle(Class
->spicn
),
2077 UserGetSystemMetrics( SM_CXSMICON
),
2078 UserGetSystemMetrics( SM_CYSMICON
),
2079 LR_COPYFROMRESOURCE
);
2081 if (!SmallIconHandle
)
2083 /* Retry without copying from resource */
2084 SmallIconHandle
= co_IntCopyImage(
2085 UserHMGetHandle(Class
->spicn
),
2087 UserGetSystemMetrics( SM_CXSMICON
),
2088 UserGetSystemMetrics( SM_CYSMICON
),
2091 if (SmallIconHandle
)
2094 NewSmallIcon
= UserGetCurIconObject(SmallIconHandle
);
2095 NewIconFromCache
= TRUE
;
2099 ERR("Failed getting a small icon for the class.\n");
2105 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2107 /* We must destroy the icon if we own it */
2108 IntDestroyCurIconObject(Class
->spicnSm
);
2113 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2115 UserDereferenceObject(Class
->spicnSm
);
2122 if (NewIconFromCache
)
2123 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2125 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2126 Class
->spicnSm
= NewSmallIcon
;
2128 /* Update the clones */
2129 Class
= Class
->pclsClone
;
2130 while (Class
!= NULL
)
2133 UserDereferenceObject(Class
->spicnSm
);
2135 UserReferenceObject(NewSmallIcon
);
2136 if (NewIconFromCache
)
2137 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2139 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2140 Class
->spicnSm
= NewSmallIcon
;
2141 Class
= Class
->pclsNext
;
2147 Ret
= (ULONG_PTR
)Class
->hModule
;
2148 Class
->hModule
= (HINSTANCE
)NewLong
;
2150 /* Update the clones */
2151 Class
= Class
->pclsClone
;
2152 while (Class
!= NULL
)
2154 Class
->hModule
= (HINSTANCE
)NewLong
;
2155 Class
= Class
->pclsNext
;
2161 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2163 if (!IntSetClassMenuName(Class
,
2166 ERR("Setting the class menu name failed!\n");
2169 /* FIXME: Really return NULL? Wine does so... */
2174 Ret
= (ULONG_PTR
)Class
->style
;
2175 Class
->style
= (UINT
)NewLong
;
2177 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2178 move the class to the appropriate list? For now, we save
2179 the original value in Class->Global, so we can always
2180 locate the appropriate list */
2182 /* Update the clones */
2183 Class
= Class
->pclsClone
;
2184 while (Class
!= NULL
)
2186 Class
->style
= (UINT
)NewLong
;
2187 Class
= Class
->pclsNext
;
2192 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2199 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2201 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
2202 if (!IntSetClassAtom(Class
,
2211 EngSetLastError(ERROR_INVALID_INDEX
);
2219 UserGetClassInfo(IN PCLS Class
,
2220 OUT PWNDCLASSEXW lpwcx
,
2222 HINSTANCE hInstance
)
2224 if (!Class
) return FALSE
;
2226 lpwcx
->style
= Class
->style
;
2228 // If fnId is set, clear the global bit. See wine class test check_style.
2230 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2232 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2234 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2235 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2236 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2237 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2238 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2239 lpwcx
->hbrBackground
= Class
->hbrBackground
;
2241 /* Copy non-string to user first. */
2243 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
2245 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
2247 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2248 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2249 * lpszClientXxxMenuName should already be mapped to user space.
2251 /* Copy string ptr to user. */
2252 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
2253 Class
->MenuNameIsString
)
2255 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2256 (PVOID
)Class
->lpszClientAnsiMenuName
:
2257 (PVOID
)Class
->lpszClientUnicodeMenuName
);
2260 if (hInstance
== hModClient
)
2261 lpwcx
->hInstance
= NULL
;
2263 lpwcx
->hInstance
= hInstance
;
2265 /* FIXME: Return the string? Okay! This is performed in User32! */
2266 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2272 // Register System Classes....
2276 UserRegisterSystemClasses(VOID
)
2279 UNICODE_STRING ClassName
, MenuName
;
2280 PPROCESSINFO ppi
= GetW32ProcessInfo();
2287 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
2290 if ( hModClient
== NULL
)
2293 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
2294 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
2296 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
2298 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
2300 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
2304 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
2305 ClassName
.Length
= 0;
2306 ClassName
.MaximumLength
= 0;
2309 wc
.cbSize
= sizeof(wc
);
2310 wc
.style
= DefaultServerClasses
[i
].Style
;
2312 Flags
|= CSF_SERVERSIDEPROC
;
2314 if (DefaultServerClasses
[i
].ProcW
)
2316 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
2317 wc
.hInstance
= hModuleWin
;
2321 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
2322 wc
.hInstance
= hModClient
;
2326 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
2329 //// System Cursors should be initilized!!!
2331 if (DefaultServerClasses
[i
].hCursor
== (HICON
)OCR_NORMAL
)
2333 if (SYSTEMCUR(ARROW
) == NULL
)
2335 ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n");
2340 wc
.hCursor
= UserHMGetHandle(SYSTEMCUR(ARROW
));
2344 hBrush
= DefaultServerClasses
[i
].hBrush
;
2345 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2347 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2349 wc
.hbrBackground
= hBrush
;
2350 wc
.lpszMenuName
= NULL
;
2351 wc
.lpszClassName
= ClassName
.Buffer
;
2354 Class
= IntCreateClass( &wc
,
2358 DefaultServerClasses
[i
].fiId
,
2364 Class
->pclsNext
= ppi
->pclsPublicList
;
2365 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2368 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2372 ERR("!!! Registering system class failed!\n");
2376 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2380 /* SYSCALLS *****************************************************************/
2384 NtUserRegisterClassExWOW(
2386 PUNICODE_STRING ClassName
,
2387 PUNICODE_STRING ClsVersion
,
2388 PCLSMENUNAME pClassMenuName
,
2394 * Registers a new class with the window manager
2396 * lpwcx = Win32 extended window class structure
2397 * bUnicodeClass = Whether to send ANSI or unicode strings
2398 * to window procedures
2400 * Atom identifying the new class
2403 WNDCLASSEXW CapturedClassInfo
= {0};
2404 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0}, CapturedVersion
= {0};
2405 RTL_ATOM Ret
= (RTL_ATOM
)0;
2406 PPROCESSINFO ppi
= GetW32ProcessInfo();
2407 BOOL Exception
= FALSE
;
2409 if (Flags
& ~(CSF_ANSIPROC
))
2411 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2412 EngSetLastError(ERROR_INVALID_FLAGS
);
2416 UserEnterExclusive();
2418 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2420 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2422 UserRegisterSystemClasses();
2427 /* Probe the parameters and basic parameter checks */
2428 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2430 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2431 goto InvalidParameter
;
2435 sizeof(WNDCLASSEXW
),
2437 RtlCopyMemory(&CapturedClassInfo
,
2439 sizeof(WNDCLASSEXW
));
2441 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2442 CapturedVersion
= ProbeForReadUnicodeString(ClsVersion
);
2444 ProbeForRead(pClassMenuName
,
2445 sizeof(CLSMENUNAME
),
2448 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2450 if ( (CapturedName
.Length
& 1) ||
2451 (CapturedMenuName
.Length
& 1) ||
2452 (CapturedClassInfo
.cbClsExtra
< 0) ||
2453 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2454 CapturedMenuName
.Length
+ sizeof(CLS
))
2455 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2456 (CapturedClassInfo
.cbWndExtra
< 0) ||
2457 (CapturedClassInfo
.hInstance
== NULL
) )
2459 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2460 goto InvalidParameter
;
2463 if (CapturedName
.Length
!= 0)
2465 ProbeForRead(CapturedName
.Buffer
,
2466 CapturedName
.Length
,
2471 if (!IS_ATOM(CapturedName
.Buffer
))
2473 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2474 goto InvalidParameter
;
2478 if (CapturedVersion
.Length
!= 0)
2480 ProbeForRead(CapturedVersion
.Buffer
,
2481 CapturedVersion
.Length
,
2486 if (!IS_ATOM(CapturedVersion
.Buffer
))
2488 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2489 goto InvalidParameter
;
2493 if (CapturedMenuName
.Length
!= 0)
2495 ProbeForRead(CapturedMenuName
.Buffer
,
2496 CapturedMenuName
.Length
,
2499 else if (CapturedMenuName
.Buffer
!= NULL
&&
2500 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2502 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2504 EngSetLastError(ERROR_INVALID_PARAMETER
);
2508 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2509 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2510 // If this pops up we know what todo!
2511 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2514 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2518 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2519 SetLastNtError(_SEH2_GetExceptionCode());
2526 /* Register the class */
2527 Ret
= UserRegisterClass(&CapturedClassInfo
,
2537 TRACE("NtUserRegisterClassExWOW Null Return!\n");
2546 NtUserSetClassLong(HWND hWnd
,
2548 ULONG_PTR dwNewLong
,
2555 UserEnterExclusive();
2557 pi
= GetW32ProcessInfo();
2559 Window
= UserGetWindowObject(hWnd
);
2562 if (Window
->head
.pti
->ppi
!= pi
)
2564 EngSetLastError(ERROR_ACCESS_DENIED
);
2570 UNICODE_STRING Value
;
2572 /* Probe the parameters */
2573 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2575 /* FIXME: Resource ID can be passed directly without UNICODE_STRING ? */
2576 if (IS_ATOM(dwNewLong
))
2578 Value
.MaximumLength
= 0;
2580 Value
.Buffer
= (PWSTR
)dwNewLong
;
2584 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2587 if (Value
.Length
& 1)
2589 goto InvalidParameter
;
2592 if (Value
.Length
!= 0)
2594 ProbeForRead(Value
.Buffer
,
2600 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2602 goto InvalidParameter
;
2604 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2607 EngSetLastError(ERROR_INVALID_PARAMETER
);
2612 dwNewLong
= (ULONG_PTR
)&Value
;
2615 Ret
= UserSetClassLongPtr(Window
->pcls
,
2624 if (Ret
&& Ret
!= dwNewLong
)
2625 UserPaintCaption(Window
, DC_ICON
);
2629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2631 SetLastNtError(_SEH2_GetExceptionCode());
2650 * NOTE: Obsoleted in 32-bit windows
2657 NtUserUnregisterClass(
2658 IN PUNICODE_STRING ClassNameOrAtom
,
2659 IN HINSTANCE hInstance
,
2660 OUT PCLSMENUNAME pClassMenuName
)
2662 UNICODE_STRING SafeClassName
;
2666 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2667 if (!NT_SUCCESS(Status
))
2669 ERR("Error capturing the class name\n");
2670 SetLastNtError(Status
);
2674 UserEnterExclusive();
2676 /* Unregister the class */
2677 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2681 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2682 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2688 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2692 HINSTANCE hInstance
,
2693 PUNICODE_STRING ClassName
,
2694 LPWNDCLASSEXW lpWndClassEx
,
2695 LPWSTR
*ppszMenuName
,
2698 UNICODE_STRING SafeClassName
;
2699 WNDCLASSEXW Safewcexw
;
2701 RTL_ATOM ClassAtom
= 0;
2708 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2709 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2713 SetLastNtError(_SEH2_GetExceptionCode());
2714 _SEH2_YIELD(return FALSE
);
2718 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2719 if (!NT_SUCCESS(Status
))
2721 ERR("Error capturing the class name\n");
2722 SetLastNtError(Status
);
2726 // If null instance use client.
2727 if (!hInstance
) hInstance
= hModClient
;
2729 TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName
, hInstance
);
2731 /* NOTE: Need exclusive lock because getting the wndproc might require the
2732 creation of a call procedure handle */
2733 UserEnterExclusive();
2735 ppi
= GetW32ProcessInfo();
2736 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2738 UserRegisterSystemClasses();
2741 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2746 if (ClassAtom
!= (RTL_ATOM
)0)
2748 ClassAtom
= Class
->atomNVClassName
;
2749 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2753 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2763 /* Emulate Function. */
2764 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2766 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2769 /* We must return the atom of the class here instead of just TRUE. */
2770 /* Undocumented behavior! Return the class atom as a BOOL! */
2771 Ret
= (BOOL
)ClassAtom
;
2773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2775 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2781 if (!IS_ATOM(SafeClassName
.Buffer
))
2782 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2789 NtUserGetClassName (IN HWND hWnd
,
2791 OUT PUNICODE_STRING ClassName
)
2794 UNICODE_STRING CapturedClassName
;
2800 Window
= UserGetWindowObject(hWnd
);
2803 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2805 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2807 Atom
= gpsi
->atomSysClass
[iCls
];
2813 ProbeForWriteUnicodeString(ClassName
);
2814 CapturedClassName
= *ClassName
;
2816 /* Get the class name */
2817 Ret
= UserGetClassName(Window
->pcls
,
2824 /* Update the Length field */
2825 ClassName
->Length
= CapturedClassName
.Length
;
2828 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2830 SetLastNtError(_SEH2_GetExceptionCode());
2840 /* Return Pointer to Class structure. */
2844 HINSTANCE hInstance
,
2845 PUNICODE_STRING ClassName
)
2847 UNICODE_STRING SafeClassName
;
2850 RTL_ATOM ClassAtom
= 0;
2853 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2854 if (!NT_SUCCESS(Status
))
2856 ERR("Error capturing the class name\n");
2857 SetLastNtError(Status
);
2861 UserEnterExclusive();
2863 pi
= GetW32ProcessInfo();
2865 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2872 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2876 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2877 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2881 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.