2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
10 DBG_DEFAULT_CHANNEL(UserClass
);
12 BOOL FASTCALL
IntClassDestroyIcon(HANDLE hCurIcon
);
13 static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom
);
15 REGISTER_SYSCLASS DefaultServerClasses
[] =
17 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
18 CS_GLOBALCLASS
|CS_DBLCLKS
,
19 NULL
, // Use User32 procs
22 (HBRUSH
)(COLOR_BACKGROUND
),
26 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
27 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
28 NULL
, // Use User32 procs
35 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
36 CS_DBLCLKS
|CS_SAVEBITS
,
37 NULL
, // Use User32 procs
40 (HBRUSH
)(COLOR_MENU
+ 1),
45 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
46 NULL
, // Use User32 procs
47 sizeof(SBWND
)-sizeof(WND
),
54 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8006))), // Tooltips
55 CS_PARENTDC
|CS_DBLCLKS
,
56 NULL
, // Use User32 procs
64 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
66 NULL
, // Use User32 procs
75 NULL
, // Use User32 procs
89 { /* Function Ids to Class indexes. */
90 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
91 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
92 { FNID_MENU
, ICLS_MENU
},
93 { FNID_DESKTOP
, ICLS_DESKTOP
},
94 { FNID_SWITCH
, ICLS_SWITCH
},
95 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
96 { FNID_BUTTON
, ICLS_BUTTON
},
97 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
98 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
99 { FNID_DIALOG
, ICLS_DIALOG
},
100 { FNID_EDIT
, ICLS_EDIT
},
101 { FNID_LISTBOX
, ICLS_LISTBOX
},
102 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
103 { FNID_STATIC
, ICLS_STATIC
},
104 { FNID_IME
, ICLS_IME
},
105 { FNID_GHOST
, ICLS_GHOST
},
106 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
111 LookupFnIdToiCls(int FnId
, int *iCls
)
115 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
117 if (FnidToiCls
[i
].FnId
== FnId
)
119 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
127 _Must_inspect_result_
130 ProbeAndCaptureUnicodeStringOrAtom(
131 _Out_
_When_(return>=0, _At_(pustrOut
->Buffer
, _Post_ _Notnull_
)) PUNICODE_STRING pustrOut
,
132 __in_data_source(USER_MODE
) _In_ PUNICODE_STRING pustrUnsafe
)
134 NTSTATUS Status
= STATUS_SUCCESS
;
136 /* Default to NULL */
137 pustrOut
->Buffer
= NULL
;
141 ProbeForRead(pustrUnsafe
, sizeof(UNICODE_STRING
), 1);
143 /* Validate the string */
144 if ((pustrUnsafe
->Length
& 1) || (pustrUnsafe
->Buffer
== NULL
))
146 /* This is not legal */
147 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
150 /* Check if this is an atom */
151 if (IS_ATOM(pustrUnsafe
->Buffer
))
153 /* Copy the atom, length is 0 */
154 pustrOut
->MaximumLength
= pustrOut
->Length
= 0;
155 pustrOut
->Buffer
= pustrUnsafe
->Buffer
;
159 /* Get the length, maximum length includes zero termination */
160 pustrOut
->Length
= pustrUnsafe
->Length
;
161 pustrOut
->MaximumLength
= pustrOut
->Length
+ sizeof(WCHAR
);
163 /* Allocate a buffer */
164 pustrOut
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
165 pustrOut
->MaximumLength
,
167 if (!pustrOut
->Buffer
)
169 _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES
);
172 /* Copy the string and zero terminate it */
173 ProbeForRead(pustrUnsafe
->Buffer
, pustrOut
->Length
, 1);
174 RtlCopyMemory(pustrOut
->Buffer
, pustrUnsafe
->Buffer
, pustrOut
->Length
);
175 pustrOut
->Buffer
[pustrOut
->Length
/ sizeof(WCHAR
)] = L
'\0';
178 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
180 /* Check if we already allocated a buffer */
181 if (pustrOut
->Buffer
)
183 /* Free the buffer */
184 ExFreePoolWithTag(pustrOut
->Buffer
, TAG_STRING
);
185 Status
= _SEH2_GetExceptionCode();
193 /* WINDOWCLASS ***************************************************************/
196 IntFreeClassMenuName(IN OUT PCLS Class
)
198 /* Free the menu name, if it was changed and allocated */
199 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
201 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
202 Class
->lpszClientUnicodeMenuName
= NULL
;
203 Class
->lpszClientAnsiMenuName
= NULL
;
208 IntDestroyClass(IN OUT PCLS Class
)
212 /* There shouldn't be any clones anymore */
213 ASSERT(Class
->cWndReferenceCount
== 0);
214 ASSERT(Class
->pclsClone
== NULL
);
216 if (Class
->pclsBase
== Class
)
218 PCALLPROCDATA CallProc
, NextCallProc
;
220 /* Destroy allocated callproc handles */
221 CallProc
= Class
->spcpdFirst
;
222 while (CallProc
!= NULL
)
224 NextCallProc
= CallProc
->spcpdNext
;
226 CallProc
->spcpdNext
= NULL
;
227 DestroyCallProc(CallProc
);
229 CallProc
= NextCallProc
;
232 // Fixes running the static test then run class test issue.
233 // Some applications do not use UnregisterClass before exiting.
234 // Keep from reusing the same atom with case insensitive
235 // comparisons, remove registration of the atom if not zeroed.
236 if (Class
->atomClassName
)
237 IntDeregisterClassAtom(Class
->atomClassName
);
241 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
245 IntFreeClassMenuName(Class
);
248 #ifdef NEW_CURSORICON
250 UserDereferenceObject(Class
->spicn
);
252 UserDereferenceObject(Class
->spcur
);
254 UserDereferenceObject(Class
->spicnSm
);
256 if (Class
->hIconSmIntern
)
257 IntClassDestroyIcon(Class
->hIconSmIntern
);
260 pDesk
= Class
->rpdeskParent
;
261 Class
->rpdeskParent
= NULL
;
263 /* Free the structure */
266 DesktopHeapFree(pDesk
, Class
);
275 /* Clean all process classes. all process windows must cleaned first!! */
276 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
279 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
283 /* Free all local classes */
284 Class
= pi
->pclsPrivateList
;
285 while (Class
!= NULL
)
287 pi
->pclsPrivateList
= Class
->pclsNext
;
289 ASSERT(Class
->pclsBase
== Class
);
290 IntDestroyClass(Class
);
292 Class
= pi
->pclsPrivateList
;
295 /* Free all global classes */
296 Class
= pi
->pclsPublicList
;
297 while (Class
!= NULL
)
299 pi
->pclsPublicList
= Class
->pclsNext
;
301 ASSERT(Class
->pclsBase
== Class
);
302 IntDestroyClass(Class
);
304 Class
= pi
->pclsPublicList
;
310 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
317 if (ClassName
->Length
!= 0)
319 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
320 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
322 EngSetLastError(ERROR_INVALID_PARAMETER
);
329 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
333 AtomName
= ClassName
->Buffer
;
335 Status
= RtlAddAtomToAtomTable(gAtomTable
,
339 if (!NT_SUCCESS(Status
))
341 SetLastNtError(Status
);
349 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
351 return RtlDeleteAtomFromAtomTable(gAtomTable
,
356 UserAddCallProcToClass(IN OUT PCLS Class
,
357 IN PCALLPROCDATA CallProc
)
361 ASSERT(CallProc
->spcpdNext
== NULL
);
363 BaseClass
= Class
->pclsBase
;
364 ASSERT(CallProc
->spcpdNext
== NULL
);
365 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
366 BaseClass
->spcpdFirst
= CallProc
;
368 /* Update all clones */
369 Class
= Class
->pclsClone
;
370 while (Class
!= NULL
)
372 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
373 Class
= Class
->pclsNext
;
378 IntSetClassAtom(IN OUT PCLS Class
,
379 IN PUNICODE_STRING ClassName
)
381 RTL_ATOM Atom
= (RTL_ATOM
)0;
383 /* Update the base class first */
384 Class
= Class
->pclsBase
;
386 if (!IntRegisterClassAtom(ClassName
,
392 IntDeregisterClassAtom(Class
->atomClassName
);
394 Class
->atomClassName
= Atom
;
396 /* Update the clones */
397 Class
= Class
->pclsClone
;
398 while (Class
!= NULL
)
400 Class
->atomClassName
= Atom
;
402 Class
= Class
->pclsNext
;
409 // Same as User32:IntGetClsWndProc.
412 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
415 WNDPROC gcpd
= NULL
, Ret
= NULL
;
417 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
419 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
421 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
424 Ret
= GETPFNCLIENTA(i
);
426 Ret
= GETPFNCLIENTW(i
);
431 Ret
= Class
->lpfnWndProc
;
433 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
437 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
438 Ret
= GETPFNCLIENTA(Class
->fnid
);
442 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
443 Ret
= GETPFNCLIENTW(Class
->fnid
);
447 if ( Ret
!= Class
->lpfnWndProc
||
448 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
451 gcpd
= (WNDPROC
)UserGetCPD( Class
,
452 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
455 return (gcpd
? gcpd
: Ret
);
461 IntSetClassWndProc(IN OUT PCLS Class
,
467 WNDPROC Ret
, chWndProc
;
469 Ret
= IntGetClassWndProc(Class
, Ansi
);
471 // If Server Side, downgrade to Client Side.
472 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
474 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
475 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
476 Class
->Unicode
= !Ansi
;
479 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
483 // Check if CallProc handle and retrieve previous call proc address and set.
484 if (IsCallProcHandle(WndProc
))
486 pcpd
= UserGetObject(gHandleTable
, WndProc
, TYPE_CALLPROC
);
487 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
490 Class
->lpfnWndProc
= chWndProc
;
495 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
496 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
498 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
500 chWndProc
= GETPFNSERVER(i
);
503 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
505 chWndProc
= GETPFNSERVER(i
);
509 // If match, set/reset to Server Side and clear ansi.
512 Class
->lpfnWndProc
= chWndProc
;
513 Class
->Unicode
= TRUE
;
514 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
515 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
519 Class
->Unicode
= !Ansi
;
522 Class
->CSF_flags
|= CSF_ANSIPROC
;
524 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
527 /* Update the clones */
528 chWndProc
= Class
->lpfnWndProc
;
530 Class
= Class
->pclsClone
;
531 while (Class
!= NULL
)
533 Class
->Unicode
= !Ansi
;
534 Class
->lpfnWndProc
= chWndProc
;
536 Class
= Class
->pclsNext
;
543 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
544 IN OUT PCLS
*ClassLink
,
550 ASSERT(Desktop
!= NULL
);
551 ASSERT(BaseClass
->pclsBase
== BaseClass
);
553 if (BaseClass
->rpdeskParent
== Desktop
)
555 /* It is most likely that a window is created on the same
556 desktop as the window class. */
561 if (BaseClass
->rpdeskParent
== NULL
)
563 ASSERT(BaseClass
->cWndReferenceCount
== 0);
564 ASSERT(BaseClass
->pclsClone
== NULL
);
566 /* Classes are also located in the shared heap when the class
567 was created before the thread attached to a desktop. As soon
568 as a window is created for such a class located on the shared
569 heap, the class is cloned into the desktop heap on which the
570 window is created. */
575 /* The user is asking for a class object on a different desktop,
577 Class
= BaseClass
->pclsClone
;
578 while (Class
!= NULL
)
580 if (Class
->rpdeskParent
== Desktop
)
582 ASSERT(Class
->pclsBase
== BaseClass
);
583 ASSERT(Class
->pclsClone
== NULL
);
587 Class
= Class
->pclsNext
;
593 /* The window is created on a different desktop, we need to
594 clone the class object to the desktop heap of the window! */
595 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
597 Class
= DesktopHeapAlloc(Desktop
,
602 /* Simply clone the class */
603 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
605 #ifdef NEW_CURSORICON
606 /* Reference our objects */
608 UserReferenceObject(Class
->spcur
);
610 UserReferenceObject(Class
->spicn
);
612 UserReferenceObject(Class
->spicnSm
);
615 TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
617 /* Restore module address if default user class Ref: Bug 4778 */
618 if ( Class
->hModule
!= hModClient
&&
619 Class
->fnid
<= FNID_GHOST
&&
620 Class
->fnid
>= FNID_BUTTON
)
622 Class
->hModule
= hModClient
;
623 TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class
, Class
->hModule
);
626 /* Update some pointers and link the class */
627 Class
->rpdeskParent
= Desktop
;
628 Class
->cWndReferenceCount
= 0;
630 if (BaseClass
->rpdeskParent
== NULL
)
632 /* We don't really need the base class on the shared
633 heap anymore, delete it so the only class left is
634 the clone we just created, which now serves as the
636 ASSERT(BaseClass
->pclsClone
== NULL
);
637 ASSERT(Class
->pclsClone
== NULL
);
638 Class
->pclsBase
= Class
;
639 Class
->pclsNext
= BaseClass
->pclsNext
;
641 /* Replace the base class */
642 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
645 /* Destroy the obsolete copy on the shared heap */
646 BaseClass
->pclsBase
= NULL
;
647 BaseClass
->pclsClone
= NULL
;
648 IntDestroyClass(BaseClass
);
652 /* Link in the clone */
653 Class
->pclsClone
= NULL
;
654 Class
->pclsBase
= BaseClass
;
655 Class
->pclsNext
= BaseClass
->pclsClone
;
656 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
662 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
669 IntReferenceClass(IN OUT PCLS BaseClass
,
670 IN OUT PCLS
*ClassLink
,
674 ASSERT(BaseClass
->pclsBase
== BaseClass
);
678 Class
= IntGetClassForDesktop(BaseClass
,
689 Class
->cWndReferenceCount
++;
697 IntMakeCloneBaseClass(IN OUT PCLS Class
,
698 IN OUT PCLS
*BaseClassLink
,
699 IN OUT PCLS
*CloneLink
)
703 ASSERT(Class
->pclsBase
!= Class
);
704 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
705 ASSERT(Class
->rpdeskParent
!= NULL
);
706 ASSERT(Class
->cWndReferenceCount
!= 0);
707 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
708 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
710 /* Unlink the clone */
711 *CloneLink
= Class
->pclsNext
;
712 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
714 /* Update the class information to make it a base class */
715 Class
->pclsBase
= Class
;
716 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
718 /* Update all clones */
719 Clone
= Class
->pclsClone
;
720 while (Clone
!= NULL
)
722 ASSERT(Clone
->pclsClone
== NULL
);
723 Clone
->pclsBase
= Class
;
725 Clone
= Clone
->pclsNext
;
728 /* Link in the new base class */
729 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
735 IntDereferenceClass(IN OUT PCLS Class
,
736 IN PDESKTOPINFO Desktop
,
739 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
741 ASSERT(Class
->cWndReferenceCount
>= 1);
743 BaseClass
= Class
->pclsBase
;
745 if (--Class
->cWndReferenceCount
== 0)
747 if (BaseClass
== Class
)
749 ASSERT(Class
->pclsBase
== Class
);
751 TRACE("IntDereferenceClass 0x%p\n", Class
);
752 /* Check if there are clones of the class on other desktops,
753 link the first clone in if possible. If there are no clones
754 then leave the class on the desktop heap. It will get moved
755 to the shared heap when the thread detaches. */
756 if (BaseClass
->pclsClone
!= NULL
)
758 if (BaseClass
->Global
)
759 PrevLink
= &pi
->pclsPublicList
;
761 PrevLink
= &pi
->pclsPrivateList
;
763 CurrentClass
= *PrevLink
;
764 while (CurrentClass
!= BaseClass
)
766 ASSERT(CurrentClass
!= NULL
);
768 PrevLink
= &CurrentClass
->pclsNext
;
769 CurrentClass
= CurrentClass
->pclsNext
;
772 ASSERT(*PrevLink
== BaseClass
);
774 /* Make the first clone become the new base class */
775 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
777 &BaseClass
->pclsClone
);
779 /* Destroy the class, there's still another clone of the class
780 that now serves as a base class. Make sure we don't destruct
781 resources shared by all classes (Base = NULL)! */
782 BaseClass
->pclsBase
= NULL
;
783 BaseClass
->pclsClone
= NULL
;
784 IntDestroyClass(BaseClass
);
789 TRACE("IntDereferenceClass1 0x%p\n", Class
);
791 /* Locate the cloned class and unlink it */
792 PrevLink
= &BaseClass
->pclsClone
;
793 CurrentClass
= BaseClass
->pclsClone
;
794 while (CurrentClass
!= Class
)
796 ASSERT(CurrentClass
!= NULL
);
798 PrevLink
= &CurrentClass
->pclsNext
;
799 CurrentClass
= CurrentClass
->pclsNext
;
802 ASSERT(CurrentClass
== Class
);
804 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
807 ASSERT(Class
->pclsBase
== BaseClass
);
808 ASSERT(Class
->pclsClone
== NULL
);
810 /* The class was just a clone, we don't need it anymore */
811 IntDestroyClass(Class
);
817 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
818 IN OUT PCLS
**ClassLinkPtr
)
823 ASSERT(Class
->pclsBase
== Class
);
824 ASSERT(Class
->rpdeskParent
!= NULL
);
825 ASSERT(Class
->cWndReferenceCount
== 0);
826 ASSERT(Class
->pclsClone
== NULL
);
828 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
830 /* Allocate the new base class on the shared heap */
831 NewClass
= UserHeapAlloc(ClassSize
);
832 if (NewClass
!= NULL
)
834 RtlCopyMemory(NewClass
,
838 NewClass
->rpdeskParent
= NULL
;
839 NewClass
->pclsBase
= NewClass
;
841 #ifdef NEW_CURSORICON
843 UserReferenceObject(NewClass
->spcur
);
845 UserReferenceObject(NewClass
->spicn
);
846 if (NewClass
->spicnSm
)
847 UserReferenceObject(NewClass
->spicnSm
);
851 /* Replace the class in the list */
852 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
854 *ClassLinkPtr
= &NewClass
->pclsNext
;
856 /* Free the obsolete class on the desktop heap */
857 Class
->pclsBase
= NULL
;
858 IntDestroyClass(Class
);
866 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
867 IN OUT PCLS
*ClassList
,
868 IN BOOL FreeOnFailure
,
871 PCLS Class
, NextClass
, *Link
;
873 /* NOTE: We only need to check base classes! When classes are no longer needed
874 on a desktop, the clones will be freed automatically as soon as possible.
875 However, we need to move base classes to the shared heap, as soon as
876 the last desktop heap where a class is allocated on is about to be destroyed.
877 If we didn't move the class to the shared heap, the class would become
880 ASSERT(Desktop
!= NULL
);
884 while (Class
!= NULL
)
886 NextClass
= Class
->pclsNext
;
888 ASSERT(Class
->pclsBase
== Class
);
890 if (Class
->rpdeskParent
== Desktop
&&
891 Class
->cWndReferenceCount
== 0)
893 /* There shouldn't be any clones around anymore! */
894 ASSERT(Class
->pclsClone
== NULL
);
896 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
897 /* FIXME: We could move the class to another desktop heap if there's still desktops
898 mapped into the process... */
900 /* Move the class to the shared heap */
901 if (IntMoveClassToSharedHeap(Class
,
904 ASSERT(*Link
== NextClass
);
908 ASSERT(NextClass
== Class
->pclsNext
);
912 /* Unlink the base class */
913 (void)InterlockedExchangePointer((PVOID
*)Link
,
916 /* We can free the old base class now */
917 Class
->pclsBase
= NULL
;
918 IntDestroyClass(Class
);
922 Link
= &Class
->pclsNext
;
928 Link
= &Class
->pclsNext
;
935 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
936 IN BOOL FreeOnFailure
)
941 pi
= GetW32ProcessInfo();
943 /* Check all local classes */
944 IntCheckDesktopClasses(Desktop
,
945 &pi
->pclsPrivateList
,
949 /* Check all global classes */
950 IntCheckDesktopClasses(Desktop
,
956 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
957 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
965 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
966 IN PUNICODE_STRING ClassName
,
967 IN PUNICODE_STRING MenuName
,
977 PWSTR pszMenuName
= NULL
;
978 NTSTATUS Status
= STATUS_SUCCESS
;
980 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
981 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
983 if (!IntRegisterClassAtom(ClassName
,
986 ERR("Failed to register class atom!\n");
990 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
991 if (MenuName
->Length
!= 0)
993 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
994 RtlUnicodeStringToAnsiSize(MenuName
));
995 if (pszMenuName
== NULL
)
1001 Class
= DesktopHeapAlloc(Desktop
,
1006 /* FIXME: The class was created before being connected
1007 to a desktop. It is possible for the desktop window,
1008 but should it be allowed for any other case? */
1009 Class
= UserHeapAlloc(ClassSize
);
1016 RtlZeroMemory(Class
, ClassSize
);
1018 Class
->rpdeskParent
= Desktop
;
1019 Class
->pclsBase
= Class
;
1020 Class
->atomClassName
= Atom
;
1022 Class
->CSF_flags
= dwFlags
;
1024 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
1026 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1031 PWSTR pszMenuNameBuffer
= pszMenuName
;
1033 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1034 and string buffers might raise an exception! We don't want to
1036 // What?! If the user interface was written correctly this would not be an issue!
1037 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
1038 Class
->style
= lpwcx
->style
;
1039 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
1040 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
1041 Class
->hModule
= lpwcx
->hInstance
;
1042 #ifdef NEW_CURSORICON
1043 Class
->spicn
= lpwcx
->hIcon
? UserGetCurIconObject(lpwcx
->hIcon
) : NULL
;
1044 Class
->spcur
= lpwcx
->hCursor
? UserGetCurIconObject(lpwcx
->hCursor
) : NULL
;
1045 Class
->spicnSm
= lpwcx
->hIconSm
? UserGetCurIconObject(lpwcx
->hIconSm
) : NULL
;
1047 Class
->hIcon
= lpwcx
->hIcon
;
1048 Class
->hIconSm
= lpwcx
->hIconSm
;
1049 Class
->hCursor
= lpwcx
->hCursor
;
1052 Class
->hbrBackground
= lpwcx
->hbrBackground
;
1054 /* Make a copy of the string */
1055 if (pszMenuNameBuffer
!= NULL
)
1057 Class
->MenuNameIsString
= TRUE
;
1059 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
1060 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
1063 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1065 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
1068 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1070 /* Save an ANSI copy of the string */
1071 if (pszMenuNameBuffer
!= NULL
)
1073 ANSI_STRING AnsiString
;
1075 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
1076 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1077 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
1078 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1081 if (!NT_SUCCESS(Status
))
1083 ERR("Failed to convert unicode menu name to ansi!\n");
1085 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1090 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1092 /* Save kernel use menu name and ansi class name */
1093 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
1094 //Class->lpszAnsiClassName = FIXME
1096 /* Server Side overrides class calling type (A/W)!
1097 User32 whine test_builtinproc: "deftest"
1098 built-in winproc - window A/W type automatically detected */
1099 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
1103 /* Due to the wine class "deftest" and most likely no FNID to reference
1104 from, sort through the Server Side list and compare proc addresses
1105 for match. This method will be used in related code.
1107 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
1108 { // Open ANSI or Unicode, just match, set and break.
1109 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
1111 WndProc
= GETPFNSERVER(i
);
1114 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
1116 WndProc
= GETPFNSERVER(i
);
1121 { // If a hit, we are Server Side so set the right flags and proc.
1122 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
1123 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
1124 Class
->lpfnWndProc
= WndProc
;
1128 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1129 Class
->Unicode
= TRUE
;
1131 if (Class
->style
& CS_GLOBALCLASS
)
1132 Class
->Global
= TRUE
;
1134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1136 Status
= _SEH2_GetExceptionCode();
1140 if (!NT_SUCCESS(Status
))
1142 ERR("Failed creating the class: 0x%x\n", Status
);
1144 SetLastNtError(Status
);
1146 if (pszMenuName
!= NULL
)
1147 UserHeapFree(pszMenuName
);
1149 DesktopHeapFree(Desktop
,
1153 IntDeregisterClassAtom(Atom
);
1159 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1161 if (pszMenuName
!= NULL
)
1162 UserHeapFree(pszMenuName
);
1164 IntDeregisterClassAtom(Atom
);
1166 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1169 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
1170 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1176 IntFindClass(IN RTL_ATOM Atom
,
1177 IN HINSTANCE hInstance
,
1179 OUT PCLS
**Link OPTIONAL
)
1181 PCLS Class
, *PrevLink
= ClassList
;
1184 while (Class
!= NULL
)
1186 if (Class
->atomClassName
== Atom
&&
1187 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1188 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1190 ASSERT(Class
->pclsBase
== Class
);
1197 PrevLink
= &Class
->pclsNext
;
1198 Class
= Class
->pclsNext
;
1206 IntGetAtomFromStringOrAtom(
1207 _In_ PUNICODE_STRING ClassName
,
1208 _Out_ RTL_ATOM
*Atom
)
1212 if (ClassName
->Length
!= 0)
1220 /* NOTE: Caller has to protect the call with SEH! */
1222 if (ClassName
->Length
!= 0)
1224 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1225 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1227 EngSetLastError(ERROR_INVALID_PARAMETER
);
1231 /* We need to make a local copy of the class name! The caller could
1232 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1233 We're protected by SEH, but the ranges that might be accessed were
1235 RtlCopyMemory(szBuf
,
1238 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1242 AtomName
= ClassName
->Buffer
;
1244 /* Lookup the atom */
1245 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1248 if (NT_SUCCESS(Status
))
1254 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1256 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1260 SetLastNtError(Status
);
1266 ASSERT(IS_ATOM(ClassName
->Buffer
));
1267 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1276 _In_ PUNICODE_STRING ClassName
,
1277 IN HINSTANCE hInstance OPTIONAL
,
1278 IN PPROCESSINFO pi OPTIONAL
,
1279 OUT PCLS
*BaseClass OPTIONAL
,
1280 OUT PCLS
**Link OPTIONAL
)
1282 RTL_ATOM Atom
= (RTL_ATOM
)0;
1284 ASSERT(BaseClass
!= NULL
);
1286 if (IntGetAtomFromStringOrAtom(ClassName
,
1288 Atom
!= (RTL_ATOM
)0)
1292 /* Attempt to locate the class object */
1296 /* Step 1: Try to find an exact match of locally registered classes */
1297 Class
= IntFindClass(Atom
,
1299 &pi
->pclsPrivateList
,
1302 { TRACE("Step 1: 0x%p\n",Class
);
1306 /* Step 2: Try to find any globally registered class. The hInstance
1307 is not relevant for global classes */
1308 Class
= IntFindClass(Atom
,
1310 &pi
->pclsPublicList
,
1313 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1317 /* Step 3: Try to find any local class registered by user32 */
1318 Class
= IntFindClass(Atom
,
1320 &pi
->pclsPrivateList
,
1323 { TRACE("Step 3: 0x%p\n",Class
);
1327 /* Step 4: Try to find any global class registered by user32 */
1328 Class
= IntFindClass(Atom
,
1330 &pi
->pclsPublicList
,
1334 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1336 }else{TRACE("Step 4: 0x%p\n",Class
);}
1346 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1348 PCLS
*ClassLink
, Class
= NULL
;
1353 pti
= gptiDesktopThread
;
1355 pti
= PsGetCurrentThreadWin32Thread();
1357 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1359 UserRegisterSystemClasses();
1362 /* Check the class. */
1364 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1366 ClassAtom
= IntGetClassAtom(ClassName
,
1372 if (ClassAtom
== (RTL_ATOM
)0)
1374 if (IS_ATOM(ClassName
->Buffer
))
1376 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1380 ERR("Class \"%wZ\" not found\n", ClassName
);
1383 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1387 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1388 Class
= IntReferenceClass(Class
,
1393 ERR("Failed to reference window class!\n");
1401 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1402 IN PUNICODE_STRING ClassName
,
1403 IN PUNICODE_STRING MenuName
,
1411 RTL_ATOM Ret
= (RTL_ATOM
)0;
1413 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1415 pti
= GetW32ThreadInfo();
1419 // Need only to test for two conditions not four....... Fix more whine tests....
1420 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1421 ClassAtom
!= (RTL_ATOM
)0 &&
1422 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1424 Class
= IntFindClass( ClassAtom
,
1426 &pi
->pclsPrivateList
,
1429 if (Class
!= NULL
&& !Class
->Global
)
1431 // Local class already exists
1432 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1433 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1437 if (lpwcx
->style
& CS_GLOBALCLASS
)
1439 Class
= IntFindClass( ClassAtom
,
1441 &pi
->pclsPublicList
,
1444 if (Class
!= NULL
&& Class
->Global
)
1446 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1447 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1453 Class
= IntCreateClass(lpwcx
,
1465 /* Register the class */
1467 List
= &pi
->pclsPublicList
;
1469 List
= &pi
->pclsPrivateList
;
1471 Class
->pclsNext
= *List
;
1472 (void)InterlockedExchangePointer((PVOID
*)List
,
1475 Ret
= Class
->atomClassName
;
1479 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1486 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1487 IN HINSTANCE hInstance
,
1488 OUT PCLSMENUNAME pClassMenuName
)
1495 pi
= GetW32ProcessInfo();
1497 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1499 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1500 ClassAtom
= IntGetClassAtom(ClassName
,
1505 if (ClassAtom
== (RTL_ATOM
)0)
1507 TRACE("UserUnregisterClass: No Class found.\n");
1511 ASSERT(Class
!= NULL
);
1513 if (Class
->cWndReferenceCount
!= 0 ||
1514 Class
->pclsClone
!= NULL
)
1516 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1517 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1521 /* Must be a base class! */
1522 ASSERT(Class
->pclsBase
== Class
);
1524 /* Unlink the class */
1525 *Link
= Class
->pclsNext
;
1527 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1529 TRACE("Class 0x%p\n", Class
);
1530 TRACE("UserUnregisterClass: Good Exit!\n");
1531 Class
->atomClassName
= 0; // Don't let it linger...
1532 /* Finally free the resources */
1533 IntDestroyClass(Class
);
1536 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1541 UserGetClassName(IN PCLS Class
,
1542 IN OUT PUNICODE_STRING ClassName
,
1546 NTSTATUS Status
= STATUS_SUCCESS
;
1547 WCHAR szStaticTemp
[32];
1548 PWSTR szTemp
= NULL
;
1549 ULONG BufLen
= sizeof(szStaticTemp
);
1552 /* Note: Accessing the buffer in ClassName may raise an exception! */
1558 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1559 UNICODE_STRING UnicodeClassName
;
1561 /* Limit the size of the static buffer on the stack to the
1562 size of the buffer provided by the caller */
1563 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1565 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1568 /* Find out how big the buffer needs to be */
1569 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1570 Class
->atomClassName
,
1575 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1577 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1579 /* The buffer required exceeds the ansi buffer provided,
1580 pretend like we're using the ansi buffer and limit the
1581 size to the buffer size provided */
1582 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1585 /* Allocate a temporary buffer that can hold the unicode class name */
1586 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1591 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1595 /* Query the class name */
1596 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1597 Atom
? Atom
: Class
->atomClassName
,
1604 szTemp
= szStaticTemp
;
1606 if (NT_SUCCESS(Status
))
1608 /* Convert the atom name to ansi */
1610 RtlInitUnicodeString(&UnicodeClassName
,
1613 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1616 if (!NT_SUCCESS(Status
))
1618 SetLastNtError(Status
);
1623 Ret
= BufLen
/ sizeof(WCHAR
);
1627 BufLen
= ClassName
->MaximumLength
;
1629 /* Query the atom name */
1630 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1631 Atom
? Atom
: Class
->atomClassName
,
1637 if (!NT_SUCCESS(Status
))
1639 SetLastNtError(Status
);
1643 Ret
= BufLen
/ sizeof(WCHAR
);
1646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1648 SetLastNtError(_SEH2_GetExceptionCode());
1652 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1654 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1661 IntSetClassMenuName(IN PCLS Class
,
1662 IN PUNICODE_STRING MenuName
)
1666 /* Change the base class first */
1667 Class
= Class
->pclsBase
;
1669 if (MenuName
->Length
!= 0)
1671 ANSI_STRING AnsiString
;
1674 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1676 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1677 AnsiString
.MaximumLength
);
1678 if (strBufW
!= NULL
)
1684 /* Copy the unicode string */
1685 RtlCopyMemory(strBufW
,
1688 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1690 /* Create an ANSI copy of the string */
1691 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1692 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1695 if (!NT_SUCCESS(Status
))
1697 SetLastNtError(Status
);
1703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1705 SetLastNtError(_SEH2_GetExceptionCode());
1711 /* Update the base class */
1712 IntFreeClassMenuName(Class
);
1713 Class
->lpszClientUnicodeMenuName
= strBufW
;
1714 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1715 Class
->MenuNameIsString
= TRUE
;
1717 /* Update the clones */
1718 Class
= Class
->pclsClone
;
1719 while (Class
!= NULL
)
1721 Class
->lpszClientUnicodeMenuName
= strBufW
;
1722 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1723 Class
->MenuNameIsString
= TRUE
;
1725 Class
= Class
->pclsNext
;
1730 ERR("Failed to copy class menu name!\n");
1731 UserHeapFree(strBufW
);
1735 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1739 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1741 /* Update the base class */
1742 IntFreeClassMenuName(Class
);
1743 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1744 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1745 Class
->MenuNameIsString
= FALSE
;
1747 /* Update the clones */
1748 Class
= Class
->pclsClone
;
1749 while (Class
!= NULL
)
1751 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1752 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1753 Class
->MenuNameIsString
= FALSE
;
1755 Class
= Class
->pclsNext
;
1764 #ifndef NEW_CURSORICON
1766 IntClassDestroyIcon(HANDLE hCurIcon
)
1768 PCURICON_OBJECT CurIcon
;
1771 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1774 ERR("hCurIcon was not found!\n");
1777 /* Note: IntDestroyCurIconObject will remove our reference for us! */
1778 Ret
= IntDestroyCurIconObject(CurIcon
, GetW32ProcessInfo());
1781 ERR("hCurIcon was not Destroyed!\n");
1788 UserSetClassLongPtr(IN PCLS Class
,
1790 IN ULONG_PTR NewLong
,
1794 #ifndef NEW_CURSORICON
1795 HANDLE hIconSmIntern
= NULL
;
1798 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1800 /* Change the information in the base class first, then update the clones */
1801 Class
= Class
->pclsBase
;
1807 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1809 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1810 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1812 EngSetLastError(ERROR_INVALID_PARAMETER
);
1816 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1818 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1819 certain architectures, maybe using RtlCopyMemory is a
1820 better choice for those architectures! */
1824 /* Update the clones */
1825 Class
= Class
->pclsClone
;
1826 while (Class
!= NULL
)
1828 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1829 Class
= Class
->pclsNext
;
1837 case GCL_CBWNDEXTRA
:
1838 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1839 Class
->cbwndExtra
= (INT
)NewLong
;
1841 /* Update the clones */
1842 Class
= Class
->pclsClone
;
1843 while (Class
!= NULL
)
1845 Class
->cbwndExtra
= (INT
)NewLong
;
1846 Class
= Class
->pclsNext
;
1851 case GCL_CBCLSEXTRA
:
1852 EngSetLastError(ERROR_INVALID_PARAMETER
);
1855 case GCLP_HBRBACKGROUND
:
1856 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1857 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1859 /* Update the clones */
1860 Class
= Class
->pclsClone
;
1861 while (Class
!= NULL
)
1863 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1864 Class
= Class
->pclsNext
;
1868 #ifdef NEW_CURSORICON
1871 PCURICON_OBJECT NewCursor
= NULL
;
1875 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1878 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1885 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1886 UserDereferenceObject(Class
->spcur
);
1899 Class
->spcur
= NewCursor
;
1901 /* Update the clones */
1902 Class
= Class
->pclsClone
;
1903 while (Class
!= NULL
)
1906 UserDereferenceObject(Class
->spcur
);
1908 UserReferenceObject(NewCursor
);
1909 Class
->spcur
= NewCursor
;
1910 Class
= Class
->pclsNext
;
1917 /* FIXME: Get handle from pointer to CURSOR object */
1918 Ret
= (ULONG_PTR
)Class
->hCursor
;
1919 Class
->hCursor
= (HANDLE
)NewLong
;
1921 /* Update the clones */
1922 Class
= Class
->pclsClone
;
1923 while (Class
!= NULL
)
1925 Class
->hCursor
= (HANDLE
)NewLong
;
1926 Class
= Class
->pclsNext
;
1932 // hIconSm, A handle to a small icon that is associated with the window class.
1933 // If this member is NULL, the system searches the icon resource specified by
1934 // the hIcon member for an icon of the appropriate size to use as the small icon.
1937 #ifdef NEW_CURSORICON
1939 PCURICON_OBJECT NewIcon
= NULL
;
1940 PCURICON_OBJECT NewSmallIcon
= NULL
;
1944 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1947 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1954 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1955 UserDereferenceObject(Class
->spicn
);
1968 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1970 /* We will change the small icon */
1971 UserDereferenceObject(Class
->spicnSm
);
1972 Class
->spicnSm
= NULL
;
1973 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1976 if (NewLong
&& !Class
->spicnSm
)
1978 /* Create the new small icon from the new large(?) one */
1979 HICON SmallIconHandle
= NULL
;
1980 if((NewIcon
->CURSORF_flags
& (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1981 == (CURSORF_LRSHARED
| CURSORF_FROMRESOURCE
))
1983 SmallIconHandle
= co_IntCopyImage(
1986 UserGetSystemMetrics( SM_CXSMICON
),
1987 UserGetSystemMetrics( SM_CYSMICON
),
1988 LR_COPYFROMRESOURCE
| LR_SHARED
);
1990 if (!SmallIconHandle
)
1992 /* Retry without copying from resource */
1993 SmallIconHandle
= co_IntCopyImage(
1996 UserGetSystemMetrics( SM_CXSMICON
),
1997 UserGetSystemMetrics( SM_CYSMICON
),
2000 if (SmallIconHandle
)
2003 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
2004 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2008 Class
->spicn
= NewIcon
;
2010 /* Update the clones */
2011 Class
= Class
->pclsClone
;
2012 while (Class
!= NULL
)
2015 UserDereferenceObject(Class
->spicn
);
2017 UserReferenceObject(NewIcon
);
2018 Class
->spicn
= NewIcon
;
2022 UserDereferenceObject(Class
->spicnSm
);
2023 UserReferenceObject(NewSmallIcon
);
2024 Class
->spicnSm
= NewSmallIcon
;
2025 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2027 Class
= Class
->pclsNext
;
2032 /* FIXME: Get handle from pointer to ICON object */
2033 Ret
= (ULONG_PTR
)Class
->hIcon
;
2034 if (Class
->hIcon
== (HANDLE
)NewLong
) break;
2035 if (Ret
&& Class
->hIconSmIntern
)
2037 IntClassDestroyIcon(Class
->hIconSmIntern
);
2038 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2039 Class
->hIconSmIntern
= NULL
;
2041 if (NewLong
&& !Class
->hIconSm
)
2043 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( (HICON
)NewLong
, IMAGE_ICON
,
2044 UserGetSystemMetrics( SM_CXSMICON
),
2045 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2046 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2048 Class
->hIcon
= (HANDLE
)NewLong
;
2050 /* Update the clones */
2051 Class
= Class
->pclsClone
;
2052 while (Class
!= NULL
)
2054 Class
->hIcon
= (HANDLE
)NewLong
;
2055 Class
->hIconSmIntern
= hIconSmIntern
;
2056 Class
= Class
->pclsNext
;
2062 #ifdef NEW_CURSORICON
2064 PCURICON_OBJECT NewSmallIcon
= NULL
;
2068 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2071 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2078 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2079 UserDereferenceObject(Class
->spicnSm
);
2086 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2087 Class
->spicnSm
= NewSmallIcon
;
2089 /* Update the clones */
2090 Class
= Class
->pclsClone
;
2091 while (Class
!= NULL
)
2094 UserDereferenceObject(Class
->spicnSm
);
2096 UserReferenceObject(NewSmallIcon
);
2097 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2098 Class
->spicnSm
= NewSmallIcon
;
2099 Class
= Class
->pclsNext
;
2104 /* FIXME: Get handle from pointer to ICON object */
2105 Ret
= (ULONG_PTR
)Class
->hIconSm
;
2106 if (Class
->hIconSm
== (HANDLE
)NewLong
) break;
2107 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2109 if (Class
->hIconSmIntern
)
2111 IntClassDestroyIcon(Class
->hIconSmIntern
);
2112 Class
->hIconSmIntern
= NULL
;
2114 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2116 if (Class
->hIcon
&& !Class
->hIconSmIntern
)
2118 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( Class
->hIcon
, IMAGE_ICON
,
2119 UserGetSystemMetrics( SM_CXSMICON
),
2120 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2122 if (hIconSmIntern
) Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2123 //// FIXME: Very hacky here but it passes the tests....
2124 Ret
= 0; // Fixes 1009
2126 Class
->hIconSm
= (HANDLE
)NewLong
;
2128 /* Update the clones */
2129 Class
= Class
->pclsClone
;
2130 while (Class
!= NULL
)
2132 Class
->hIconSm
= (HANDLE
)NewLong
;
2133 Class
->hIconSmIntern
= hIconSmIntern
;
2134 Class
= Class
->pclsNext
;
2140 Ret
= (ULONG_PTR
)Class
->hModule
;
2141 Class
->hModule
= (HINSTANCE
)NewLong
;
2143 /* Update the clones */
2144 Class
= Class
->pclsClone
;
2145 while (Class
!= NULL
)
2147 Class
->hModule
= (HINSTANCE
)NewLong
;
2148 Class
= Class
->pclsNext
;
2154 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2156 if (!IntSetClassMenuName(Class
,
2159 ERR("Setting the class menu name failed!\n");
2162 /* FIXME: Really return NULL? Wine does so... */
2167 Ret
= (ULONG_PTR
)Class
->style
;
2168 Class
->style
= (UINT
)NewLong
;
2170 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2171 move the class to the appropriate list? For now, we save
2172 the original value in Class->Global, so we can always
2173 locate the appropriate list */
2175 /* Update the clones */
2176 Class
= Class
->pclsClone
;
2177 while (Class
!= NULL
)
2179 Class
->style
= (UINT
)NewLong
;
2180 Class
= Class
->pclsNext
;
2185 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2192 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2194 Ret
= (ULONG_PTR
)Class
->atomClassName
;
2195 if (!IntSetClassAtom(Class
,
2204 EngSetLastError(ERROR_INVALID_INDEX
);
2212 UserGetClassInfo(IN PCLS Class
,
2213 OUT PWNDCLASSEXW lpwcx
,
2215 HINSTANCE hInstance
)
2217 if (!Class
) return FALSE
;
2219 lpwcx
->style
= Class
->style
;
2221 // If fnId is set, clear the global bit. See wine class test check_style.
2223 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2225 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2227 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2228 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2229 #ifdef NEW_CURSORICON
2230 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2231 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2232 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2234 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME: Get handle from pointer */
2235 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME: Get handle from pointer */
2236 /* FIXME: Get handle from pointer */
2237 lpwcx
->hIconSm
= Class
->hIconSm
? Class
->hIconSm
: Class
->hIconSmIntern
;
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);
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
;
2328 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
2329 hBrush
= DefaultServerClasses
[i
].hBrush
;
2330 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2332 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2334 wc
.hbrBackground
= hBrush
;
2335 wc
.lpszMenuName
= NULL
;
2336 wc
.lpszClassName
= ClassName
.Buffer
;
2339 Class
= IntCreateClass( &wc
,
2342 DefaultServerClasses
[i
].fiId
,
2348 Class
->pclsNext
= ppi
->pclsPublicList
;
2349 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2352 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2356 ERR("!!! Registering system class failed!\n");
2360 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2364 /* SYSCALLS *****************************************************************/
2368 NtUserRegisterClassExWOW(
2370 PUNICODE_STRING ClassName
,
2371 PUNICODE_STRING ClsNVersion
,
2372 PCLSMENUNAME pClassMenuName
,
2378 * Registers a new class with the window manager
2380 * lpwcx = Win32 extended window class structure
2381 * bUnicodeClass = Whether to send ANSI or unicode strings
2382 * to window procedures
2384 * Atom identifying the new class
2387 WNDCLASSEXW CapturedClassInfo
= {0};
2388 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2389 RTL_ATOM Ret
= (RTL_ATOM
)0;
2390 PPROCESSINFO ppi
= GetW32ProcessInfo();
2392 if (Flags
& ~(CSF_ANSIPROC
))
2394 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2395 EngSetLastError(ERROR_INVALID_FLAGS
);
2399 UserEnterExclusive();
2401 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2403 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2405 UserRegisterSystemClasses();
2410 /* Probe the parameters and basic parameter checks */
2411 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2413 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2414 goto InvalidParameter
;
2418 sizeof(WNDCLASSEXW
),
2420 RtlCopyMemory(&CapturedClassInfo
,
2422 sizeof(WNDCLASSEXW
));
2424 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2426 ProbeForRead(pClassMenuName
,
2427 sizeof(CLSMENUNAME
),
2430 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2432 if ( (CapturedName
.Length
& 1) ||
2433 (CapturedMenuName
.Length
& 1) ||
2434 (CapturedClassInfo
.cbClsExtra
< 0) ||
2435 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2436 CapturedMenuName
.Length
+ sizeof(CLS
))
2437 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2438 (CapturedClassInfo
.cbWndExtra
< 0) ||
2439 (CapturedClassInfo
.hInstance
== NULL
) )
2441 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2442 goto InvalidParameter
;
2445 if (CapturedName
.Length
!= 0)
2447 ProbeForRead(CapturedName
.Buffer
,
2448 CapturedName
.Length
,
2453 if (!IS_ATOM(CapturedName
.Buffer
))
2455 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2456 goto InvalidParameter
;
2460 if (CapturedMenuName
.Length
!= 0)
2462 ProbeForRead(CapturedMenuName
.Buffer
,
2463 CapturedMenuName
.Length
,
2466 else if (CapturedMenuName
.Buffer
!= NULL
&&
2467 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2469 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2471 EngSetLastError(ERROR_INVALID_PARAMETER
);
2475 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2476 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2477 // If this pops up we know what todo!
2478 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2481 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2483 /* Register the class */
2484 Ret
= UserRegisterClass(&CapturedClassInfo
,
2490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2492 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2493 SetLastNtError(_SEH2_GetExceptionCode());
2499 ERR("NtUserRegisterClassExWOW Null Return!\n");
2508 NtUserSetClassLong(HWND hWnd
,
2510 ULONG_PTR dwNewLong
,
2517 UserEnterExclusive();
2519 pi
= GetW32ProcessInfo();
2521 Window
= UserGetWindowObject(hWnd
);
2524 if (Window
->head
.pti
->ppi
!= pi
)
2526 EngSetLastError(ERROR_ACCESS_DENIED
);
2532 UNICODE_STRING Value
;
2534 /* Probe the parameters */
2535 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2537 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2538 if (Value
.Length
& 1)
2540 goto InvalidParameter
;
2543 if (Value
.Length
!= 0)
2545 ProbeForRead(Value
.Buffer
,
2551 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2553 goto InvalidParameter
;
2555 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2558 EngSetLastError(ERROR_INVALID_PARAMETER
);
2563 dwNewLong
= (ULONG_PTR
)&Value
;
2566 Ret
= UserSetClassLongPtr(Window
->pcls
,
2571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2573 SetLastNtError(_SEH2_GetExceptionCode());
2592 * NOTE: Obsoleted in 32-bit windows
2599 NtUserUnregisterClass(
2600 IN PUNICODE_STRING ClassNameOrAtom
,
2601 IN HINSTANCE hInstance
,
2602 OUT PCLSMENUNAME pClassMenuName
)
2604 UNICODE_STRING SafeClassName
;
2608 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2609 if (!NT_SUCCESS(Status
))
2611 ERR("Error capturing the class name\n");
2612 SetLastNtError(Status
);
2616 UserEnterExclusive();
2618 /* Unregister the class */
2619 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2623 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2624 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2630 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2634 HINSTANCE hInstance
,
2635 PUNICODE_STRING ClassName
,
2636 LPWNDCLASSEXW lpWndClassEx
,
2637 LPWSTR
*ppszMenuName
,
2640 UNICODE_STRING SafeClassName
;
2641 WNDCLASSEXW Safewcexw
;
2643 RTL_ATOM ClassAtom
= 0;
2650 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2651 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2655 SetLastNtError(_SEH2_GetExceptionCode());
2656 _SEH2_YIELD(return FALSE
);
2660 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2661 if (!NT_SUCCESS(Status
))
2663 ERR("Error capturing the class name\n");
2664 SetLastNtError(Status
);
2668 // If null instance use client.
2669 if (!hInstance
) hInstance
= hModClient
;
2671 TRACE("GetClassInfo(%wZ, %p)\n", SafeClassName
, hInstance
);
2673 /* NOTE: Need exclusive lock because getting the wndproc might require the
2674 creation of a call procedure handle */
2675 UserEnterExclusive();
2677 ppi
= GetW32ProcessInfo();
2678 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2680 UserRegisterSystemClasses();
2683 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2688 if (ClassAtom
!= (RTL_ATOM
)0)
2690 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2694 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2704 /* Emulate Function. */
2705 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2707 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2710 /* We must return the atom of the class here instead of just TRUE. */
2711 /* Undocumented behavior! Return the class atom as a BOOL! */
2712 Ret
= (BOOL
)ClassAtom
;
2714 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2716 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2722 if (!IS_ATOM(SafeClassName
.Buffer
))
2723 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2730 NtUserGetClassName (IN HWND hWnd
,
2732 OUT PUNICODE_STRING ClassName
)
2735 UNICODE_STRING CapturedClassName
;
2741 Window
= UserGetWindowObject(hWnd
);
2744 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2746 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2748 Atom
= gpsi
->atomSysClass
[iCls
];
2754 ProbeForWriteUnicodeString(ClassName
);
2755 CapturedClassName
= *ClassName
;
2757 /* Get the class name */
2758 Ret
= UserGetClassName(Window
->pcls
,
2765 /* Update the Length field */
2766 ClassName
->Length
= CapturedClassName
.Length
;
2769 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2771 SetLastNtError(_SEH2_GetExceptionCode());
2781 /* Return Pointer to Class structure. */
2785 HINSTANCE hInstance
,
2786 PUNICODE_STRING ClassName
)
2788 UNICODE_STRING SafeClassName
;
2791 RTL_ATOM ClassAtom
= 0;
2794 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2795 if (!NT_SUCCESS(Status
))
2797 ERR("Error capturing the class name\n");
2798 SetLastNtError(Status
);
2802 UserEnterExclusive();
2804 pi
= GetW32ProcessInfo();
2806 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2813 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2817 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2818 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2822 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.