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
->spicnSm
);
254 UserDereferenceObject(Class
->spcur
);
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 /* Replace the class in the list */
842 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
844 *ClassLinkPtr
= &NewClass
->pclsNext
;
846 /* Free the obsolete class on the desktop heap */
847 Class
->pclsBase
= NULL
;
848 IntDestroyClass(Class
);
856 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
857 IN OUT PCLS
*ClassList
,
858 IN BOOL FreeOnFailure
,
861 PCLS Class
, NextClass
, *Link
;
863 /* NOTE: We only need to check base classes! When classes are no longer needed
864 on a desktop, the clones will be freed automatically as soon as possible.
865 However, we need to move base classes to the shared heap, as soon as
866 the last desktop heap where a class is allocated on is about to be destroyed.
867 If we didn't move the class to the shared heap, the class would become
870 ASSERT(Desktop
!= NULL
);
874 while (Class
!= NULL
)
876 NextClass
= Class
->pclsNext
;
878 ASSERT(Class
->pclsBase
== Class
);
880 if (Class
->rpdeskParent
== Desktop
&&
881 Class
->cWndReferenceCount
== 0)
883 /* There shouldn't be any clones around anymore! */
884 ASSERT(Class
->pclsClone
== NULL
);
886 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
887 /* FIXME: We could move the class to another desktop heap if there's still desktops
888 mapped into the process... */
890 /* Move the class to the shared heap */
891 if (IntMoveClassToSharedHeap(Class
,
894 ASSERT(*Link
== NextClass
);
898 ASSERT(NextClass
== Class
->pclsNext
);
902 /* Unlink the base class */
903 (void)InterlockedExchangePointer((PVOID
*)Link
,
906 /* We can free the old base class now */
907 Class
->pclsBase
= NULL
;
908 IntDestroyClass(Class
);
912 Link
= &Class
->pclsNext
;
918 Link
= &Class
->pclsNext
;
925 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
926 IN BOOL FreeOnFailure
)
931 pi
= GetW32ProcessInfo();
933 /* Check all local classes */
934 IntCheckDesktopClasses(Desktop
,
935 &pi
->pclsPrivateList
,
939 /* Check all global classes */
940 IntCheckDesktopClasses(Desktop
,
946 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
947 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
955 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
956 IN PUNICODE_STRING ClassName
,
957 IN PUNICODE_STRING MenuName
,
967 PWSTR pszMenuName
= NULL
;
968 NTSTATUS Status
= STATUS_SUCCESS
;
970 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
971 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
973 if (!IntRegisterClassAtom(ClassName
,
976 ERR("Failed to register class atom!\n");
980 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
981 if (MenuName
->Length
!= 0)
983 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
984 RtlUnicodeStringToAnsiSize(MenuName
));
985 if (pszMenuName
== NULL
)
991 Class
= DesktopHeapAlloc(Desktop
,
996 /* FIXME: The class was created before being connected
997 to a desktop. It is possible for the desktop window,
998 but should it be allowed for any other case? */
999 Class
= UserHeapAlloc(ClassSize
);
1006 RtlZeroMemory(Class
, ClassSize
);
1008 Class
->rpdeskParent
= Desktop
;
1009 Class
->pclsBase
= Class
;
1010 Class
->atomClassName
= Atom
;
1012 Class
->CSF_flags
= dwFlags
;
1014 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
1016 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
1021 PWSTR pszMenuNameBuffer
= pszMenuName
;
1023 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1024 and string buffers might raise an exception! We don't want to
1026 // What?! If the user interface was written correctly this would not be an issue!
1027 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
1028 Class
->style
= lpwcx
->style
;
1029 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
1030 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
1031 Class
->hModule
= lpwcx
->hInstance
;
1032 #ifdef NEW_CURSORICON
1033 Class
->spicn
= lpwcx
->hIcon
? UserGetCurIconObject(lpwcx
->hIcon
) : NULL
;
1034 Class
->spcur
= lpwcx
->hCursor
? UserGetCurIconObject(lpwcx
->hCursor
) : NULL
;
1035 Class
->spicnSm
= lpwcx
->hIconSm
? UserGetCurIconObject(lpwcx
->hIconSm
) : NULL
;
1037 Class
->hIcon
= lpwcx
->hIcon
;
1038 Class
->hIconSm
= lpwcx
->hIconSm
;
1039 Class
->hCursor
= lpwcx
->hCursor
;
1042 Class
->hbrBackground
= lpwcx
->hbrBackground
;
1044 /* Make a copy of the string */
1045 if (pszMenuNameBuffer
!= NULL
)
1047 Class
->MenuNameIsString
= TRUE
;
1049 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
1050 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
1053 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1055 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
1058 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1060 /* Save an ANSI copy of the string */
1061 if (pszMenuNameBuffer
!= NULL
)
1063 ANSI_STRING AnsiString
;
1065 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
1066 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1067 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
1068 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1071 if (!NT_SUCCESS(Status
))
1073 ERR("Failed to convert unicode menu name to ansi!\n");
1075 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1080 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1082 /* Save kernel use menu name and ansi class name */
1083 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
1084 //Class->lpszAnsiClassName = FIXME
1086 /* Server Side overrides class calling type (A/W)!
1087 User32 whine test_builtinproc: "deftest"
1088 built-in winproc - window A/W type automatically detected */
1089 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
1093 /* Due to the wine class "deftest" and most likely no FNID to reference
1094 from, sort through the Server Side list and compare proc addresses
1095 for match. This method will be used in related code.
1097 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
1098 { // Open ANSI or Unicode, just match, set and break.
1099 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
1101 WndProc
= GETPFNSERVER(i
);
1104 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
1106 WndProc
= GETPFNSERVER(i
);
1111 { // If a hit, we are Server Side so set the right flags and proc.
1112 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
1113 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
1114 Class
->lpfnWndProc
= WndProc
;
1118 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1119 Class
->Unicode
= TRUE
;
1121 if (Class
->style
& CS_GLOBALCLASS
)
1122 Class
->Global
= TRUE
;
1124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1126 Status
= _SEH2_GetExceptionCode();
1130 if (!NT_SUCCESS(Status
))
1132 ERR("Failed creating the class: 0x%x\n", Status
);
1134 SetLastNtError(Status
);
1136 if (pszMenuName
!= NULL
)
1137 UserHeapFree(pszMenuName
);
1139 DesktopHeapFree(Desktop
,
1143 IntDeregisterClassAtom(Atom
);
1149 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1151 if (pszMenuName
!= NULL
)
1152 UserHeapFree(pszMenuName
);
1154 IntDeregisterClassAtom(Atom
);
1156 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1159 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
1160 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1166 IntFindClass(IN RTL_ATOM Atom
,
1167 IN HINSTANCE hInstance
,
1169 OUT PCLS
**Link OPTIONAL
)
1171 PCLS Class
, *PrevLink
= ClassList
;
1174 while (Class
!= NULL
)
1176 if (Class
->atomClassName
== Atom
&&
1177 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1178 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1180 ASSERT(Class
->pclsBase
== Class
);
1187 PrevLink
= &Class
->pclsNext
;
1188 Class
= Class
->pclsNext
;
1196 IntGetAtomFromStringOrAtom(
1197 _In_ PUNICODE_STRING ClassName
,
1198 _Out_ RTL_ATOM
*Atom
)
1202 if (ClassName
->Length
!= 0)
1210 /* NOTE: Caller has to protect the call with SEH! */
1212 if (ClassName
->Length
!= 0)
1214 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1215 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1217 EngSetLastError(ERROR_INVALID_PARAMETER
);
1221 /* We need to make a local copy of the class name! The caller could
1222 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1223 We're protected by SEH, but the ranges that might be accessed were
1225 RtlCopyMemory(szBuf
,
1228 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1232 AtomName
= ClassName
->Buffer
;
1234 /* Lookup the atom */
1235 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1238 if (NT_SUCCESS(Status
))
1244 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1246 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1250 SetLastNtError(Status
);
1256 ASSERT(IS_ATOM(ClassName
->Buffer
));
1257 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1266 _In_ PUNICODE_STRING ClassName
,
1267 IN HINSTANCE hInstance OPTIONAL
,
1268 IN PPROCESSINFO pi OPTIONAL
,
1269 OUT PCLS
*BaseClass OPTIONAL
,
1270 OUT PCLS
**Link OPTIONAL
)
1272 RTL_ATOM Atom
= (RTL_ATOM
)0;
1274 ASSERT(BaseClass
!= NULL
);
1276 if (IntGetAtomFromStringOrAtom(ClassName
,
1278 Atom
!= (RTL_ATOM
)0)
1282 /* Attempt to locate the class object */
1286 /* Step 1: Try to find an exact match of locally registered classes */
1287 Class
= IntFindClass(Atom
,
1289 &pi
->pclsPrivateList
,
1292 { TRACE("Step 1: 0x%p\n",Class
);
1296 /* Step 2: Try to find any globally registered class. The hInstance
1297 is not relevant for global classes */
1298 Class
= IntFindClass(Atom
,
1300 &pi
->pclsPublicList
,
1303 { TRACE("Step 2: 0x%p 0x%p\n",Class
, Class
->hModule
);
1307 /* Step 3: Try to find any local class registered by user32 */
1308 Class
= IntFindClass(Atom
,
1310 &pi
->pclsPrivateList
,
1313 { TRACE("Step 3: 0x%p\n",Class
);
1317 /* Step 4: Try to find any global class registered by user32 */
1318 Class
= IntFindClass(Atom
,
1320 &pi
->pclsPublicList
,
1324 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1326 }else{TRACE("Step 4: 0x%p\n",Class
);}
1336 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
, BOOL bDesktopThread
)
1338 PCLS
*ClassLink
, Class
= NULL
;
1343 pti
= gptiDesktopThread
;
1345 pti
= PsGetCurrentThreadWin32Thread();
1347 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1349 UserRegisterSystemClasses();
1352 /* Check the class. */
1354 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName
, hInstance
);
1356 ClassAtom
= IntGetClassAtom(ClassName
,
1362 if (ClassAtom
== (RTL_ATOM
)0)
1364 if (IS_ATOM(ClassName
->Buffer
))
1366 ERR("Class 0x%p not found\n", ClassName
->Buffer
);
1370 ERR("Class \"%wZ\" not found\n", ClassName
);
1373 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1377 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class
, ClassAtom
);
1378 Class
= IntReferenceClass(Class
,
1383 ERR("Failed to reference window class!\n");
1391 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1392 IN PUNICODE_STRING ClassName
,
1393 IN PUNICODE_STRING MenuName
,
1401 RTL_ATOM Ret
= (RTL_ATOM
)0;
1403 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1405 pti
= GetW32ThreadInfo();
1409 // Need only to test for two conditions not four....... Fix more whine tests....
1410 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1411 ClassAtom
!= (RTL_ATOM
)0 &&
1412 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1414 Class
= IntFindClass( ClassAtom
,
1416 &pi
->pclsPrivateList
,
1419 if (Class
!= NULL
&& !Class
->Global
)
1421 // Local class already exists
1422 TRACE("Local Class 0x%x does already exist!\n", ClassAtom
);
1423 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1427 if (lpwcx
->style
& CS_GLOBALCLASS
)
1429 Class
= IntFindClass( ClassAtom
,
1431 &pi
->pclsPublicList
,
1434 if (Class
!= NULL
&& Class
->Global
)
1436 TRACE("Global Class 0x%x does already exist!\n", ClassAtom
);
1437 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1443 Class
= IntCreateClass(lpwcx
,
1455 /* Register the class */
1457 List
= &pi
->pclsPublicList
;
1459 List
= &pi
->pclsPrivateList
;
1461 Class
->pclsNext
= *List
;
1462 (void)InterlockedExchangePointer((PVOID
*)List
,
1465 Ret
= Class
->atomClassName
;
1469 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1476 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1477 IN HINSTANCE hInstance
,
1478 OUT PCLSMENUNAME pClassMenuName
)
1485 pi
= GetW32ProcessInfo();
1487 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName
, hInstance
);
1489 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1490 ClassAtom
= IntGetClassAtom(ClassName
,
1495 if (ClassAtom
== (RTL_ATOM
)0)
1497 TRACE("UserUnregisterClass: No Class found.\n");
1501 ASSERT(Class
!= NULL
);
1503 if (Class
->cWndReferenceCount
!= 0 ||
1504 Class
->pclsClone
!= NULL
)
1506 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1507 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1511 /* Must be a base class! */
1512 ASSERT(Class
->pclsBase
== Class
);
1514 /* Unlink the class */
1515 *Link
= Class
->pclsNext
;
1517 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1519 TRACE("Class 0x%p\n", Class
);
1520 TRACE("UserUnregisterClass: Good Exit!\n");
1521 Class
->atomClassName
= 0; // Don't let it linger...
1522 /* Finally free the resources */
1523 IntDestroyClass(Class
);
1526 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1531 UserGetClassName(IN PCLS Class
,
1532 IN OUT PUNICODE_STRING ClassName
,
1536 NTSTATUS Status
= STATUS_SUCCESS
;
1537 WCHAR szStaticTemp
[32];
1538 PWSTR szTemp
= NULL
;
1539 ULONG BufLen
= sizeof(szStaticTemp
);
1542 /* Note: Accessing the buffer in ClassName may raise an exception! */
1548 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1549 UNICODE_STRING UnicodeClassName
;
1551 /* Limit the size of the static buffer on the stack to the
1552 size of the buffer provided by the caller */
1553 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1555 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1558 /* Find out how big the buffer needs to be */
1559 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1560 Class
->atomClassName
,
1565 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1567 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1569 /* The buffer required exceeds the ansi buffer provided,
1570 pretend like we're using the ansi buffer and limit the
1571 size to the buffer size provided */
1572 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1575 /* Allocate a temporary buffer that can hold the unicode class name */
1576 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1581 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1585 /* Query the class name */
1586 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1587 Atom
? Atom
: Class
->atomClassName
,
1594 szTemp
= szStaticTemp
;
1596 if (NT_SUCCESS(Status
))
1598 /* Convert the atom name to ansi */
1600 RtlInitUnicodeString(&UnicodeClassName
,
1603 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1606 if (!NT_SUCCESS(Status
))
1608 SetLastNtError(Status
);
1613 Ret
= BufLen
/ sizeof(WCHAR
);
1617 BufLen
= ClassName
->MaximumLength
;
1619 /* Query the atom name */
1620 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1621 Atom
? Atom
: Class
->atomClassName
,
1627 if (!NT_SUCCESS(Status
))
1629 SetLastNtError(Status
);
1633 Ret
= BufLen
/ sizeof(WCHAR
);
1636 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1638 SetLastNtError(_SEH2_GetExceptionCode());
1642 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1644 ExFreePoolWithTag(szTemp
, USERTAG_CLASS
);
1651 IntSetClassMenuName(IN PCLS Class
,
1652 IN PUNICODE_STRING MenuName
)
1656 /* Change the base class first */
1657 Class
= Class
->pclsBase
;
1659 if (MenuName
->Length
!= 0)
1661 ANSI_STRING AnsiString
;
1664 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1666 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1667 AnsiString
.MaximumLength
);
1668 if (strBufW
!= NULL
)
1674 /* Copy the unicode string */
1675 RtlCopyMemory(strBufW
,
1678 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1680 /* Create an ANSI copy of the string */
1681 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1682 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1685 if (!NT_SUCCESS(Status
))
1687 SetLastNtError(Status
);
1693 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1695 SetLastNtError(_SEH2_GetExceptionCode());
1701 /* Update the base class */
1702 IntFreeClassMenuName(Class
);
1703 Class
->lpszClientUnicodeMenuName
= strBufW
;
1704 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1705 Class
->MenuNameIsString
= TRUE
;
1707 /* Update the clones */
1708 Class
= Class
->pclsClone
;
1709 while (Class
!= NULL
)
1711 Class
->lpszClientUnicodeMenuName
= strBufW
;
1712 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1713 Class
->MenuNameIsString
= TRUE
;
1715 Class
= Class
->pclsNext
;
1720 ERR("Failed to copy class menu name!\n");
1721 UserHeapFree(strBufW
);
1725 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1729 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1731 /* Update the base class */
1732 IntFreeClassMenuName(Class
);
1733 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1734 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1735 Class
->MenuNameIsString
= FALSE
;
1737 /* Update the clones */
1738 Class
= Class
->pclsClone
;
1739 while (Class
!= NULL
)
1741 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1742 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1743 Class
->MenuNameIsString
= FALSE
;
1745 Class
= Class
->pclsNext
;
1754 #ifndef NEW_CURSORICON
1756 IntClassDestroyIcon(HANDLE hCurIcon
)
1758 PCURICON_OBJECT CurIcon
;
1761 if (!(CurIcon
= UserGetCurIconObject(hCurIcon
)))
1764 ERR("hCurIcon was not found!\n");
1767 /* Note: IntDestroyCurIconObject will remove our reference for us! */
1768 Ret
= IntDestroyCurIconObject(CurIcon
, GetW32ProcessInfo());
1771 ERR("hCurIcon was not Destroyed!\n");
1778 UserSetClassLongPtr(IN PCLS Class
,
1780 IN ULONG_PTR NewLong
,
1784 #ifndef NEW_CURSORICON
1785 HANDLE hIconSmIntern
= NULL
;
1788 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1790 /* Change the information in the base class first, then update the clones */
1791 Class
= Class
->pclsBase
;
1797 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1799 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1800 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1802 EngSetLastError(ERROR_INVALID_PARAMETER
);
1806 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1808 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1809 certain architectures, maybe using RtlCopyMemory is a
1810 better choice for those architectures! */
1814 /* Update the clones */
1815 Class
= Class
->pclsClone
;
1816 while (Class
!= NULL
)
1818 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1819 Class
= Class
->pclsNext
;
1827 case GCL_CBWNDEXTRA
:
1828 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1829 Class
->cbwndExtra
= (INT
)NewLong
;
1831 /* Update the clones */
1832 Class
= Class
->pclsClone
;
1833 while (Class
!= NULL
)
1835 Class
->cbwndExtra
= (INT
)NewLong
;
1836 Class
= Class
->pclsNext
;
1841 case GCL_CBCLSEXTRA
:
1842 EngSetLastError(ERROR_INVALID_PARAMETER
);
1845 case GCLP_HBRBACKGROUND
:
1846 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1847 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1849 /* Update the clones */
1850 Class
= Class
->pclsClone
;
1851 while (Class
!= NULL
)
1853 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1854 Class
= Class
->pclsNext
;
1858 #ifdef NEW_CURSORICON
1861 PCURICON_OBJECT NewCursor
= NULL
;
1865 NewCursor
= UserGetCurIconObject((HCURSOR
)NewLong
);
1868 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE
);
1875 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spcur
);
1876 UserDereferenceObject(Class
->spcur
);
1889 Class
->spcur
= NewCursor
;
1891 /* Update the clones */
1892 Class
= Class
->pclsClone
;
1893 while (Class
!= NULL
)
1896 UserDereferenceObject(Class
->spcur
);
1898 UserReferenceObject(NewCursor
);
1899 Class
->spcur
= NewCursor
;
1900 Class
= Class
->pclsNext
;
1907 /* FIXME: Get handle from pointer to CURSOR object */
1908 Ret
= (ULONG_PTR
)Class
->hCursor
;
1909 Class
->hCursor
= (HANDLE
)NewLong
;
1911 /* Update the clones */
1912 Class
= Class
->pclsClone
;
1913 while (Class
!= NULL
)
1915 Class
->hCursor
= (HANDLE
)NewLong
;
1916 Class
= Class
->pclsNext
;
1922 // hIconSm, A handle to a small icon that is associated with the window class.
1923 // If this member is NULL, the system searches the icon resource specified by
1924 // the hIcon member for an icon of the appropriate size to use as the small icon.
1927 #ifdef NEW_CURSORICON
1929 PCURICON_OBJECT NewIcon
= NULL
;
1930 PCURICON_OBJECT NewSmallIcon
= NULL
;
1934 NewIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
1937 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
1944 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicn
);
1945 UserDereferenceObject(Class
->spicn
);
1958 if (Ret
&& (Class
->CSF_flags
& CSF_CACHEDSMICON
))
1960 /* We will change the small icon */
1961 UserDereferenceObject(Class
->spicnSm
);
1962 Class
->spicnSm
= NULL
;
1963 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
1966 if (NewLong
&& !Class
->spicnSm
)
1968 /* Create the new small icon from the new large(?) one */
1969 HICON SmallIconHandle
= co_IntCopyImage(
1972 UserGetSystemMetrics( SM_CXSMICON
),
1973 UserGetSystemMetrics( SM_CYSMICON
),
1975 if (SmallIconHandle
)
1978 NewSmallIcon
= Class
->spicnSm
= UserGetCurIconObject(SmallIconHandle
);
1979 /* Let the handle go, we have the reference on the object */
1980 NtUserDestroyCursor(SmallIconHandle
, FALSE
);
1981 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
1985 Class
->spicn
= NewIcon
;
1987 /* Update the clones */
1988 Class
= Class
->pclsClone
;
1989 while (Class
!= NULL
)
1992 UserDereferenceObject(Class
->spicn
);
1994 UserReferenceObject(NewIcon
);
1995 Class
->spicn
= NewIcon
;
1999 UserDereferenceObject(Class
->spicnSm
);
2000 UserReferenceObject(NewSmallIcon
);
2001 Class
->spicnSm
= NewSmallIcon
;
2002 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2004 Class
= Class
->pclsNext
;
2009 /* FIXME: Get handle from pointer to ICON object */
2010 Ret
= (ULONG_PTR
)Class
->hIcon
;
2011 if (Class
->hIcon
== (HANDLE
)NewLong
) break;
2012 if (Ret
&& Class
->hIconSmIntern
)
2014 IntClassDestroyIcon(Class
->hIconSmIntern
);
2015 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2016 Class
->hIconSmIntern
= NULL
;
2018 if (NewLong
&& !Class
->hIconSm
)
2020 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( (HICON
)NewLong
, IMAGE_ICON
,
2021 UserGetSystemMetrics( SM_CXSMICON
),
2022 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2023 Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2025 Class
->hIcon
= (HANDLE
)NewLong
;
2027 /* Update the clones */
2028 Class
= Class
->pclsClone
;
2029 while (Class
!= NULL
)
2031 Class
->hIcon
= (HANDLE
)NewLong
;
2032 Class
->hIconSmIntern
= hIconSmIntern
;
2033 Class
= Class
->pclsNext
;
2039 #ifdef NEW_CURSORICON
2041 PCURICON_OBJECT NewSmallIcon
= NULL
;
2045 NewSmallIcon
= UserGetCurIconObject((HCURSOR
)NewLong
);
2048 EngSetLastError(ERROR_INVALID_ICON_HANDLE
);
2055 Ret
= (ULONG_PTR
)UserHMGetHandle(Class
->spicnSm
);
2056 UserDereferenceObject(Class
->spicnSm
);
2063 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2064 Class
->spicnSm
= NewSmallIcon
;
2066 /* Update the clones */
2067 Class
= Class
->pclsClone
;
2068 while (Class
!= NULL
)
2071 UserDereferenceObject(Class
->spicnSm
);
2073 UserReferenceObject(NewSmallIcon
);
2074 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2075 Class
->spicnSm
= NewSmallIcon
;
2076 Class
= Class
->pclsNext
;
2081 /* FIXME: Get handle from pointer to ICON object */
2082 Ret
= (ULONG_PTR
)Class
->hIconSm
;
2083 if (Class
->hIconSm
== (HANDLE
)NewLong
) break;
2084 if (Class
->CSF_flags
& CSF_CACHEDSMICON
)
2086 if (Class
->hIconSmIntern
)
2088 IntClassDestroyIcon(Class
->hIconSmIntern
);
2089 Class
->hIconSmIntern
= NULL
;
2091 Class
->CSF_flags
&= ~CSF_CACHEDSMICON
;
2093 if (Class
->hIcon
&& !Class
->hIconSmIntern
)
2095 hIconSmIntern
= Class
->hIconSmIntern
= co_IntCopyImage( Class
->hIcon
, IMAGE_ICON
,
2096 UserGetSystemMetrics( SM_CXSMICON
),
2097 UserGetSystemMetrics( SM_CYSMICON
), 0 );
2099 if (hIconSmIntern
) Class
->CSF_flags
|= CSF_CACHEDSMICON
;
2100 //// FIXME: Very hacky here but it passes the tests....
2101 Ret
= 0; // Fixes 1009
2103 Class
->hIconSm
= (HANDLE
)NewLong
;
2105 /* Update the clones */
2106 Class
= Class
->pclsClone
;
2107 while (Class
!= NULL
)
2109 Class
->hIconSm
= (HANDLE
)NewLong
;
2110 Class
->hIconSmIntern
= hIconSmIntern
;
2111 Class
= Class
->pclsNext
;
2117 Ret
= (ULONG_PTR
)Class
->hModule
;
2118 Class
->hModule
= (HINSTANCE
)NewLong
;
2120 /* Update the clones */
2121 Class
= Class
->pclsClone
;
2122 while (Class
!= NULL
)
2124 Class
->hModule
= (HINSTANCE
)NewLong
;
2125 Class
= Class
->pclsNext
;
2131 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2133 if (!IntSetClassMenuName(Class
,
2136 ERR("Setting the class menu name failed!\n");
2139 /* FIXME: Really return NULL? Wine does so... */
2144 Ret
= (ULONG_PTR
)Class
->style
;
2145 Class
->style
= (UINT
)NewLong
;
2147 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2148 move the class to the appropriate list? For now, we save
2149 the original value in Class->Global, so we can always
2150 locate the appropriate list */
2152 /* Update the clones */
2153 Class
= Class
->pclsClone
;
2154 while (Class
!= NULL
)
2156 Class
->style
= (UINT
)NewLong
;
2157 Class
= Class
->pclsNext
;
2162 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
2169 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
2171 Ret
= (ULONG_PTR
)Class
->atomClassName
;
2172 if (!IntSetClassAtom(Class
,
2181 EngSetLastError(ERROR_INVALID_INDEX
);
2189 UserGetClassInfo(IN PCLS Class
,
2190 OUT PWNDCLASSEXW lpwcx
,
2192 HINSTANCE hInstance
)
2194 if (!Class
) return FALSE
;
2196 lpwcx
->style
= Class
->style
;
2198 // If fnId is set, clear the global bit. See wine class test check_style.
2200 lpwcx
->style
&= ~CS_GLOBALCLASS
;
2202 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
2204 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
2205 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
2206 #ifdef NEW_CURSORICON
2207 lpwcx
->hIcon
= Class
->spicn
? UserHMGetHandle(Class
->spicn
) : NULL
;
2208 lpwcx
->hCursor
= Class
->spcur
? UserHMGetHandle(Class
->spcur
) : NULL
;
2209 lpwcx
->hIconSm
= Class
->spicnSm
? UserHMGetHandle(Class
->spicnSm
) : NULL
;
2211 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME: Get handle from pointer */
2212 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME: Get handle from pointer */
2213 /* FIXME: Get handle from pointer */
2214 lpwcx
->hIconSm
= Class
->hIconSm
? Class
->hIconSm
: Class
->hIconSmIntern
;
2216 lpwcx
->hbrBackground
= Class
->hbrBackground
;
2218 /* Copy non-string to user first. */
2220 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
2222 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
2224 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2225 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2226 * lpszClientXxxMenuName should already be mapped to user space.
2228 /* Copy string ptr to user. */
2229 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
2230 Class
->MenuNameIsString
)
2232 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
2233 (PVOID
)Class
->lpszClientAnsiMenuName
:
2234 (PVOID
)Class
->lpszClientUnicodeMenuName
);
2237 if (hInstance
== hModClient
)
2238 lpwcx
->hInstance
= NULL
;
2240 lpwcx
->hInstance
= hInstance
;
2242 /* FIXME: Return the string? Okay! This is performed in User32! */
2243 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2253 UserRegisterSystemClasses(VOID
)
2256 UNICODE_STRING ClassName
, MenuName
;
2257 PPROCESSINFO ppi
= GetW32ProcessInfo();
2264 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
2267 if ( hModClient
== NULL
)
2270 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
2271 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
2273 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
2275 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
2277 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
2281 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
2282 ClassName
.Length
= 0;
2283 ClassName
.MaximumLength
= 0;
2286 wc
.cbSize
= sizeof(wc
);
2287 wc
.style
= DefaultServerClasses
[i
].Style
;
2289 Flags
|= CSF_SERVERSIDEPROC
;
2291 if (DefaultServerClasses
[i
].ProcW
)
2293 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
2294 wc
.hInstance
= hModuleWin
;
2298 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
2299 wc
.hInstance
= hModClient
;
2303 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
2305 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
2306 hBrush
= DefaultServerClasses
[i
].hBrush
;
2307 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
2309 hBrush
= IntGetSysColorBrush((INT
)hBrush
);
2311 wc
.hbrBackground
= hBrush
;
2312 wc
.lpszMenuName
= NULL
;
2313 wc
.lpszClassName
= ClassName
.Buffer
;
2316 Class
= IntCreateClass( &wc
,
2319 DefaultServerClasses
[i
].fiId
,
2325 Class
->pclsNext
= ppi
->pclsPublicList
;
2326 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
2329 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
2333 ERR("!!! Registering system class failed!\n");
2337 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
2341 /* SYSCALLS *****************************************************************/
2345 NtUserRegisterClassExWOW(
2347 PUNICODE_STRING ClassName
,
2348 PUNICODE_STRING ClsNVersion
,
2349 PCLSMENUNAME pClassMenuName
,
2355 * Registers a new class with the window manager
2357 * lpwcx = Win32 extended window class structure
2358 * bUnicodeClass = Whether to send ANSI or unicode strings
2359 * to window procedures
2361 * Atom identifying the new class
2364 WNDCLASSEXW CapturedClassInfo
= {0};
2365 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2366 RTL_ATOM Ret
= (RTL_ATOM
)0;
2367 PPROCESSINFO ppi
= GetW32ProcessInfo();
2369 if (Flags
& ~(CSF_ANSIPROC
))
2371 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2372 EngSetLastError(ERROR_INVALID_FLAGS
);
2376 UserEnterExclusive();
2378 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2380 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2382 UserRegisterSystemClasses();
2387 /* Probe the parameters and basic parameter checks */
2388 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2390 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2391 goto InvalidParameter
;
2395 sizeof(WNDCLASSEXW
),
2397 RtlCopyMemory(&CapturedClassInfo
,
2399 sizeof(WNDCLASSEXW
));
2401 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2403 ProbeForRead(pClassMenuName
,
2404 sizeof(CLSMENUNAME
),
2407 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2409 if ( (CapturedName
.Length
& 1) ||
2410 (CapturedMenuName
.Length
& 1) ||
2411 (CapturedClassInfo
.cbClsExtra
< 0) ||
2412 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2413 CapturedMenuName
.Length
+ sizeof(CLS
))
2414 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2415 (CapturedClassInfo
.cbWndExtra
< 0) ||
2416 (CapturedClassInfo
.hInstance
== NULL
) )
2418 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2419 goto InvalidParameter
;
2422 if (CapturedName
.Length
!= 0)
2424 ProbeForRead(CapturedName
.Buffer
,
2425 CapturedName
.Length
,
2430 if (!IS_ATOM(CapturedName
.Buffer
))
2432 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2433 goto InvalidParameter
;
2437 if (CapturedMenuName
.Length
!= 0)
2439 ProbeForRead(CapturedMenuName
.Buffer
,
2440 CapturedMenuName
.Length
,
2443 else if (CapturedMenuName
.Buffer
!= NULL
&&
2444 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2446 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2448 EngSetLastError(ERROR_INVALID_PARAMETER
);
2452 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2453 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2454 // If this pops up we know what todo!
2455 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2458 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2460 /* Register the class */
2461 Ret
= UserRegisterClass(&CapturedClassInfo
,
2467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2469 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2470 SetLastNtError(_SEH2_GetExceptionCode());
2476 ERR("NtUserRegisterClassExWOW Null Return!\n");
2485 NtUserSetClassLong(HWND hWnd
,
2487 ULONG_PTR dwNewLong
,
2494 UserEnterExclusive();
2496 pi
= GetW32ProcessInfo();
2498 Window
= UserGetWindowObject(hWnd
);
2501 if (Window
->head
.pti
->ppi
!= pi
)
2503 EngSetLastError(ERROR_ACCESS_DENIED
);
2509 UNICODE_STRING Value
;
2511 /* Probe the parameters */
2512 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2514 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2515 if (Value
.Length
& 1)
2517 goto InvalidParameter
;
2520 if (Value
.Length
!= 0)
2522 ProbeForRead(Value
.Buffer
,
2528 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2530 goto InvalidParameter
;
2532 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2535 EngSetLastError(ERROR_INVALID_PARAMETER
);
2540 dwNewLong
= (ULONG_PTR
)&Value
;
2543 Ret
= UserSetClassLongPtr(Window
->pcls
,
2548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2550 SetLastNtError(_SEH2_GetExceptionCode());
2569 * NOTE: Obsoleted in 32-bit windows
2576 NtUserUnregisterClass(
2577 IN PUNICODE_STRING ClassNameOrAtom
,
2578 IN HINSTANCE hInstance
,
2579 OUT PCLSMENUNAME pClassMenuName
)
2581 UNICODE_STRING SafeClassName
;
2585 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassNameOrAtom
);
2586 if (!NT_SUCCESS(Status
))
2588 ERR("Error capturing the class name\n");
2589 SetLastNtError(Status
);
2593 UserEnterExclusive();
2595 /* Unregister the class */
2596 Ret
= UserUnregisterClass(&SafeClassName
, hInstance
, NULL
); // Null for now~
2600 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2601 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2607 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2611 HINSTANCE hInstance
,
2612 PUNICODE_STRING ClassName
,
2613 LPWNDCLASSEXW lpWndClassEx
,
2614 LPWSTR
*ppszMenuName
,
2617 UNICODE_STRING SafeClassName
;
2618 WNDCLASSEXW Safewcexw
;
2620 RTL_ATOM ClassAtom
= 0;
2627 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2628 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2630 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2632 SetLastNtError(_SEH2_GetExceptionCode());
2633 _SEH2_YIELD(return FALSE
);
2637 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2638 if (!NT_SUCCESS(Status
))
2640 ERR("Error capturing the class name\n");
2641 SetLastNtError(Status
);
2645 // If null instance use client.
2646 if (!hInstance
) hInstance
= hModClient
;
2648 TRACE("GetClassInfo(%wZ, %p)\n", SafeClassName
, hInstance
);
2650 /* NOTE: Need exclusive lock because getting the wndproc might require the
2651 creation of a call procedure handle */
2652 UserEnterExclusive();
2654 ppi
= GetW32ProcessInfo();
2655 if (!(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2657 UserRegisterSystemClasses();
2660 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2665 if (ClassAtom
!= (RTL_ATOM
)0)
2667 Ret
= UserGetClassInfo(Class
, &Safewcexw
, bAnsi
, hInstance
);
2671 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2681 /* Emulate Function. */
2682 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2684 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2687 /* We must return the atom of the class here instead of just TRUE. */
2688 /* Undocumented behavior! Return the class atom as a BOOL! */
2689 Ret
= (BOOL
)ClassAtom
;
2691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2693 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2699 if (!IS_ATOM(SafeClassName
.Buffer
))
2700 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2707 NtUserGetClassName (IN HWND hWnd
,
2709 OUT PUNICODE_STRING ClassName
)
2712 UNICODE_STRING CapturedClassName
;
2718 Window
= UserGetWindowObject(hWnd
);
2721 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2723 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2725 Atom
= gpsi
->atomSysClass
[iCls
];
2731 ProbeForWriteUnicodeString(ClassName
);
2732 CapturedClassName
= *ClassName
;
2734 /* Get the class name */
2735 Ret
= UserGetClassName(Window
->pcls
,
2742 /* Update the Length field */
2743 ClassName
->Length
= CapturedClassName
.Length
;
2746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2748 SetLastNtError(_SEH2_GetExceptionCode());
2758 /* Return Pointer to Class structure. */
2762 HINSTANCE hInstance
,
2763 PUNICODE_STRING ClassName
)
2765 UNICODE_STRING SafeClassName
;
2768 RTL_ATOM ClassAtom
= 0;
2771 Status
= ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName
, ClassName
);
2772 if (!NT_SUCCESS(Status
))
2774 ERR("Error capturing the class name\n");
2775 SetLastNtError(Status
);
2779 UserEnterExclusive();
2781 pi
= GetW32ProcessInfo();
2783 ClassAtom
= IntGetClassAtom(&SafeClassName
,
2790 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2794 if (SafeClassName
.Buffer
&& !IS_ATOM(SafeClassName
.Buffer
))
2795 ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2799 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.