2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
8 * 06-06-2001 CSH Created
10 /* INCLUDES ******************************************************************/
20 REGISTER_SYSCLASS DefaultServerClasses
[] =
22 /* { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
23 CS_GLOBALCLASS|CS_DBLCLKS,
27 (HBRUSH)(COLOR_BACKGROUND+1),
31 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
32 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
33 NULL
, // Use User32 procs
40 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
41 CS_DBLCLKS
|CS_SAVEBITS
,
42 NULL
, // Use User32 procs
45 (HBRUSH
)(COLOR_MENU
+ 1),
50 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
51 NULL
, // Use User32 procs
58 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
60 NULL
, // Use User32 procs
69 NULL
, // Use User32 procs
83 { /* Function Ids to Class indexes. */
84 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
85 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
86 { FNID_MENU
, ICLS_MENU
},
87 { FNID_DESKTOP
, ICLS_DESKTOP
},
88 { FNID_SWITCH
, ICLS_SWITCH
},
89 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
90 { FNID_BUTTON
, ICLS_BUTTON
},
91 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
92 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
93 { FNID_DIALOG
, ICLS_DIALOG
},
94 { FNID_EDIT
, ICLS_EDIT
},
95 { FNID_LISTBOX
, ICLS_LISTBOX
},
96 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
97 { FNID_STATIC
, ICLS_STATIC
},
98 { FNID_IME
, ICLS_IME
},
99 { FNID_GHOST
, ICLS_GHOST
},
100 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
105 LookupFnIdToiCls(int FnId
, int *iCls
)
109 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
111 if (FnidToiCls
[i
].FnId
== FnId
)
113 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
121 /* WINDOWCLASS ***************************************************************/
124 IntFreeClassMenuName(IN OUT PCLS Class
)
126 /* free the menu name, if it was changed and allocated */
127 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
129 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
130 Class
->lpszClientUnicodeMenuName
= NULL
;
131 Class
->lpszClientAnsiMenuName
= NULL
;
136 IntDestroyClass(IN OUT PCLS Class
)
139 /* there shouldn't be any clones anymore */
140 ASSERT(Class
->cWndReferenceCount
== 0);
141 ASSERT(Class
->pclsClone
== NULL
);
143 if (Class
->pclsBase
== Class
)
145 PCALLPROCDATA CallProc
, NextCallProc
;
147 /* Destroy allocated callproc handles */
148 CallProc
= Class
->spcpdFirst
;
149 while (CallProc
!= NULL
)
151 NextCallProc
= CallProc
->spcpdNext
;
153 CallProc
->spcpdNext
= NULL
;
154 DestroyCallProc(NULL
,
157 CallProc
= NextCallProc
;
162 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
166 IntFreeClassMenuName(Class
);
169 pDesk
= Class
->rpdeskParent
;
170 Class
->rpdeskParent
= NULL
;
172 /* free the structure */
175 DesktopHeapFree(pDesk
, Class
);
184 /* clean all process classes. all process windows must cleaned first!! */
185 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
188 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
192 /* free all local classes */
193 Class
= pi
->pclsPrivateList
;
194 while (Class
!= NULL
)
196 pi
->pclsPrivateList
= Class
->pclsNext
;
198 ASSERT(Class
->pclsBase
== Class
);
199 IntDestroyClass(Class
);
201 Class
= pi
->pclsPrivateList
;
204 /* free all global classes */
205 Class
= pi
->pclsPublicList
;
206 while (Class
!= NULL
)
208 pi
->pclsPublicList
= Class
->pclsNext
;
210 ASSERT(Class
->pclsBase
== Class
);
211 IntDestroyClass(Class
);
213 Class
= pi
->pclsPublicList
;
219 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
226 if (ClassName
->Length
!= 0)
228 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
229 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
231 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
238 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
242 AtomName
= ClassName
->Buffer
;
244 Status
= RtlAddAtomToAtomTable(gAtomTable
,
248 if (!NT_SUCCESS(Status
))
250 SetLastNtError(Status
);
258 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
260 return RtlDeleteAtomFromAtomTable(gAtomTable
,
265 UserAddCallProcToClass(IN OUT PCLS Class
,
266 IN PCALLPROCDATA CallProc
)
270 ASSERT(CallProc
->spcpdNext
== NULL
);
272 BaseClass
= Class
->pclsBase
;
273 ASSERT(CallProc
->spcpdNext
== NULL
);
274 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
275 BaseClass
->spcpdFirst
= CallProc
;
277 /* Update all clones */
278 Class
= Class
->pclsClone
;
279 while (Class
!= NULL
)
281 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
282 Class
= Class
->pclsNext
;
287 IntSetClassAtom(IN OUT PCLS Class
,
288 IN PUNICODE_STRING ClassName
)
290 RTL_ATOM Atom
= (RTL_ATOM
)0;
292 /* update the base class first */
293 Class
= Class
->pclsBase
;
295 if (!IntRegisterClassAtom(ClassName
,
301 IntDeregisterClassAtom(Class
->atomClassName
);
303 Class
->atomClassName
= Atom
;
305 /* update the clones */
306 Class
= Class
->pclsClone
;
307 while (Class
!= NULL
)
309 Class
->atomClassName
= Atom
;
311 Class
= Class
->pclsNext
;
318 // Same as User32:IntGetClsWndProc.
321 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
324 WNDPROC gcpd
= NULL
, Ret
= NULL
;
326 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
328 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
330 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
333 Ret
= GETPFNCLIENTA(i
);
335 Ret
= GETPFNCLIENTW(i
);
340 Ret
= Class
->lpfnWndProc
;
342 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
346 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
347 Ret
= GETPFNCLIENTA(Class
->fnid
);
351 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
352 Ret
= GETPFNCLIENTW(Class
->fnid
);
356 if ( Ret
!= Class
->lpfnWndProc
||
357 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
360 gcpd
= (WNDPROC
)UserGetCPD( Class
,
361 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
364 return (gcpd
? gcpd
: Ret
);
370 IntSetClassWndProc(IN OUT PCLS Class
,
376 WNDPROC Ret
, chWndProc
;
378 Ret
= IntGetClassWndProc(Class
, Ansi
);
380 // If Server Side, downgrade to Client Side.
381 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
383 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
384 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
385 Class
->Unicode
= !Ansi
;
390 // Check if CallProc handle and retrieve previous call proc address and set.
391 if (IsCallProcHandle(WndProc
))
393 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
394 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
397 Class
->lpfnWndProc
= chWndProc
;
402 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
403 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
405 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
407 chWndProc
= GETPFNSERVER(i
);
410 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
412 chWndProc
= GETPFNSERVER(i
);
416 // If match, set/reset to Server Side and clear ansi.
419 Class
->lpfnWndProc
= chWndProc
;
420 Class
->Unicode
= TRUE
;
421 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
422 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
426 Class
->Unicode
= !Ansi
;
429 Class
->CSF_flags
|= CSF_ANSIPROC
;
431 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
434 /* update the clones */
435 chWndProc
= Class
->lpfnWndProc
;
437 Class
= Class
->pclsClone
;
438 while (Class
!= NULL
)
440 Class
->Unicode
= !Ansi
;
441 Class
->lpfnWndProc
= chWndProc
;
443 Class
= Class
->pclsNext
;
450 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
451 IN OUT PCLS
*ClassLink
,
457 ASSERT(Desktop
!= NULL
);
458 ASSERT(BaseClass
->pclsBase
== BaseClass
);
460 if (BaseClass
->rpdeskParent
== Desktop
)
462 /* it is most likely that a window is created on the same
463 desktop as the window class. */
468 if (BaseClass
->rpdeskParent
== NULL
)
470 ASSERT(BaseClass
->cWndReferenceCount
== 0);
471 ASSERT(BaseClass
->pclsClone
== NULL
);
473 /* Classes are also located in the shared heap when the class
474 was created before the thread attached to a desktop. As soon
475 as a window is created for such a class located on the shared
476 heap, the class is cloned into the desktop heap on which the
477 window is created. */
482 /* The user is asking for a class object on a different desktop,
484 Class
= BaseClass
->pclsClone
;
485 while (Class
!= NULL
)
487 if (Class
->rpdeskParent
== Desktop
)
489 ASSERT(Class
->pclsBase
== BaseClass
);
490 ASSERT(Class
->pclsClone
== NULL
);
494 Class
= Class
->pclsNext
;
500 /* The window is created on a different desktop, we need to
501 clone the class object to the desktop heap of the window! */
502 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
504 Class
= DesktopHeapAlloc(Desktop
,
508 /* simply clone the class */
512 DPRINT("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
514 /* update some pointers and link the class */
515 Class
->rpdeskParent
= Desktop
;
516 Class
->cWndReferenceCount
= 0;
518 if (BaseClass
->rpdeskParent
== NULL
)
520 /* we don't really need the base class on the shared
521 heap anymore, delete it so the only class left is
522 the clone we just created, which now serves as the
524 ASSERT(BaseClass
->pclsClone
== NULL
);
525 ASSERT(Class
->pclsClone
== NULL
);
526 Class
->pclsBase
= Class
;
527 Class
->pclsNext
= BaseClass
->pclsNext
;
529 /* replace the base class */
530 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
533 /* destroy the obsolete copy on the shared heap */
534 BaseClass
->pclsBase
= NULL
;
535 BaseClass
->pclsClone
= NULL
;
536 IntDestroyClass(BaseClass
);
540 /* link in the clone */
541 Class
->pclsClone
= NULL
;
542 Class
->pclsBase
= BaseClass
;
543 Class
->pclsNext
= BaseClass
->pclsClone
;
544 (void)InterlockedExchangePointer(&BaseClass
->pclsClone
,
550 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
557 IntReferenceClass(IN OUT PCLS BaseClass
,
558 IN OUT PCLS
*ClassLink
,
562 ASSERT(BaseClass
->pclsBase
== BaseClass
);
564 Class
= IntGetClassForDesktop(BaseClass
,
569 Class
->cWndReferenceCount
++;
577 IntMakeCloneBaseClass(IN OUT PCLS Class
,
578 IN OUT PCLS
*BaseClassLink
,
579 IN OUT PCLS
*CloneLink
)
581 PCLS Clone
, BaseClass
;
583 ASSERT(Class
->pclsBase
!= Class
);
584 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
585 ASSERT(Class
->rpdeskParent
!= NULL
);
586 ASSERT(Class
->cWndReferenceCount
!= 0);
587 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
588 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
590 /* unlink the clone */
591 *CloneLink
= Class
->pclsNext
;
592 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
594 BaseClass
= Class
->pclsBase
;
596 /* update the class information to make it a base class */
597 Class
->pclsBase
= Class
;
598 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
600 /* update all clones */
601 Clone
= Class
->pclsClone
;
602 while (Clone
!= NULL
)
604 ASSERT(Clone
->pclsClone
== NULL
);
605 Clone
->pclsBase
= Class
;
607 Clone
= Clone
->pclsNext
;
610 /* link in the new base class */
611 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
617 IntDereferenceClass(IN OUT PCLS Class
,
618 IN PDESKTOPINFO Desktop
,
621 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
623 BaseClass
= Class
->pclsBase
;
625 if (--Class
->cWndReferenceCount
<= 0)
627 if (BaseClass
== Class
)
629 ASSERT(Class
->pclsBase
== Class
);
631 DPRINT("IntDereferenceClass 0x%x\n", Class
);
632 /* check if there are clones of the class on other desktops,
633 link the first clone in if possible. If there are no clones
634 then leave the class on the desktop heap. It will get moved
635 to the shared heap when the thread detaches. */
636 if (BaseClass
->pclsClone
!= NULL
)
638 if (BaseClass
->Global
)
639 PrevLink
= &pi
->pclsPublicList
;
641 PrevLink
= &pi
->pclsPrivateList
;
643 CurrentClass
= *PrevLink
;
644 while (CurrentClass
!= BaseClass
)
646 ASSERT(CurrentClass
!= NULL
);
648 PrevLink
= &CurrentClass
->pclsNext
;
649 CurrentClass
= CurrentClass
->pclsNext
;
652 ASSERT(*PrevLink
== BaseClass
);
654 /* make the first clone become the new base class */
655 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
657 &BaseClass
->pclsClone
);
659 /* destroy the class, there's still another clone of the class
660 that now serves as a base class. Make sure we don't destruct
661 resources shared by all classes (Base = NULL)! */
662 BaseClass
->pclsBase
= NULL
;
663 BaseClass
->pclsClone
= NULL
;
664 IntDestroyClass(BaseClass
);
669 DPRINT("IntDereferenceClass1 0x%x\n", Class
);
671 /* locate the cloned class and unlink it */
672 PrevLink
= &BaseClass
->pclsClone
;
673 CurrentClass
= BaseClass
->pclsClone
;
674 while (CurrentClass
!= Class
)
676 ASSERT(CurrentClass
!= NULL
);
678 PrevLink
= &CurrentClass
->pclsNext
;
679 CurrentClass
= CurrentClass
->pclsNext
;
682 ASSERT(CurrentClass
== Class
);
684 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
687 ASSERT(Class
->pclsBase
== BaseClass
);
688 ASSERT(Class
->pclsClone
== NULL
);
690 /* the class was just a clone, we don't need it anymore */
691 IntDestroyClass(Class
);
697 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
698 IN OUT PCLS
**ClassLinkPtr
)
703 ASSERT(Class
->pclsBase
== Class
);
704 ASSERT(Class
->rpdeskParent
!= NULL
);
705 ASSERT(Class
->cWndReferenceCount
== 0);
706 ASSERT(Class
->pclsClone
== NULL
);
708 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
710 /* allocate the new base class on the shared heap */
711 NewClass
= UserHeapAlloc(ClassSize
);
712 if (NewClass
!= NULL
)
714 RtlCopyMemory(NewClass
,
718 NewClass
->rpdeskParent
= NULL
;
719 NewClass
->pclsBase
= NewClass
;
721 /* replace the class in the list */
722 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
724 *ClassLinkPtr
= &NewClass
->pclsNext
;
726 /* free the obsolete class on the desktop heap */
727 Class
->pclsBase
= NULL
;
728 IntDestroyClass(Class
);
736 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
737 IN OUT PCLS
*ClassList
,
738 IN BOOL FreeOnFailure
,
741 PCLS Class
, NextClass
, *Link
;
743 /* NOTE: We only need to check base classes! When classes are no longer needed
744 on a desktop, the clones will be freed automatically as soon as possible.
745 However, we need to move base classes to the shared heap, as soon as
746 the last desktop heap where a class is allocated on is about to be destroyed.
747 If we didn't move the class to the shared heap, the class would become
750 ASSERT(Desktop
!= NULL
);
754 while (Class
!= NULL
)
756 NextClass
= Class
->pclsNext
;
758 ASSERT(Class
->pclsBase
== Class
);
760 if (Class
->rpdeskParent
== Desktop
&&
761 Class
->cWndReferenceCount
== 0)
763 /* there shouldn't be any clones around anymore! */
764 ASSERT(Class
->pclsClone
== NULL
);
766 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
767 /* FIXME - We could move the class to another desktop heap if there's still desktops
768 mapped into the process... */
770 /* move the class to the shared heap */
771 if (IntMoveClassToSharedHeap(Class
,
774 ASSERT(*Link
== NextClass
);
778 ASSERT(NextClass
== Class
->pclsNext
);
782 /* unlink the base class */
783 (void)InterlockedExchangePointer((PVOID
*)Link
,
786 /* we can free the old base class now */
787 Class
->pclsBase
= NULL
;
788 IntDestroyClass(Class
);
792 Link
= &Class
->pclsNext
;
798 Link
= &Class
->pclsNext
;
805 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
806 IN BOOL FreeOnFailure
)
811 pi
= GetW32ProcessInfo();
813 /* check all local classes */
814 IntCheckDesktopClasses(Desktop
,
815 &pi
->pclsPrivateList
,
819 /* check all global classes */
820 IntCheckDesktopClasses(Desktop
,
826 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
827 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
835 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
836 IN PUNICODE_STRING ClassName
,
837 IN PUNICODE_STRING MenuName
,
847 PWSTR pszMenuName
= NULL
;
848 NTSTATUS Status
= STATUS_SUCCESS
;
850 DPRINT("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
851 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
853 if (!IntRegisterClassAtom(ClassName
,
856 DPRINT1("Failed to register class atom!\n");
860 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
861 if (MenuName
->Length
!= 0)
863 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
864 RtlUnicodeStringToAnsiSize(MenuName
));
865 if (pszMenuName
== NULL
)
871 Class
= DesktopHeapAlloc(Desktop
,
876 /* FIXME - the class was created before being connected
877 to a desktop. It is possible for the desktop window,
878 but should it be allowed for any other case? */
879 Class
= UserHeapAlloc(ClassSize
);
886 RtlZeroMemory(Class
, ClassSize
);
888 Class
->rpdeskParent
= Desktop
;
889 Class
->pclsBase
= Class
;
890 Class
->atomClassName
= Atom
;
892 Class
->CSF_flags
= dwFlags
;
894 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
896 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
901 PWSTR pszMenuNameBuffer
= pszMenuName
;
903 /* need to protect with SEH since accessing the WNDCLASSEX structure
904 and string buffers might raise an exception! We don't want to
906 // What?! If the user interface was written correctly this would not be an issue!
907 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
908 Class
->style
= lpwcx
->style
;
909 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
910 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
911 Class
->hModule
= lpwcx
->hInstance
;
912 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
913 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
914 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
915 Class
->hbrBackground
= lpwcx
->hbrBackground
;
917 /* make a copy of the string */
918 if (pszMenuNameBuffer
!= NULL
)
920 Class
->MenuNameIsString
= TRUE
;
922 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
923 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
926 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
928 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
931 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
933 /* save an ansi copy of the string */
934 if (pszMenuNameBuffer
!= NULL
)
936 ANSI_STRING AnsiString
;
938 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
939 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
940 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
941 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
944 if (!NT_SUCCESS(Status
))
946 DPRINT1("Failed to convert unicode menu name to ansi!\n");
948 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
953 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
955 /* Save kernel use menu name and ansi class name */
956 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
957 //Class->lpszAnsiClassName = Fixme!
959 /* Server Side overrides class calling type (A/W)!
960 User32 whine test_builtinproc: "deftest"
961 built-in winproc - window A/W type automatically detected */
962 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
966 /* Due to the wine class "deftest" and most likely no FNID to reference
967 from, sort through the Server Side list and compare proc addresses
968 for match. This method will be used in related code.
970 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
971 { // Open Ansi or Unicode, just match, set and break.
972 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
974 WndProc
= GETPFNSERVER(i
);
977 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
979 WndProc
= GETPFNSERVER(i
);
984 { // If a hit, we are Server Side so set the right flags and proc.
985 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
986 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
987 Class
->lpfnWndProc
= WndProc
;
991 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
992 Class
->Unicode
= TRUE
;
994 if (Class
->style
& CS_GLOBALCLASS
)
995 Class
->Global
= TRUE
;
997 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
999 Status
= _SEH2_GetExceptionCode();
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT1("Failed creating the class: 0x%x\n", Status
);
1007 SetLastNtError(Status
);
1009 if (pszMenuName
!= NULL
)
1010 UserHeapFree(pszMenuName
);
1012 DesktopHeapFree(Desktop
,
1016 IntDeregisterClassAtom(Atom
);
1022 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1024 if (pszMenuName
!= NULL
)
1025 UserHeapFree(pszMenuName
);
1027 IntDeregisterClassAtom(Atom
);
1029 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1036 IntFindClass(IN RTL_ATOM Atom
,
1037 IN HINSTANCE hInstance
,
1039 OUT PCLS
**Link OPTIONAL
)
1041 PCLS Class
, *PrevLink
= ClassList
;
1044 while (Class
!= NULL
)
1046 if (Class
->atomClassName
== Atom
&&
1047 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1048 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1050 ASSERT(Class
->pclsBase
== Class
);
1057 PrevLink
= &Class
->pclsNext
;
1058 Class
= Class
->pclsNext
;
1065 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1070 if (ClassName
->Length
!= 0)
1076 /* NOTE: Caller has to protect the call with SEH! */
1078 if (ClassName
->Length
!= 0)
1080 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1081 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1083 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1087 /* We need to make a local copy of the class name! The caller could
1088 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1089 We're protected by SEH, but the ranges that might be accessed were
1091 RtlCopyMemory(szBuf
,
1094 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1098 AtomName
= ClassName
->Buffer
;
1100 /* lookup the atom */
1101 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1104 if (NT_SUCCESS(Status
))
1110 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1112 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1116 SetLastNtError(Status
);
1122 ASSERT(IS_ATOM(ClassName
->Buffer
));
1123 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1131 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1132 IN HINSTANCE hInstance OPTIONAL
,
1133 IN PPROCESSINFO pi OPTIONAL
,
1134 OUT PCLS
*BaseClass OPTIONAL
,
1135 OUT PCLS
**Link OPTIONAL
)
1137 RTL_ATOM Atom
= (RTL_ATOM
)0;
1139 ASSERT(BaseClass
!= NULL
);
1141 if (IntGetAtomFromStringOrAtom(ClassName
,
1143 Atom
!= (RTL_ATOM
)0)
1147 /* attempt to locate the class object */
1151 /* Step 1: try to find an exact match of locally registered classes */
1152 Class
= IntFindClass(Atom
,
1154 &pi
->pclsPrivateList
,
1157 { DPRINT("Step 1: 0x%x\n",Class
);
1161 /* Step 2: try to find any globally registered class. The hInstance
1162 is not relevant for global classes */
1163 Class
= IntFindClass(Atom
,
1165 &pi
->pclsPublicList
,
1168 { DPRINT("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1172 /* Step 3: try to find any local class registered by user32 */
1173 Class
= IntFindClass(Atom
,
1175 &pi
->pclsPrivateList
,
1178 { DPRINT("Step 3: 0x%x\n",Class
);
1182 /* Step 4: try to find any global class registered by user32 */
1183 Class
= IntFindClass(Atom
,
1185 &pi
->pclsPublicList
,
1189 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1191 }else{DPRINT("Step 4: 0x%x\n",Class
);}
1201 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1202 IN PUNICODE_STRING ClassName
,
1203 IN PUNICODE_STRING MenuName
,
1211 RTL_ATOM Ret
= (RTL_ATOM
)0;
1213 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1215 pti
= GetW32ThreadInfo();
1219 // Need only to test for two conditions not four....... Fix more whine tests....
1220 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1221 ClassAtom
!= (RTL_ATOM
)0 &&
1222 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1224 Class
= IntFindClass( ClassAtom
,
1226 &pi
->pclsPrivateList
,
1229 if (Class
!= NULL
&& !Class
->Global
)
1231 // local class already exists
1232 DPRINT1("Local Class 0x%p does already exist!\n", ClassAtom
);
1233 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1237 if (lpwcx
->style
& CS_GLOBALCLASS
)
1239 Class
= IntFindClass( ClassAtom
,
1241 &pi
->pclsPublicList
,
1244 if (Class
!= NULL
&& Class
->Global
)
1246 DPRINT1("Global Class 0x%p does already exist!\n", ClassAtom
);
1247 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1253 Class
= IntCreateClass(lpwcx
,
1265 /* Register the class */
1267 List
= &pi
->pclsPublicList
;
1269 List
= &pi
->pclsPrivateList
;
1271 Class
->pclsNext
= *List
;
1272 (void)InterlockedExchangePointer((PVOID
*)List
,
1275 Ret
= Class
->atomClassName
;
1279 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1286 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1287 IN HINSTANCE hInstance
,
1288 OUT PCLSMENUNAME pClassMenuName
)
1295 pi
= GetW32ProcessInfo();
1297 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1299 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1300 ClassAtom
= IntGetClassAtom(ClassName
,
1305 if (ClassAtom
== (RTL_ATOM
)0)
1307 DPRINT1("UserUnregisterClass: No Class found.\n");
1311 ASSERT(Class
!= NULL
);
1313 if (Class
->cWndReferenceCount
!= 0 ||
1314 Class
->pclsClone
!= NULL
)
1316 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1317 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1321 /* must be a base class! */
1322 ASSERT(Class
->pclsBase
== Class
);
1324 /* unlink the class */
1325 *Link
= Class
->pclsNext
;
1327 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1329 DPRINT("Class 0x%x\n", Class
);
1330 DPRINT("UserUnregisterClass: Good Exit!\n");
1331 /* finally free the resources */
1332 IntDestroyClass(Class
);
1335 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1340 UserGetClassName(IN PCLS Class
,
1341 IN OUT PUNICODE_STRING ClassName
,
1344 NTSTATUS Status
= STATUS_SUCCESS
;
1345 WCHAR szStaticTemp
[32];
1346 PWSTR szTemp
= NULL
;
1347 ULONG BufLen
= sizeof(szStaticTemp
);
1350 /* Note: Accessing the buffer in ClassName may raise an exception! */
1356 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1357 UNICODE_STRING UnicodeClassName
;
1359 /* limit the size of the static buffer on the stack to the
1360 size of the buffer provided by the caller */
1361 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1363 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1366 /* find out how big the buffer needs to be */
1367 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1368 Class
->atomClassName
,
1373 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1375 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1377 /* the buffer required exceeds the ansi buffer provided,
1378 pretend like we're using the ansi buffer and limit the
1379 size to the buffer size provided */
1380 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1383 /* allocate a temporary buffer that can hold the unicode class name */
1384 szTemp
= ExAllocatePool(PagedPool
,
1388 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1392 /* query the class name */
1393 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1394 Class
->atomClassName
,
1401 szTemp
= szStaticTemp
;
1403 if (NT_SUCCESS(Status
))
1405 /* convert the atom name to ansi */
1407 RtlInitUnicodeString(&UnicodeClassName
,
1410 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1413 if (!NT_SUCCESS(Status
))
1415 SetLastNtError(Status
);
1420 Ret
= BufLen
/ sizeof(WCHAR
);
1424 BufLen
= ClassName
->MaximumLength
;
1426 /* query the atom name */
1427 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1428 Class
->atomClassName
,
1434 if (!NT_SUCCESS(Status
))
1436 SetLastNtError(Status
);
1440 Ret
= BufLen
/ sizeof(WCHAR
);
1443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1445 SetLastNtError(_SEH2_GetExceptionCode());
1449 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1458 UserGetClassLongPtr(IN PCLS Class
,
1468 TRACE("GetClassLong(%d)\n", Index
);
1469 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1470 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1472 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1476 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1478 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1479 certain architectures, maybe using RtlCopyMemory is a
1480 better choice for those architectures! */
1482 TRACE("Result: %x\n", Ret
);
1488 case GCL_CBWNDEXTRA
:
1489 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1492 case GCL_CBCLSEXTRA
:
1493 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
1496 case GCLP_HBRBACKGROUND
:
1497 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1501 /* FIXME - get handle from pointer to CURSOR object */
1502 Ret
= (ULONG_PTR
)Class
->hCursor
;
1506 /* FIXME - get handle from pointer to ICON object */
1507 Ret
= (ULONG_PTR
)Class
->hIcon
;
1511 /* FIXME - get handle from pointer to ICON object */
1512 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1516 Ret
= (ULONG_PTR
)Class
->hModule
;
1520 /* NOTE: Returns pointer in kernel heap! */
1522 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
1524 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
1528 Ret
= (ULONG_PTR
)Class
->style
;
1532 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
, Ansi
);
1536 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1540 SetLastWin32Error(ERROR_INVALID_INDEX
);
1548 IntSetClassMenuName(IN PCLS Class
,
1549 IN PUNICODE_STRING MenuName
)
1553 /* change the base class first */
1554 Class
= Class
->pclsBase
;
1556 if (MenuName
->Length
!= 0)
1558 ANSI_STRING AnsiString
;
1561 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1563 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1564 AnsiString
.MaximumLength
);
1565 if (strBufW
!= NULL
)
1571 /* copy the unicode string */
1572 RtlCopyMemory(strBufW
,
1575 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1577 /* create an ansi copy of the string */
1578 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1579 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1582 if (!NT_SUCCESS(Status
))
1584 SetLastNtError(Status
);
1590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1592 SetLastNtError(_SEH2_GetExceptionCode());
1598 /* update the base class */
1599 IntFreeClassMenuName(Class
);
1600 Class
->lpszClientUnicodeMenuName
= strBufW
;
1601 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1602 Class
->MenuNameIsString
= TRUE
;
1604 /* update the clones */
1605 Class
= Class
->pclsClone
;
1606 while (Class
!= NULL
)
1608 Class
->lpszClientUnicodeMenuName
= strBufW
;
1609 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1610 Class
->MenuNameIsString
= TRUE
;
1612 Class
= Class
->pclsNext
;
1617 DPRINT1("Failed to copy class menu name!\n");
1618 UserHeapFree(strBufW
);
1622 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1626 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1628 /* update the base class */
1629 IntFreeClassMenuName(Class
);
1630 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1631 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1632 Class
->MenuNameIsString
= FALSE
;
1634 /* update the clones */
1635 Class
= Class
->pclsClone
;
1636 while (Class
!= NULL
)
1638 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1639 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1640 Class
->MenuNameIsString
= FALSE
;
1642 Class
= Class
->pclsNext
;
1652 UserSetClassLongPtr(IN PCLS Class
,
1654 IN ULONG_PTR NewLong
,
1659 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1661 /* change the information in the base class first, then update the clones */
1662 Class
= Class
->pclsBase
;
1668 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1670 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1671 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1673 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1677 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1679 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1680 certain architectures, maybe using RtlCopyMemory is a
1681 better choice for those architectures! */
1685 /* update the clones */
1686 Class
= Class
->pclsClone
;
1687 while (Class
!= NULL
)
1689 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1690 Class
= Class
->pclsNext
;
1698 case GCL_CBWNDEXTRA
:
1699 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1700 Class
->cbwndExtra
= (INT
)NewLong
;
1702 /* update the clones */
1703 Class
= Class
->pclsClone
;
1704 while (Class
!= NULL
)
1706 Class
->cbwndExtra
= (INT
)NewLong
;
1707 Class
= Class
->pclsNext
;
1712 case GCL_CBCLSEXTRA
:
1713 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1716 case GCLP_HBRBACKGROUND
:
1717 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1718 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1720 /* update the clones */
1721 Class
= Class
->pclsClone
;
1722 while (Class
!= NULL
)
1724 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1725 Class
= Class
->pclsNext
;
1730 /* FIXME - get handle from pointer to CURSOR object */
1731 Ret
= (ULONG_PTR
)Class
->hCursor
;
1732 Class
->hCursor
= (HANDLE
)NewLong
;
1734 /* update the clones */
1735 Class
= Class
->pclsClone
;
1736 while (Class
!= NULL
)
1738 Class
->hCursor
= (HANDLE
)NewLong
;
1739 Class
= Class
->pclsNext
;
1744 /* FIXME - get handle from pointer to ICON object */
1745 Ret
= (ULONG_PTR
)Class
->hIcon
;
1746 Class
->hIcon
= (HANDLE
)NewLong
;
1748 /* update the clones */
1749 Class
= Class
->pclsClone
;
1750 while (Class
!= NULL
)
1752 Class
->hIcon
= (HANDLE
)NewLong
;
1753 Class
= Class
->pclsNext
;
1758 /* FIXME - get handle from pointer to ICON object */
1759 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1760 Class
->hIconSm
= (HANDLE
)NewLong
;
1762 /* update the clones */
1763 Class
= Class
->pclsClone
;
1764 while (Class
!= NULL
)
1766 Class
->hIconSm
= (HANDLE
)NewLong
;
1767 Class
= Class
->pclsNext
;
1772 Ret
= (ULONG_PTR
)Class
->hModule
;
1773 Class
->hModule
= (HINSTANCE
)NewLong
;
1775 /* update the clones */
1776 Class
= Class
->pclsClone
;
1777 while (Class
!= NULL
)
1779 Class
->hModule
= (HINSTANCE
)NewLong
;
1780 Class
= Class
->pclsNext
;
1786 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1788 if (!IntSetClassMenuName(Class
,
1791 DPRINT1("Setting the class menu name failed!\n");
1794 /* FIXME - really return NULL? Wine does so... */
1799 Ret
= (ULONG_PTR
)Class
->style
;
1800 Class
->style
= (UINT
)NewLong
;
1802 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1803 move the class to the appropriate list? For now, we save
1804 the original value in Class->Global, so we can always
1805 locate the appropriate list */
1807 /* update the clones */
1808 Class
= Class
->pclsClone
;
1809 while (Class
!= NULL
)
1811 Class
->style
= (UINT
)NewLong
;
1812 Class
= Class
->pclsNext
;
1817 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1824 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1826 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1827 if (!IntSetClassAtom(Class
,
1836 SetLastWin32Error(ERROR_INVALID_INDEX
);
1844 UserGetClassInfo(IN PCLS Class
,
1845 OUT PWNDCLASSEXW lpwcx
,
1847 HINSTANCE hInstance
)
1851 if (!Class
) return FALSE
;
1853 lpwcx
->style
= Class
->style
;
1855 // If fnId is set, clear the global bit. See wine class test check_style.
1857 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1859 pi
= GetW32ProcessInfo();
1861 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1863 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1864 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1865 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1866 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1867 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1869 /* Copy non-string to user first. */
1871 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1873 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1875 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1876 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1877 lpszClientXxxMenuName should already be mapped to user space.
1879 /* Copy string ptr to user. */
1880 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1881 Class
->MenuNameIsString
)
1883 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1884 (PVOID
)Class
->lpszClientAnsiMenuName
:
1885 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1888 if (hInstance
== hModClient
)
1889 lpwcx
->hInstance
= NULL
;
1891 lpwcx
->hInstance
= hInstance
;
1893 /* FIXME - return the string? Okay! This is performed in User32!*/
1894 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1896 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1906 UserRegisterSystemClasses(VOID
)
1909 UNICODE_STRING ClassName
, MenuName
;
1910 PPROCESSINFO ppi
= GetW32ProcessInfo();
1916 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1919 if ( hModClient
== NULL
)
1922 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1923 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1925 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1927 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1929 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1933 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1934 ClassName
.Length
= 0;
1935 ClassName
.MaximumLength
= 0;
1938 wc
.cbSize
= sizeof(wc
);
1939 wc
.style
= DefaultServerClasses
[i
].Style
;
1941 Flags
|= CSF_SERVERSIDEPROC
;
1943 if (DefaultServerClasses
[i
].ProcW
)
1945 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1946 wc
.hInstance
= hModuleWin
;
1950 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1951 wc
.hInstance
= hModClient
;
1955 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1957 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1958 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1959 wc
.lpszMenuName
= NULL
;
1960 wc
.lpszClassName
= ClassName
.Buffer
;
1963 Class
= IntCreateClass( &wc
,
1966 DefaultServerClasses
[i
].fiId
,
1972 Class
->pclsNext
= ppi
->pclsPublicList
;
1973 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1976 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1980 WARN("!!! Registering system class failed!\n");
1984 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1988 /* SYSCALLS *****************************************************************/
1992 NtUserRegisterClassExWOW(
1994 PUNICODE_STRING ClassName
,
1995 PUNICODE_STRING ClsNVersion
,
1996 PCLSMENUNAME pClassMenuName
,
2002 * Registers a new class with the window manager
2004 * lpwcx = Win32 extended window class structure
2005 * bUnicodeClass = Whether to send ANSI or unicode strings
2006 * to window procedures
2008 * Atom identifying the new class
2011 WNDCLASSEXW CapturedClassInfo
= {0};
2012 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2013 RTL_ATOM Ret
= (RTL_ATOM
)0;
2014 PPROCESSINFO ppi
= GetW32ProcessInfo();
2016 if (Flags
& ~(CSF_ANSIPROC
))
2018 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
2019 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2023 UserEnterExclusive();
2025 DPRINT("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2027 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2029 UserRegisterSystemClasses();
2034 /* Probe the parameters and basic parameter checks */
2035 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2037 DPRINT1("NtUserRegisterClassExWOW Wrong cbSize!\n");
2038 goto InvalidParameter
;
2042 sizeof(WNDCLASSEXW
),
2044 RtlCopyMemory(&CapturedClassInfo
,
2046 sizeof(WNDCLASSEXW
));
2048 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2050 ProbeForRead(pClassMenuName
,
2051 sizeof(CLSMENUNAME
),
2054 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2056 if ( CapturedName
.Length
& 1 ||
2057 CapturedMenuName
.Length
& 1 ||
2058 CapturedClassInfo
.cbClsExtra
< 0 ||
2059 CapturedClassInfo
.cbClsExtra
+
2060 CapturedName
.Length
+
2061 CapturedMenuName
.Length
+
2062 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2063 CapturedClassInfo
.cbWndExtra
< 0 ||
2064 CapturedClassInfo
.hInstance
== NULL
)
2066 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2067 goto InvalidParameter
;
2070 if (CapturedName
.Length
!= 0)
2072 ProbeForRead(CapturedName
.Buffer
,
2073 CapturedName
.Length
,
2078 if (!IS_ATOM(CapturedName
.Buffer
))
2080 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2081 goto InvalidParameter
;
2085 if (CapturedMenuName
.Length
!= 0)
2087 ProbeForRead(CapturedMenuName
.Buffer
,
2088 CapturedMenuName
.Length
,
2091 else if (CapturedMenuName
.Buffer
!= NULL
&&
2092 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2094 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2096 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2100 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2101 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2102 // If this pops up we know what todo!
2103 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2106 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2108 /* Register the class */
2109 Ret
= UserRegisterClass(&CapturedClassInfo
,
2115 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2117 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2118 SetLastNtError(_SEH2_GetExceptionCode());
2124 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2133 NtUserGetClassLong(IN HWND hWnd
,
2137 PWINDOW_OBJECT Window
;
2140 if (Offset
!= GCLP_WNDPROC
)
2146 UserEnterExclusive();
2149 Window
= UserGetWindowObject(hWnd
);
2152 Ret
= UserGetClassLongPtr(Window
->Wnd
->pcls
,
2157 Offset
== GCLP_MENUNAME
&&
2158 Window
->Wnd
->pcls
->MenuNameIsString
)
2160 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2172 NtUserSetClassLong(HWND hWnd
,
2174 ULONG_PTR dwNewLong
,
2178 PWINDOW_OBJECT Window
;
2181 UserEnterExclusive();
2183 pi
= GetW32ProcessInfo();
2185 Window
= UserGetWindowObject(hWnd
);
2188 if (Window
->ti
->ppi
!= pi
)
2190 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2196 UNICODE_STRING Value
;
2198 /* probe the parameters */
2199 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2201 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2202 if (Value
.Length
& 1)
2204 goto InvalidParameter
;
2207 if (Value
.Length
!= 0)
2209 ProbeForRead(Value
.Buffer
,
2215 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2217 goto InvalidParameter
;
2219 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2222 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2227 dwNewLong
= (ULONG_PTR
)&Value
;
2230 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2237 SetLastNtError(_SEH2_GetExceptionCode());
2256 * NOTE: Obsoleted in 32-bit windows
2262 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2263 IN HINSTANCE hInstance
,
2264 OUT PCLSMENUNAME pClassMenuName
)
2266 UNICODE_STRING CapturedClassName
;
2269 UserEnterExclusive();
2273 /* probe the paramters */
2274 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2275 if (CapturedClassName
.Length
& 1)
2277 goto InvalidParameter
;
2280 if (CapturedClassName
.Length
!= 0)
2282 ProbeForRead(CapturedClassName
.Buffer
,
2283 CapturedClassName
.Length
,
2288 if (!IS_ATOM(CapturedClassName
.Buffer
))
2291 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2296 /* unregister the class */
2297 Ret
= UserUnregisterClass(&CapturedClassName
,
2299 NULL
); // Null for now~
2301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2303 SetLastNtError(_SEH2_GetExceptionCode());
2311 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2314 HINSTANCE hInstance
,
2315 PUNICODE_STRING ClassName
,
2316 LPWNDCLASSEXW lpWndClassEx
,
2317 LPWSTR
*ppszMenuName
,
2320 UNICODE_STRING CapturedClassName
, SafeClassName
;
2321 WNDCLASSEXW Safewcexw
;
2323 RTL_ATOM ClassAtom
= 0;
2327 /* NOTE: need exclusive lock because getting the wndproc might require the
2328 creation of a call procedure handle */
2329 UserEnterExclusive();
2331 ppi
= GetW32ProcessInfo();
2333 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2335 UserRegisterSystemClasses();
2340 /* probe the paramters */
2341 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2343 if (CapturedClassName
.Length
== 0)
2344 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2346 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2348 if (CapturedClassName
.Length
& 1)
2350 goto InvalidParameter
;
2353 if (CapturedClassName
.Length
!= 0)
2355 ProbeForRead( CapturedClassName
.Buffer
,
2356 CapturedClassName
.Length
,
2359 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2361 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2362 SafeClassName
.MaximumLength
,
2364 RtlCopyMemory( SafeClassName
.Buffer
,
2365 CapturedClassName
.Buffer
,
2366 SafeClassName
.MaximumLength
);
2370 if (!IS_ATOM(CapturedClassName
.Buffer
))
2372 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2373 goto InvalidParameter
;
2376 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2377 SafeClassName
.Length
= 0;
2378 SafeClassName
.MaximumLength
= 0;
2381 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2384 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2389 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2391 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2395 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2400 // If null instance use client.
2401 if (!hInstance
) hInstance
= hModClient
;
2405 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName
, hInstance
);
2406 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2411 if (ClassAtom
!= (RTL_ATOM
)0)
2413 if (hInstance
== NULL
) hInstance
= hModClient
;
2415 Ret
= UserGetClassInfo( Class
,
2422 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2430 /* Emulate Function. */
2431 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2433 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2436 /* We must return the atom of the class here instead of just TRUE. */
2437 /* Undocumented behavior! Return the class atom as a BOOL! */
2438 Ret
= (BOOL
)ClassAtom
;
2441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2443 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2448 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2455 NtUserGetClassName (IN HWND hWnd
,
2456 OUT PUNICODE_STRING ClassName
,
2459 PWINDOW_OBJECT Window
;
2460 UNICODE_STRING CapturedClassName
;
2465 Window
= UserGetWindowObject(hWnd
);
2470 ProbeForWriteUnicodeString(ClassName
);
2471 CapturedClassName
= *ClassName
;
2473 /* get the class name */
2474 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2480 /* update the Length field */
2481 ClassName
->Length
= CapturedClassName
.Length
;
2484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2486 SetLastNtError(_SEH2_GetExceptionCode());
2496 /* Return Pointer to Class structure. */
2498 NtUserGetWOWClass(HINSTANCE hInstance
,
2499 PUNICODE_STRING ClassName
)
2501 UNICODE_STRING SafeClassName
;
2504 RTL_ATOM ClassAtom
= 0;
2507 UserEnterExclusive();
2509 pi
= GetW32ProcessInfo();
2513 if (ClassName
->Length
!= 0)
2515 ProbeForRead( ClassName
->Buffer
,
2519 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2521 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2522 SafeClassName
.MaximumLength
,
2524 RtlCopyMemory( SafeClassName
.Buffer
,
2526 SafeClassName
.MaximumLength
);
2530 if (!IS_ATOM(ClassName
->Buffer
))
2532 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2537 SafeClassName
.Buffer
= ClassName
->Buffer
;
2538 SafeClassName
.Length
= 0;
2539 SafeClassName
.MaximumLength
= 0;
2543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2545 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2552 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2559 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2563 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2566 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.