2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2006 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
27 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
34 #include <wine/debug.h>
36 /* WINDOWCLASS ***************************************************************/
39 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class
)
41 /* free the menu name, if it was changed and allocated */
42 if (Class
->MenuName
!= NULL
&& !IS_INTRESOURCE(Class
->MenuName
) &&
43 Class
->MenuName
!= (PWSTR
)(Class
+ 1))
45 UserHeapFree(Class
->MenuName
);
46 Class
->MenuName
= NULL
;
47 Class
->AnsiMenuName
= NULL
;
52 IntDestroyClass(IN OUT PWINDOWCLASS Class
)
54 /* there shouldn't be any clones anymore */
55 //ASSERT(Class->Windows == 0);
58 DPRINT1("FIXME: W3Seek's Class Patch is broken!\n");
61 ASSERT(Class
->Clone
== NULL
);
63 if (Class
->Base
== Class
)
65 /* destruct resources shared with clones */
66 if (!Class
->System
&& Class
->CallProc
!= NULL
)
68 DestroyCallProc(Class
->GlobalCallProc
? NULL
: Class
->Desktop
,
72 if (Class
->CallProc2
!= NULL
)
74 DestroyCallProc(Class
->GlobalCallProc2
? NULL
: Class
->Desktop
,
78 IntFreeClassMenuName(Class
);
81 /* free the structure */
82 if (Class
->Desktop
!= NULL
)
84 DesktopHeapFree(Class
->Desktop
,
94 /* clean all process classes. all process windows must cleaned first!! */
95 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
98 PW32PROCESSINFO pi
= Process
->ProcessInfo
;
102 /* free all local classes */
103 Class
= pi
->LocalClassList
;
104 while (Class
!= NULL
)
106 pi
->LocalClassList
= Class
->Next
;
108 ASSERT(Class
->Base
== Class
);
109 IntDestroyClass(Class
);
111 Class
= pi
->LocalClassList
;
114 /* free all global classes */
115 Class
= pi
->GlobalClassList
;
116 while (Class
!= NULL
)
118 pi
->GlobalClassList
= Class
->Next
;
120 ASSERT(Class
->Base
== Class
);
121 IntDestroyClass(Class
);
123 Class
= pi
->GlobalClassList
;
126 /* free all system classes */
127 Class
= pi
->SystemClassList
;
128 while (Class
!= NULL
)
130 pi
->SystemClassList
= Class
->Next
;
132 ASSERT(Class
->Base
== Class
);
133 IntDestroyClass(Class
);
135 Class
= pi
->SystemClassList
;
141 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
148 if (ClassName
->Length
!= 0)
150 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
151 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
153 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
160 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
164 AtomName
= ClassName
->Buffer
;
166 Status
= RtlAddAtomToAtomTable(gAtomTable
,
170 if (!NT_SUCCESS(Status
))
172 SetLastNtError(Status
);
180 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
182 return RtlDeleteAtomFromAtomTable(gAtomTable
,
187 IntSetClassAtom(IN OUT PWINDOWCLASS Class
,
188 IN PUNICODE_STRING ClassName
)
190 RTL_ATOM Atom
= (RTL_ATOM
)0;
192 /* update the base class first */
195 if (!IntRegisterClassAtom(ClassName
,
201 IntDeregisterClassAtom(Class
->Atom
);
205 /* update the clones */
206 Class
= Class
->Clone
;
207 while (Class
!= NULL
)
218 IntGetClassWndProc(IN PWINDOWCLASS Class
,
219 IN PW32PROCESSINFO pi
,
221 IN BOOL UseCallProc2
)
223 ASSERT(UserIsEnteredExclusive() == TRUE
);
227 return (Ansi
? Class
->WndProcExtra
: Class
->WndProc
);
231 if (!Ansi
== Class
->Unicode
)
233 return Class
->WndProc
;
237 PCALLPROC
*CallProcPtr
;
238 PWINDOWCLASS BaseClass
;
240 /* make sure the call procedures are located on the desktop
241 of the base class! */
242 BaseClass
= Class
->Base
;
245 CallProcPtr
= (UseCallProc2
? &Class
->CallProc2
: &Class
->CallProc
);
247 if (*CallProcPtr
!= NULL
)
249 return GetCallProcHandle(*CallProcPtr
);
253 PCALLPROC NewCallProc
;
258 NewCallProc
= CreateCallProc(Class
->Desktop
,
262 if (NewCallProc
== NULL
)
264 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
268 *CallProcPtr
= NewCallProc
;
270 if (Class
->Desktop
== NULL
)
273 Class
->GlobalCallProc2
= TRUE
;
275 Class
->GlobalCallProc
= TRUE
;
278 /* update the clones */
279 Class
= Class
->Clone
;
280 while (Class
!= NULL
)
284 Class
->CallProc2
= NewCallProc
;
285 Class
->GlobalCallProc2
= BaseClass
->GlobalCallProc2
;
289 Class
->CallProc
= NewCallProc
;
290 Class
->GlobalCallProc
= BaseClass
->GlobalCallProc
;
296 return GetCallProcHandle(NewCallProc
);
303 IntSetClassWndProc(IN OUT PWINDOWCLASS Class
,
311 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class
->Atom
);
312 SetLastWin32Error(ERROR_ACCESS_DENIED
);
316 /* update the base class first */
319 /* resolve any callproc handle if possible */
320 if (IsCallProcHandle(WndProc
))
324 if (UserGetCallProcInfo((HANDLE
)WndProc
,
327 WndProc
= wpInfo
.WindowProc
;
328 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
332 Ret
= IntGetClassWndProc(Class
,
341 /* update the class info */
342 Class
->Unicode
= !Ansi
;
343 Class
->WndProc
= WndProc
;
344 if (Class
->CallProc
!= NULL
)
346 Class
->CallProc
->WndProc
= WndProc
;
347 Class
->CallProc
->Unicode
= !Ansi
;
350 /* update the clones */
351 Class
= Class
->Clone
;
352 while (Class
!= NULL
)
354 Class
->Unicode
= !Ansi
;
355 Class
->WndProc
= WndProc
;
364 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass
,
365 IN OUT PWINDOWCLASS
*ClassLink
,
371 ASSERT(Desktop
!= NULL
);
372 ASSERT(BaseClass
->Base
== BaseClass
);
374 if (BaseClass
->Desktop
== Desktop
)
376 /* it is most likely that a window is created on the same
377 desktop as the window class. */
382 if (BaseClass
->Desktop
== NULL
)
384 ASSERT(BaseClass
->Windows
== 0);
385 ASSERT(BaseClass
->Clone
== NULL
);
387 /* Classes are also located in the shared heap when the class
388 was created before the thread attached to a desktop. As soon
389 as a window is created for such a class located on the shared
390 heap, the class is cloned into the desktop heap on which the
391 window is created. */
396 /* The user is asking for a class object on a different desktop,
398 Class
= BaseClass
->Clone
;
399 while (Class
!= NULL
)
401 if (Class
->Desktop
== Desktop
)
403 ASSERT(Class
->Base
== BaseClass
);
404 ASSERT(Class
->Clone
== NULL
);
414 /* The window is created on a different desktop, we need to
415 clone the class object to the desktop heap of the window! */
416 ClassSize
= (SIZE_T
)BaseClass
->ClassExtraDataOffset
+
417 (SIZE_T
)BaseClass
->ClsExtra
;
419 Class
= DesktopHeapAlloc(Desktop
,
423 /* simply clone the class */
428 /* update some pointers and link the class */
429 Class
->Desktop
= Desktop
;
432 if (BaseClass
->Desktop
== NULL
)
434 /* we don't really need the base class on the shared
435 heap anymore, delete it so the only class left is
436 the clone we just created, which now serves as the
438 ASSERT(BaseClass
->Clone
== NULL
);
439 ASSERT(Class
->Clone
== NULL
);
441 Class
->Next
= BaseClass
->Next
;
443 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
)
444 Class
->GlobalCallProc
= TRUE
;
445 if (BaseClass
->CallProc2
!= NULL
)
446 Class
->GlobalCallProc2
= TRUE
;
448 /* replace the base class */
449 (void)InterlockedExchangePointer(ClassLink
,
452 /* destroy the obsolete copy on the shared heap */
453 BaseClass
->Base
= NULL
;
454 BaseClass
->Clone
= NULL
;
455 IntDestroyClass(BaseClass
);
459 /* link in the clone */
461 Class
->Base
= BaseClass
;
462 Class
->Next
= BaseClass
->Clone
;
463 (void)InterlockedExchangePointer(&BaseClass
->Clone
,
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
477 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass
,
478 IN OUT PWINDOWCLASS
*ClassLink
,
483 ASSERT(BaseClass
->Base
== BaseClass
);
485 Class
= IntGetClassForDesktop(BaseClass
,
497 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class
,
498 IN OUT PWINDOWCLASS
*BaseClassLink
,
499 IN OUT PWINDOWCLASS
*CloneLink
)
501 PWINDOWCLASS Clone
, BaseClass
;
504 ASSERT(Class
->Base
!= Class
);
505 ASSERT(Class
->Base
->Clone
!= NULL
);
506 ASSERT(Class
->Desktop
!= NULL
);
507 ASSERT(Class
->Windows
!= 0);
508 ASSERT(Class
->Base
->Desktop
!= NULL
);
509 ASSERT(Class
->Base
->Windows
== 0);
511 /* unlink the clone */
512 *CloneLink
= Class
->Next
;
513 Class
->Clone
= Class
->Base
->Clone
;
515 BaseClass
= Class
->Base
;
517 if (!BaseClass
->System
&& BaseClass
->CallProc
!= NULL
&&
518 !BaseClass
->GlobalCallProc
)
520 /* we need to move the allocated call procedure */
521 CallProc
= BaseClass
->CallProc
;
522 Class
->CallProc
= CloneCallProc(Class
->Desktop
,
524 DestroyCallProc(BaseClass
->Desktop
,
528 if (BaseClass
->CallProc2
!= NULL
&&
529 !BaseClass
->GlobalCallProc2
)
531 /* we need to move the allocated call procedure */
532 CallProc
= BaseClass
->CallProc2
;
533 Class
->CallProc2
= CloneCallProc(Class
->Desktop
,
535 DestroyCallProc(BaseClass
->Desktop
,
539 /* update the class information to make it a base class */
541 Class
->Next
= (*BaseClassLink
)->Next
;
543 /* update all clones */
544 Clone
= Class
->Clone
;
545 while (Clone
!= NULL
)
547 ASSERT(Clone
->Clone
== NULL
);
551 Clone
->CallProc
= Class
->CallProc
;
552 Clone
->CallProc2
= Class
->CallProc2
;
557 /* link in the new base class */
558 (void)InterlockedExchangePointer(BaseClassLink
,
563 IntDereferenceClass(IN OUT PWINDOWCLASS Class
,
565 IN PW32PROCESSINFO pi
)
567 PWINDOWCLASS
*PrevLink
, BaseClass
, CurrentClass
;
569 BaseClass
= Class
->Base
;
571 if (--Class
->Windows
== 0)
573 if (BaseClass
== Class
)
575 ASSERT(Class
->Base
== Class
);
577 /* check if there are clones of the class on other desktops,
578 link the first clone in if possible. If there are no clones
579 then leave the class on the desktop heap. It will get moved
580 to the shared heap when the thread detaches. */
581 if (BaseClass
->Clone
!= NULL
)
583 if (BaseClass
->System
)
584 PrevLink
= &pi
->SystemClassList
;
585 else if (BaseClass
->Global
)
586 PrevLink
= &pi
->GlobalClassList
;
588 PrevLink
= &pi
->LocalClassList
;
590 while (*PrevLink
!= BaseClass
)
592 ASSERT(BaseClass
!= NULL
);
593 PrevLink
= &BaseClass
->Next
;
596 ASSERT(*PrevLink
== BaseClass
);
598 /* make the first clone become the new base class */
599 IntMakeCloneBaseClass(BaseClass
->Clone
,
603 /* destroy the class, there's still another clone of the class
604 that now serves as a base class. Make sure we don't destruct
605 resources shared by all classes (Base = NULL)! */
606 BaseClass
->Base
= NULL
;
607 BaseClass
->Clone
= NULL
;
608 IntDestroyClass(BaseClass
);
613 /* locate the cloned class and unlink it */
614 PrevLink
= &BaseClass
->Clone
;
615 CurrentClass
= BaseClass
->Clone
;
616 while (CurrentClass
!= Class
)
618 ASSERT(CurrentClass
!= NULL
);
620 PrevLink
= &CurrentClass
->Next
;
621 CurrentClass
= CurrentClass
->Next
;
624 ASSERT(CurrentClass
== Class
);
626 (void)InterlockedExchangePointer(PrevLink
,
629 ASSERT(Class
->Base
== BaseClass
);
630 ASSERT(Class
->Clone
== NULL
);
632 /* the class was just a clone, we don't need it anymore */
633 IntDestroyClass(Class
);
639 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class
,
640 IN OUT PWINDOWCLASS
**ClassLinkPtr
)
642 PWINDOWCLASS NewClass
;
646 ASSERT(Class
->Base
== Class
);
647 ASSERT(Class
->Desktop
!= NULL
);
648 ASSERT(Class
->Windows
== 0);
649 ASSERT(Class
->Clone
== NULL
);
651 ClassSize
= (SIZE_T
)Class
->ClassExtraDataOffset
+
652 (SIZE_T
)Class
->ClsExtra
;
654 /* allocate the new base class on the shared heap */
655 NewClass
= UserHeapAlloc(ClassSize
);
656 if (NewClass
!= NULL
)
658 RtlCopyMemory(NewClass
,
662 NewClass
->Desktop
= NULL
;
663 NewClass
->Base
= NewClass
;
665 if (Class
->MenuName
== (PWSTR
)(Class
+ 1))
667 ULONG_PTR AnsiDelta
= (ULONG_PTR
)Class
->AnsiMenuName
- (ULONG_PTR
)Class
->MenuName
;
669 /* fixup the self-relative MenuName pointers */
670 NewClass
->MenuName
= (PWSTR
)(NewClass
+ 1);
671 NewClass
->AnsiMenuName
= (PSTR
)((ULONG_PTR
)NewClass
->MenuName
+ AnsiDelta
);
674 if (!NewClass
->System
&& NewClass
->CallProc
!= NULL
&&
675 !NewClass
->GlobalCallProc
)
677 /* we need to move the allocated call procedure to the shared heap */
678 CallProc
= NewClass
->CallProc
;
679 NewClass
->CallProc
= CloneCallProc(NULL
,
681 DestroyCallProc(Class
->Desktop
,
684 NewClass
->GlobalCallProc
= TRUE
;
687 if (NewClass
->CallProc2
!= NULL
&&
688 !NewClass
->GlobalCallProc2
)
690 /* we need to move the allocated call procedure to the shared heap */
691 CallProc
= NewClass
->CallProc2
;
692 NewClass
->CallProc2
= CloneCallProc(NULL
,
694 DestroyCallProc(Class
->Desktop
,
697 NewClass
->GlobalCallProc2
= TRUE
;
700 /* replace the class in the list */
701 (void)InterlockedExchangePointer(*ClassLinkPtr
,
703 *ClassLinkPtr
= &NewClass
->Next
;
705 /* free the obsolete class on the desktop heap */
707 IntDestroyClass(Class
);
715 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
716 IN OUT PWINDOWCLASS
*ClassList
,
717 IN BOOL FreeOnFailure
,
720 PWINDOWCLASS Class
, NextClass
, *Link
;
722 /* NOTE: We only need to check base classes! When classes are no longer needed
723 on a desktop, the clones will be freed automatically as soon as possible.
724 However, we need to move base classes to the shared heap, as soon as
725 the last desktop heap where a class is allocated on is about to be destroyed.
726 If we didn't move the class to the shared heap, the class would become
729 ASSERT(Desktop
!= NULL
);
733 while (Class
!= NULL
)
735 NextClass
= Class
->Next
;
737 ASSERT(Class
->Base
== Class
);
739 if (Class
->Desktop
== Desktop
&&
742 /* there shouldn't be any clones around anymore! */
743 ASSERT(Class
->Clone
== NULL
);
745 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
746 /* FIXME - We could move the class to another desktop heap if there's still desktops
747 mapped into the process... */
749 /* move the class to the shared heap */
750 if (IntMoveClassToSharedHeap(Class
,
753 ASSERT(*Link
== NextClass
);
757 ASSERT(NextClass
== Class
->Next
);
761 /* unlink the base class */
762 (void)InterlockedExchangePointer(Link
,
765 /* we can free the old base class now */
767 IntDestroyClass(Class
);
784 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
785 IN BOOL FreeOnFailure
)
790 pi
= GetW32ProcessInfo();
794 /* check all local classes */
795 IntCheckDesktopClasses(Desktop
,
800 /* check all global classes */
801 IntCheckDesktopClasses(Desktop
,
802 &pi
->GlobalClassList
,
806 /* check all system classes */
807 IntCheckDesktopClasses(Desktop
,
808 &pi
->SystemClassList
,
814 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
815 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
822 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
823 IN PUNICODE_STRING ClassName
,
824 IN PUNICODE_STRING MenuName
,
828 IN PW32PROCESSINFO pi
)
831 PWINDOWCLASS Class
= NULL
;
833 NTSTATUS Status
= STATUS_SUCCESS
;
835 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
836 lpwcx
, ClassName
, MenuName
, wpExtra
, dwFlags
, Desktop
, pi
);
838 if (!IntRegisterClassAtom(ClassName
,
841 DPRINT1("Failed to register class atom!\n");
845 ClassSize
= sizeof(WINDOWCLASS
) + lpwcx
->cbClsExtra
;
846 if (MenuName
->Length
!= 0)
848 ClassSize
+= MenuName
->Length
+ sizeof(UNICODE_NULL
);
849 ClassSize
+= RtlUnicodeStringToAnsiSize(MenuName
);
854 Class
= DesktopHeapAlloc(Desktop
,
859 /* FIXME - the class was created before being connected
860 to a desktop. It is possible for the desktop window,
861 but should it be allowed for any other case? */
862 Class
= UserHeapAlloc(ClassSize
);
870 Class
->Desktop
= Desktop
;
874 if (dwFlags
& REGISTERCLASS_SYSTEM
)
876 dwFlags
&= ~REGISTERCLASS_ANSI
;
877 Class
->WndProcExtra
= wpExtra
;
878 Class
->System
= TRUE
;
885 ANSI_STRING AnsiString
;
887 /* need to protect with SEH since accessing the WNDCLASSEX structure
888 and string buffers might raise an exception! We don't want to
890 Class
->WndProc
= lpwcx
->lpfnWndProc
;
891 Class
->Style
= lpwcx
->style
;
892 Class
->ClsExtra
= lpwcx
->cbClsExtra
;
893 Class
->WndExtra
= lpwcx
->cbWndExtra
;
894 Class
->hInstance
= lpwcx
->hInstance
;
895 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
896 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
897 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
898 Class
->hbrBackground
= lpwcx
->hbrBackground
;
900 /* make a copy of the string */
901 strBuf
= (PWSTR
)(Class
+ 1);
902 if (MenuName
->Length
!= 0)
904 Class
->MenuName
= strBuf
;
905 RtlCopyMemory(Class
->MenuName
,
909 strBuf
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
912 Class
->MenuName
= MenuName
->Buffer
;
914 /* save an ansi copy of the string */
915 strBufA
= (PSTR
)strBuf
;
916 if (MenuName
->Length
!= 0)
918 Class
->AnsiMenuName
= strBufA
;
919 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
920 AnsiString
.Buffer
= strBufA
;
921 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
924 if (!NT_SUCCESS(Status
))
926 DPRINT1("Failed to convert unicode menu name to ansi!\n");
928 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
932 strBufA
+= AnsiString
.Length
+ 1;
935 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
937 /* calculate the offset of the extra data */
938 Class
->ClassExtraDataOffset
= (ULONG_PTR
)strBufA
- (ULONG_PTR
)Class
;
940 if (!(dwFlags
& REGISTERCLASS_ANSI
))
941 Class
->Unicode
= TRUE
;
943 if (Class
->Style
& CS_GLOBALCLASS
)
944 Class
->Global
= TRUE
;
948 Status
= _SEH_GetExceptionCode();
952 if (!NT_SUCCESS(Status
))
954 DPRINT1("Failed creating the class: 0x%x\n", Status
);
956 SetLastNtError(Status
);
958 DesktopHeapFree(Desktop
,
962 IntDeregisterClassAtom(Atom
);
967 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
969 IntDeregisterClassAtom(Atom
);
971 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
978 IntFindClass(IN RTL_ATOM Atom
,
979 IN HINSTANCE hInstance
,
980 IN PWINDOWCLASS
*ClassList
,
981 OUT PWINDOWCLASS
**Link OPTIONAL
)
983 PWINDOWCLASS Class
, *PrevLink
= ClassList
;
986 while (Class
!= NULL
)
988 if (Class
->Atom
== Atom
&&
989 (hInstance
== NULL
|| Class
->hInstance
== hInstance
) &&
992 ASSERT(Class
->Base
== Class
);
999 PrevLink
= &Class
->Next
;
1000 Class
= Class
->Next
;
1007 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1012 if (ClassName
->Length
!= 0)
1018 /* NOTE: Caller has to protect the call with SEH! */
1020 if (ClassName
->Length
!= 0)
1022 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1023 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1025 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1029 /* We need to make a local copy of the class name! The caller could
1030 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1031 We're protected by SEH, but the ranges that might be accessed were
1033 RtlCopyMemory(szBuf
,
1036 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1040 AtomName
= ClassName
->Buffer
;
1042 /* lookup the atom */
1043 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1046 if (NT_SUCCESS(Status
))
1052 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1054 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1058 SetLastNtError(Status
);
1064 ASSERT(IS_ATOM(ClassName
->Buffer
));
1065 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1073 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1074 IN HINSTANCE hInstance OPTIONAL
,
1075 IN PW32PROCESSINFO pi OPTIONAL
,
1076 OUT PWINDOWCLASS
*BaseClass OPTIONAL
,
1077 OUT PWINDOWCLASS
**Link OPTIONAL
)
1079 RTL_ATOM Atom
= (RTL_ATOM
)0;
1081 if (IntGetAtomFromStringOrAtom(ClassName
,
1083 BaseClass
!= NULL
&& Atom
!= (RTL_ATOM
)0)
1087 /* attempt to locate the class object */
1091 /* Step 1: try to find an exact match of locally registered classes */
1092 Class
= IntFindClass(Atom
,
1094 &pi
->LocalClassList
,
1101 /* Step 2: try to find any globally registered class. The hInstance
1102 is not relevant for global classes */
1103 Class
= IntFindClass(Atom
,
1105 &pi
->GlobalClassList
,
1112 /* Step 3: try to find a system class */
1113 Class
= IntFindClass(Atom
,
1115 &pi
->SystemClassList
,
1120 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1132 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1133 IN PUNICODE_STRING ClassName
,
1134 IN PUNICODE_STRING MenuName
,
1135 IN HANDLE hMenu
, /* FIXME */
1143 RTL_ATOM Ret
= (RTL_ATOM
)0;
1145 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1147 ti
= GetW32ThreadInfo();
1150 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1156 /* try to find a previously registered class */
1157 ClassAtom
= IntGetClassAtom(ClassName
,
1162 if (ClassAtom
!= (RTL_ATOM
)0)
1164 if (lpwcx
->style
& CS_GLOBALCLASS
)
1166 // global classes shall not have same names as system classes
1167 if (Class
->Global
|| Class
->System
)
1169 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1170 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1174 else if ( !Class
->Global
&& !Class
->System
)
1176 // local class already exists
1177 DPRINT("Class 0x%p does already exist!\n", ClassAtom
);
1178 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1183 Class
= IntCreateClass(lpwcx
,
1195 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1196 Class
->hMenu
= hMenu
;
1198 /* Register the class */
1200 List
= &pi
->SystemClassList
;
1201 else if (Class
->Global
)
1202 List
= &pi
->GlobalClassList
;
1204 List
= &pi
->LocalClassList
;
1206 Class
->Next
= *List
;
1207 (void)InterlockedExchangePointer(List
,
1217 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1218 IN HINSTANCE hInstance
)
1225 pi
= GetW32ProcessInfo();
1228 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1232 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1233 ClassAtom
= IntGetClassAtom(ClassName
,
1238 if (ClassAtom
== (RTL_ATOM
)0)
1243 ASSERT(Class
!= NULL
);
1245 if (Class
->Windows
!= 0 ||
1246 Class
->Clone
!= NULL
)
1248 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1252 /* must be a base class! */
1253 ASSERT(Class
->Base
== Class
);
1255 /* unlink the class */
1256 *Link
= Class
->Next
;
1258 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->Atom
)))
1260 /* finally free the resources */
1261 IntDestroyClass(Class
);
1268 UserGetClassName(IN PWINDOWCLASS Class
,
1269 IN OUT PUNICODE_STRING ClassName
,
1272 NTSTATUS Status
= STATUS_SUCCESS
;
1273 WCHAR szStaticTemp
[32];
1274 PWSTR szTemp
= NULL
;
1275 ULONG BufLen
= sizeof(szStaticTemp
);
1278 /* Note: Accessing the buffer in ClassName may raise an exception! */
1284 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1285 UNICODE_STRING UnicodeClassName
;
1287 /* limit the size of the static buffer on the stack to the
1288 size of the buffer provided by the caller */
1289 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1291 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1294 /* find out how big the buffer needs to be */
1295 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1301 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1303 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1305 /* the buffer required exceeds the ansi buffer provided,
1306 pretend like we're using the ansi buffer and limit the
1307 size to the buffer size provided */
1308 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1311 /* allocate a temporary buffer that can hold the unicode class name */
1312 szTemp
= ExAllocatePool(PagedPool
,
1316 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1320 /* query the class name */
1321 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1329 szTemp
= szStaticTemp
;
1331 if (NT_SUCCESS(Status
))
1333 /* convert the atom name to ansi */
1335 RtlInitUnicodeString(&UnicodeClassName
,
1338 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1341 if (!NT_SUCCESS(Status
))
1343 SetLastNtError(Status
);
1348 Ret
= BufLen
/ sizeof(WCHAR
);
1352 BufLen
= ClassName
->MaximumLength
;
1354 /* query the atom name */
1355 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1362 if (!NT_SUCCESS(Status
))
1364 SetLastNtError(Status
);
1368 Ret
= BufLen
/ sizeof(WCHAR
);
1373 SetLastNtError(_SEH_GetExceptionCode());
1377 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1386 UserGetClassLongPtr(IN PWINDOWCLASS Class
,
1396 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1397 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1399 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1403 Data
= (PULONG_PTR
)((ULONG_PTR
)Class
+ Class
->ClassExtraDataOffset
+ Index
);
1405 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1406 certain architectures, maybe using RtlCopyMemory is a
1407 better choice for those architectures! */
1413 case GCL_CBWNDEXTRA
:
1414 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1417 case GCL_CBCLSEXTRA
:
1418 Ret
= (ULONG_PTR
)Class
->ClsExtra
;
1421 case GCLP_HBRBACKGROUND
:
1422 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1426 /* FIXME - get handle from pointer to CURSOR object */
1427 Ret
= (ULONG_PTR
)Class
->hCursor
;
1431 /* FIXME - get handle from pointer to ICON object */
1432 Ret
= (ULONG_PTR
)Class
->hIcon
;
1436 /* FIXME - get handle from pointer to ICON object */
1437 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1441 Ret
= (ULONG_PTR
)Class
->hInstance
;
1445 /* NOTE: Returns pointer in kernel heap! */
1447 Ret
= (ULONG_PTR
)Class
->AnsiMenuName
;
1449 Ret
= (ULONG_PTR
)Class
->MenuName
;
1453 Ret
= (ULONG_PTR
)Class
->Style
;
1457 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
,
1458 GetW32ProcessInfo(),
1464 Ret
= (ULONG_PTR
)Class
->Atom
;
1468 SetLastWin32Error(ERROR_INVALID_INDEX
);
1476 IntSetClassMenuName(IN PWINDOWCLASS Class
,
1477 IN PUNICODE_STRING MenuName
)
1481 /* change the base class first */
1482 Class
= Class
->Base
;
1484 if (MenuName
->Length
!= 0)
1486 ANSI_STRING AnsiString
;
1489 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1491 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1492 AnsiString
.MaximumLength
);
1493 if (strBufW
!= NULL
)
1499 /* copy the unicode string */
1500 RtlCopyMemory(strBufW
,
1503 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1505 /* create an ansi copy of the string */
1506 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1507 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1510 if (!NT_SUCCESS(Status
))
1512 SetLastNtError(Status
);
1520 SetLastNtError(_SEH_GetExceptionCode());
1526 /* update the base class */
1527 IntFreeClassMenuName(Class
);
1528 Class
->MenuName
= strBufW
;
1529 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1531 /* update the clones */
1532 Class
= Class
->Clone
;
1533 while (Class
!= NULL
)
1535 Class
->MenuName
= strBufW
;
1536 Class
->AnsiMenuName
= AnsiString
.Buffer
;
1538 Class
= Class
->Next
;
1543 DPRINT1("Failed to copy class menu name!\n");
1544 UserHeapFree(strBufW
);
1548 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1552 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1554 /* update the base class */
1555 IntFreeClassMenuName(Class
);
1556 Class
->MenuName
= MenuName
->Buffer
;
1557 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1559 /* update the clones */
1560 Class
= Class
->Clone
;
1561 while (Class
!= NULL
)
1563 Class
->MenuName
= MenuName
->Buffer
;
1564 Class
->AnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1566 Class
= Class
->Next
;
1576 UserSetClassLongPtr(IN PWINDOWCLASS Class
,
1578 IN ULONG_PTR NewLong
,
1583 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1585 /* change the information in the base class first, then update the clones */
1586 Class
= Class
->Base
;
1592 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1593 Index
+ sizeof(ULONG_PTR
) > Class
->ClsExtra
)
1595 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1599 Data
= (PULONG_PTR
)((ULONG_PTR
)Class
+ Class
->ClassExtraDataOffset
+ Index
);
1601 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1602 certain architectures, maybe using RtlCopyMemory is a
1603 better choice for those architectures! */
1607 /* update the clones */
1608 Class
= Class
->Clone
;
1609 while (Class
!= NULL
)
1611 *(PULONG_PTR
)((ULONG_PTR
)Class
+ Class
->ClassExtraDataOffset
+ Index
) = NewLong
;
1612 Class
= Class
->Next
;
1620 case GCL_CBWNDEXTRA
:
1621 Ret
= (ULONG_PTR
)Class
->WndExtra
;
1622 Class
->WndExtra
= (INT
)NewLong
;
1624 /* update the clones */
1625 Class
= Class
->Clone
;
1626 while (Class
!= NULL
)
1628 Class
->WndExtra
= (INT
)NewLong
;
1629 Class
= Class
->Next
;
1634 case GCL_CBCLSEXTRA
:
1635 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1638 case GCLP_HBRBACKGROUND
:
1639 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1640 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1642 /* update the clones */
1643 Class
= Class
->Clone
;
1644 while (Class
!= NULL
)
1646 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1647 Class
= Class
->Next
;
1652 /* FIXME - get handle from pointer to CURSOR object */
1653 Ret
= (ULONG_PTR
)Class
->hCursor
;
1654 Class
->hCursor
= (HANDLE
)NewLong
;
1656 /* update the clones */
1657 Class
= Class
->Clone
;
1658 while (Class
!= NULL
)
1660 Class
->hCursor
= (HANDLE
)NewLong
;
1661 Class
= Class
->Next
;
1666 /* FIXME - get handle from pointer to ICON object */
1667 Ret
= (ULONG_PTR
)Class
->hIcon
;
1668 Class
->hIcon
= (HANDLE
)NewLong
;
1670 /* update the clones */
1671 Class
= Class
->Clone
;
1672 while (Class
!= NULL
)
1674 Class
->hIcon
= (HANDLE
)NewLong
;
1675 Class
= Class
->Next
;
1680 /* FIXME - get handle from pointer to ICON object */
1681 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1682 Class
->hIconSm
= (HANDLE
)NewLong
;
1684 /* update the clones */
1685 Class
= Class
->Clone
;
1686 while (Class
!= NULL
)
1688 Class
->hIconSm
= (HANDLE
)NewLong
;
1689 Class
= Class
->Next
;
1694 Ret
= (ULONG_PTR
)Class
->hInstance
;
1695 Class
->hInstance
= (HINSTANCE
)NewLong
;
1697 /* update the clones */
1698 Class
= Class
->Clone
;
1699 while (Class
!= NULL
)
1701 Class
->hInstance
= (HINSTANCE
)NewLong
;
1702 Class
= Class
->Next
;
1708 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1710 if (!IntSetClassMenuName(Class
,
1713 DPRINT("Setting the class menu name failed!\n");
1716 /* FIXME - really return NULL? Wine does so... */
1721 Ret
= (ULONG_PTR
)Class
->Style
;
1722 Class
->Style
= (UINT
)NewLong
;
1724 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1725 move the class to the appropriate list? For now, we save
1726 the original value in Class->Global, so we can always
1727 locate the appropriate list */
1729 /* update the clones */
1730 Class
= Class
->Clone
;
1731 while (Class
!= NULL
)
1733 Class
->Style
= (UINT
)NewLong
;
1734 Class
= Class
->Next
;
1739 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1746 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1748 Ret
= (ULONG_PTR
)Class
->Atom
;
1749 if (!IntSetClassAtom(Class
,
1758 SetLastWin32Error(ERROR_INVALID_INDEX
);
1766 UserGetClassInfo(IN PWINDOWCLASS Class
,
1767 OUT PWNDCLASSEXW lpwcx
,
1769 HINSTANCE hInstance
)
1771 lpwcx
->style
= Class
->Style
;
1773 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
,
1774 GetW32ProcessInfo(),
1778 lpwcx
->cbClsExtra
= Class
->ClsExtra
;
1779 lpwcx
->cbWndExtra
= Class
->WndExtra
;
1780 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1781 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1782 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1785 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->AnsiMenuName
;
1787 lpwcx
->lpszMenuName
= Class
->MenuName
;
1790 lpwcx
->hInstance
= hInstance
;
1791 else if (Class
->Global
)
1792 lpwcx
->hInstance
= NULL
;
1794 lpwcx
->hInstance
= Class
->hInstance
;
1796 lpwcx
->lpszClassName
= (LPCWSTR
)((ULONG_PTR
)Class
->Atom
); /* FIXME - return the string? */
1798 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1803 /* SYSCALLS *****************************************************************/
1807 NtUserRegisterClassEx(IN CONST WNDCLASSEXW
* lpwcx
,
1808 IN PUNICODE_STRING ClassName
,
1809 IN PUNICODE_STRING MenuName
,
1816 * Registers a new class with the window manager
1818 * lpwcx = Win32 extended window class structure
1819 * bUnicodeClass = Whether to send ANSI or unicode strings
1820 * to window procedures
1821 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1823 * Atom identifying the new class
1826 WNDCLASSEXW CapturedClassInfo
= {0};
1827 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1828 RTL_ATOM Ret
= (RTL_ATOM
)0;
1830 if (Flags
& ~REGISTERCLASS_ALL
)
1832 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1836 UserEnterExclusive();
1840 /* Probe the parameters and basic parameter checks */
1841 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
1843 goto InvalidParameter
;
1847 sizeof(WNDCLASSEXW
),
1849 RtlCopyMemory(&CapturedClassInfo
,
1851 sizeof(WNDCLASSEXW
));
1853 CapturedName
= ProbeForReadUnicodeString(ClassName
);
1854 CapturedMenuName
= ProbeForReadUnicodeString(MenuName
);
1856 if (CapturedName
.Length
& 1 || CapturedMenuName
.Length
& 1 ||
1857 CapturedClassInfo
.cbClsExtra
< 0 ||
1858 CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
1859 CapturedMenuName
.Length
+ sizeof(WINDOWCLASS
) < CapturedClassInfo
.cbClsExtra
||
1860 CapturedClassInfo
.cbWndExtra
< 0 ||
1861 CapturedClassInfo
.hInstance
== NULL
)
1863 goto InvalidParameter
;
1866 if (CapturedName
.Length
!= 0)
1868 ProbeForRead(CapturedName
.Buffer
,
1869 CapturedName
.Length
,
1874 if (!IS_ATOM(CapturedName
.Buffer
))
1876 goto InvalidParameter
;
1880 if (CapturedMenuName
.Length
!= 0)
1882 ProbeForRead(CapturedMenuName
.Buffer
,
1883 CapturedMenuName
.Length
,
1886 else if (CapturedMenuName
.Buffer
!= NULL
&&
1887 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
1890 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1894 /* Register the class */
1895 Ret
= UserRegisterClass(&CapturedClassInfo
,
1898 hMenu
, /* FIXME - pass pointer */
1905 SetLastNtError(_SEH_GetExceptionCode());
1917 NtUserGetClassLong(IN HWND hWnd
,
1921 PWINDOW_OBJECT Window
;
1924 if (Offset
!= GCLP_WNDPROC
)
1930 UserEnterExclusive();
1933 Window
= UserGetWindowObject(hWnd
);
1936 Ret
= UserGetClassLongPtr(Window
->Class
,
1940 if (Ret
!= 0 && Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Ret
))
1942 Ret
= (ULONG_PTR
)DesktopHeapAddressToUser(Window
->Class
->Desktop
,
1955 NtUserSetClassLong(HWND hWnd
,
1957 ULONG_PTR dwNewLong
,
1961 PWINDOW_OBJECT Window
;
1964 UserEnterExclusive();
1966 pi
= GetW32ProcessInfo();
1970 Window
= UserGetWindowObject(hWnd
);
1973 if (Window
->ti
->kpi
!= pi
)
1975 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1981 UNICODE_STRING Value
;
1983 /* probe the parameters */
1984 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
1986 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
1987 if (Value
.Length
& 1)
1989 goto InvalidParameter
;
1992 if (Value
.Length
!= 0)
1994 ProbeForRead(Value
.Buffer
,
2000 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2002 goto InvalidParameter
;
2004 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2007 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2012 dwNewLong
= (ULONG_PTR
)&Value
;
2015 Ret
= UserSetClassLongPtr(Window
->Class
,
2022 SetLastNtError(_SEH_GetExceptionCode());
2034 NtUserSetClassWord(DWORD Unknown0
,
2042 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2043 IN HINSTANCE hInstance
)
2045 UNICODE_STRING CapturedClassName
;
2048 UserEnterExclusive();
2052 /* probe the paramters */
2053 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2054 if (CapturedClassName
.Length
& 1)
2056 goto InvalidParameter
;
2059 if (CapturedClassName
.Length
!= 0)
2061 ProbeForRead(CapturedClassName
.Buffer
,
2062 CapturedClassName
.Length
,
2067 if (!IS_ATOM(CapturedClassName
.Buffer
))
2070 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2075 /* unregister the class */
2076 Ret
= UserUnregisterClass(&CapturedClassName
,
2081 SetLastNtError(_SEH_GetExceptionCode());
2090 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2093 HINSTANCE hInstance
,
2094 PUNICODE_STRING ClassName
,
2095 LPWNDCLASSEXW lpWndClassEx
,
2098 UNICODE_STRING CapturedClassName
;
2104 /* NOTE: need exclusive lock because getting the wndproc might require the
2105 creation of a call procedure handle */
2106 UserEnterExclusive();
2108 pi
= GetW32ProcessInfo();
2111 ERR("GetW32ProcessInfo() returned NULL!\n");
2116 /* probe the paramters */
2117 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2119 if (IS_ATOM(CapturedClassName
.Buffer
))
2120 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2122 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2124 if (CapturedClassName
.Length
& 1)
2126 goto InvalidParameter
;
2129 if (CapturedClassName
.Length
!= 0)
2131 ProbeForRead(CapturedClassName
.Buffer
,
2132 CapturedClassName
.Length
,
2137 if (!IS_ATOM(CapturedClassName
.Buffer
))
2139 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2140 goto InvalidParameter
;
2144 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2147 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2151 ProbeForWrite(lpWndClassEx
,
2152 sizeof(WNDCLASSEXW
),
2155 ClassAtom
= IntGetClassAtom(&CapturedClassName
,
2160 if (ClassAtom
!= (RTL_ATOM
)0)
2162 Ret
= UserGetClassInfo(Class
,
2169 lpWndClassEx
->lpszClassName
= CapturedClassName
.Buffer
;
2170 /* FIXME - handle Class->Desktop == NULL!!!!! */
2172 if (Class
->MenuName
!= NULL
&&
2173 !IS_INTRESOURCE(Class
->MenuName
))
2175 lpWndClassEx
->lpszMenuName
= DesktopHeapAddressToUser(Class
->Desktop
,
2177 (PVOID
)Class
->AnsiMenuName
:
2178 (PVOID
)Class
->MenuName
));
2181 /* Undocumented behavior! Return the class atom as a BOOL! */
2182 Ret
= (BOOL
)ClassAtom
;
2184 if (!(Class
->Global
|| Class
->System
) && hInstance
== NULL
)
2186 WARN("Tried to get information of a non-existing class\n");
2187 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2194 WARN("Tried to get information of a non-existing class\n");
2195 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2200 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2212 NtUserGetClassName (IN HWND hWnd
,
2213 OUT PUNICODE_STRING ClassName
,
2216 PWINDOW_OBJECT Window
;
2217 UNICODE_STRING CapturedClassName
;
2222 Window
= UserGetWindowObject(hWnd
);
2227 ProbeForWriteUnicodeString(ClassName
);
2228 CapturedClassName
= *ClassName
;
2230 /* get the class name */
2231 Ret
= UserGetClassName(Window
->Class
,
2237 /* update the Length field */
2238 ClassName
->Length
= CapturedClassName
.Length
;
2243 SetLastNtError(_SEH_GetExceptionCode());
2254 NtUserGetWOWClass(DWORD Unknown0
,