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
;
388 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
392 // Check if CallProc handle and retrieve previous call proc address and set.
393 if (IsCallProcHandle(WndProc
))
395 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
396 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
399 Class
->lpfnWndProc
= chWndProc
;
404 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
405 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
407 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
409 chWndProc
= GETPFNSERVER(i
);
412 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
414 chWndProc
= GETPFNSERVER(i
);
418 // If match, set/reset to Server Side and clear ansi.
421 Class
->lpfnWndProc
= chWndProc
;
422 Class
->Unicode
= TRUE
;
423 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
424 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
428 Class
->Unicode
= !Ansi
;
431 Class
->CSF_flags
|= CSF_ANSIPROC
;
433 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
436 /* update the clones */
437 chWndProc
= Class
->lpfnWndProc
;
439 Class
= Class
->pclsClone
;
440 while (Class
!= NULL
)
442 Class
->Unicode
= !Ansi
;
443 Class
->lpfnWndProc
= chWndProc
;
445 Class
= Class
->pclsNext
;
452 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
453 IN OUT PCLS
*ClassLink
,
459 ASSERT(Desktop
!= NULL
);
460 ASSERT(BaseClass
->pclsBase
== BaseClass
);
462 if (BaseClass
->rpdeskParent
== Desktop
)
464 /* it is most likely that a window is created on the same
465 desktop as the window class. */
470 if (BaseClass
->rpdeskParent
== NULL
)
472 ASSERT(BaseClass
->cWndReferenceCount
== 0);
473 ASSERT(BaseClass
->pclsClone
== NULL
);
475 /* Classes are also located in the shared heap when the class
476 was created before the thread attached to a desktop. As soon
477 as a window is created for such a class located on the shared
478 heap, the class is cloned into the desktop heap on which the
479 window is created. */
484 /* The user is asking for a class object on a different desktop,
486 Class
= BaseClass
->pclsClone
;
487 while (Class
!= NULL
)
489 if (Class
->rpdeskParent
== Desktop
)
491 ASSERT(Class
->pclsBase
== BaseClass
);
492 ASSERT(Class
->pclsClone
== NULL
);
496 Class
= Class
->pclsNext
;
502 /* The window is created on a different desktop, we need to
503 clone the class object to the desktop heap of the window! */
504 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
506 Class
= DesktopHeapAlloc(Desktop
,
510 /* simply clone the class */
511 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
513 DPRINT("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
515 /* restore module address if default user class Ref: Bug 4778 */
516 if ( Class
->hModule
!= hModClient
&&
517 Class
->fnid
<= FNID_GHOST
&&
518 Class
->fnid
>= FNID_BUTTON
)
520 Class
->hModule
= hModClient
;
521 DPRINT("Clone Class 0x%x Reset hM 0x%x\n",Class
, Class
->hModule
);
524 /* update some pointers and link the class */
525 Class
->rpdeskParent
= Desktop
;
526 Class
->cWndReferenceCount
= 0;
528 if (BaseClass
->rpdeskParent
== NULL
)
530 /* we don't really need the base class on the shared
531 heap anymore, delete it so the only class left is
532 the clone we just created, which now serves as the
534 ASSERT(BaseClass
->pclsClone
== NULL
);
535 ASSERT(Class
->pclsClone
== NULL
);
536 Class
->pclsBase
= Class
;
537 Class
->pclsNext
= BaseClass
->pclsNext
;
539 /* replace the base class */
540 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
543 /* destroy the obsolete copy on the shared heap */
544 BaseClass
->pclsBase
= NULL
;
545 BaseClass
->pclsClone
= NULL
;
546 IntDestroyClass(BaseClass
);
550 /* link in the clone */
551 Class
->pclsClone
= NULL
;
552 Class
->pclsBase
= BaseClass
;
553 Class
->pclsNext
= BaseClass
->pclsClone
;
554 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
560 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
567 IntReferenceClass(IN OUT PCLS BaseClass
,
568 IN OUT PCLS
*ClassLink
,
572 ASSERT(BaseClass
->pclsBase
== BaseClass
);
574 Class
= IntGetClassForDesktop(BaseClass
,
579 Class
->cWndReferenceCount
++;
587 IntMakeCloneBaseClass(IN OUT PCLS Class
,
588 IN OUT PCLS
*BaseClassLink
,
589 IN OUT PCLS
*CloneLink
)
591 PCLS Clone
, BaseClass
;
593 ASSERT(Class
->pclsBase
!= Class
);
594 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
595 ASSERT(Class
->rpdeskParent
!= NULL
);
596 ASSERT(Class
->cWndReferenceCount
!= 0);
597 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
598 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
600 /* unlink the clone */
601 *CloneLink
= Class
->pclsNext
;
602 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
604 BaseClass
= Class
->pclsBase
;
606 /* update the class information to make it a base class */
607 Class
->pclsBase
= Class
;
608 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
610 /* update all clones */
611 Clone
= Class
->pclsClone
;
612 while (Clone
!= NULL
)
614 ASSERT(Clone
->pclsClone
== NULL
);
615 Clone
->pclsBase
= Class
;
617 Clone
= Clone
->pclsNext
;
620 /* link in the new base class */
621 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
627 IntDereferenceClass(IN OUT PCLS Class
,
628 IN PDESKTOPINFO Desktop
,
631 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
633 BaseClass
= Class
->pclsBase
;
635 if (--Class
->cWndReferenceCount
<= 0)
637 if (BaseClass
== Class
)
639 ASSERT(Class
->pclsBase
== Class
);
641 DPRINT("IntDereferenceClass 0x%x\n", Class
);
642 /* check if there are clones of the class on other desktops,
643 link the first clone in if possible. If there are no clones
644 then leave the class on the desktop heap. It will get moved
645 to the shared heap when the thread detaches. */
646 if (BaseClass
->pclsClone
!= NULL
)
648 if (BaseClass
->Global
)
649 PrevLink
= &pi
->pclsPublicList
;
651 PrevLink
= &pi
->pclsPrivateList
;
653 CurrentClass
= *PrevLink
;
654 while (CurrentClass
!= BaseClass
)
656 ASSERT(CurrentClass
!= NULL
);
658 PrevLink
= &CurrentClass
->pclsNext
;
659 CurrentClass
= CurrentClass
->pclsNext
;
662 ASSERT(*PrevLink
== BaseClass
);
664 /* make the first clone become the new base class */
665 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
667 &BaseClass
->pclsClone
);
669 /* destroy the class, there's still another clone of the class
670 that now serves as a base class. Make sure we don't destruct
671 resources shared by all classes (Base = NULL)! */
672 BaseClass
->pclsBase
= NULL
;
673 BaseClass
->pclsClone
= NULL
;
674 IntDestroyClass(BaseClass
);
679 DPRINT("IntDereferenceClass1 0x%x\n", Class
);
681 /* locate the cloned class and unlink it */
682 PrevLink
= &BaseClass
->pclsClone
;
683 CurrentClass
= BaseClass
->pclsClone
;
684 while (CurrentClass
!= Class
)
686 ASSERT(CurrentClass
!= NULL
);
688 PrevLink
= &CurrentClass
->pclsNext
;
689 CurrentClass
= CurrentClass
->pclsNext
;
692 ASSERT(CurrentClass
== Class
);
694 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
697 ASSERT(Class
->pclsBase
== BaseClass
);
698 ASSERT(Class
->pclsClone
== NULL
);
700 /* the class was just a clone, we don't need it anymore */
701 IntDestroyClass(Class
);
707 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
708 IN OUT PCLS
**ClassLinkPtr
)
713 ASSERT(Class
->pclsBase
== Class
);
714 ASSERT(Class
->rpdeskParent
!= NULL
);
715 ASSERT(Class
->cWndReferenceCount
== 0);
716 ASSERT(Class
->pclsClone
== NULL
);
718 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
720 /* allocate the new base class on the shared heap */
721 NewClass
= UserHeapAlloc(ClassSize
);
722 if (NewClass
!= NULL
)
724 RtlCopyMemory(NewClass
,
728 NewClass
->rpdeskParent
= NULL
;
729 NewClass
->pclsBase
= NewClass
;
731 /* replace the class in the list */
732 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
734 *ClassLinkPtr
= &NewClass
->pclsNext
;
736 /* free the obsolete class on the desktop heap */
737 Class
->pclsBase
= NULL
;
738 IntDestroyClass(Class
);
746 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
747 IN OUT PCLS
*ClassList
,
748 IN BOOL FreeOnFailure
,
751 PCLS Class
, NextClass
, *Link
;
753 /* NOTE: We only need to check base classes! When classes are no longer needed
754 on a desktop, the clones will be freed automatically as soon as possible.
755 However, we need to move base classes to the shared heap, as soon as
756 the last desktop heap where a class is allocated on is about to be destroyed.
757 If we didn't move the class to the shared heap, the class would become
760 ASSERT(Desktop
!= NULL
);
764 while (Class
!= NULL
)
766 NextClass
= Class
->pclsNext
;
768 ASSERT(Class
->pclsBase
== Class
);
770 if (Class
->rpdeskParent
== Desktop
&&
771 Class
->cWndReferenceCount
== 0)
773 /* there shouldn't be any clones around anymore! */
774 ASSERT(Class
->pclsClone
== NULL
);
776 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
777 /* FIXME - We could move the class to another desktop heap if there's still desktops
778 mapped into the process... */
780 /* move the class to the shared heap */
781 if (IntMoveClassToSharedHeap(Class
,
784 ASSERT(*Link
== NextClass
);
788 ASSERT(NextClass
== Class
->pclsNext
);
792 /* unlink the base class */
793 (void)InterlockedExchangePointer((PVOID
*)Link
,
796 /* we can free the old base class now */
797 Class
->pclsBase
= NULL
;
798 IntDestroyClass(Class
);
802 Link
= &Class
->pclsNext
;
808 Link
= &Class
->pclsNext
;
815 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
816 IN BOOL FreeOnFailure
)
821 pi
= GetW32ProcessInfo();
823 /* check all local classes */
824 IntCheckDesktopClasses(Desktop
,
825 &pi
->pclsPrivateList
,
829 /* check all global classes */
830 IntCheckDesktopClasses(Desktop
,
836 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
837 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
845 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
846 IN PUNICODE_STRING ClassName
,
847 IN PUNICODE_STRING MenuName
,
857 PWSTR pszMenuName
= NULL
;
858 NTSTATUS Status
= STATUS_SUCCESS
;
860 DPRINT("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
861 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
863 if (!IntRegisterClassAtom(ClassName
,
866 DPRINT1("Failed to register class atom!\n");
870 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
871 if (MenuName
->Length
!= 0)
873 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
874 RtlUnicodeStringToAnsiSize(MenuName
));
875 if (pszMenuName
== NULL
)
881 Class
= DesktopHeapAlloc(Desktop
,
886 /* FIXME - the class was created before being connected
887 to a desktop. It is possible for the desktop window,
888 but should it be allowed for any other case? */
889 Class
= UserHeapAlloc(ClassSize
);
896 RtlZeroMemory(Class
, ClassSize
);
898 Class
->rpdeskParent
= Desktop
;
899 Class
->pclsBase
= Class
;
900 Class
->atomClassName
= Atom
;
902 Class
->CSF_flags
= dwFlags
;
904 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
906 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
911 PWSTR pszMenuNameBuffer
= pszMenuName
;
913 /* need to protect with SEH since accessing the WNDCLASSEX structure
914 and string buffers might raise an exception! We don't want to
916 // What?! If the user interface was written correctly this would not be an issue!
917 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
918 Class
->style
= lpwcx
->style
;
919 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
920 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
921 Class
->hModule
= lpwcx
->hInstance
;
922 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
923 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
924 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
925 Class
->hbrBackground
= lpwcx
->hbrBackground
;
927 /* make a copy of the string */
928 if (pszMenuNameBuffer
!= NULL
)
930 Class
->MenuNameIsString
= TRUE
;
932 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
933 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
936 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
938 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
941 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
943 /* save an ansi copy of the string */
944 if (pszMenuNameBuffer
!= NULL
)
946 ANSI_STRING AnsiString
;
948 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
949 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
950 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
951 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
954 if (!NT_SUCCESS(Status
))
956 DPRINT1("Failed to convert unicode menu name to ansi!\n");
958 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
963 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
965 /* Save kernel use menu name and ansi class name */
966 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
967 //Class->lpszAnsiClassName = Fixme!
969 /* Server Side overrides class calling type (A/W)!
970 User32 whine test_builtinproc: "deftest"
971 built-in winproc - window A/W type automatically detected */
972 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
976 /* Due to the wine class "deftest" and most likely no FNID to reference
977 from, sort through the Server Side list and compare proc addresses
978 for match. This method will be used in related code.
980 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
981 { // Open Ansi or Unicode, just match, set and break.
982 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
984 WndProc
= GETPFNSERVER(i
);
987 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
989 WndProc
= GETPFNSERVER(i
);
994 { // If a hit, we are Server Side so set the right flags and proc.
995 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
996 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
997 Class
->lpfnWndProc
= WndProc
;
1001 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1002 Class
->Unicode
= TRUE
;
1004 if (Class
->style
& CS_GLOBALCLASS
)
1005 Class
->Global
= TRUE
;
1007 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1009 Status
= _SEH2_GetExceptionCode();
1013 if (!NT_SUCCESS(Status
))
1015 DPRINT1("Failed creating the class: 0x%x\n", Status
);
1017 SetLastNtError(Status
);
1019 if (pszMenuName
!= NULL
)
1020 UserHeapFree(pszMenuName
);
1022 DesktopHeapFree(Desktop
,
1026 IntDeregisterClassAtom(Atom
);
1032 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1034 if (pszMenuName
!= NULL
)
1035 UserHeapFree(pszMenuName
);
1037 IntDeregisterClassAtom(Atom
);
1039 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1046 IntFindClass(IN RTL_ATOM Atom
,
1047 IN HINSTANCE hInstance
,
1049 OUT PCLS
**Link OPTIONAL
)
1051 PCLS Class
, *PrevLink
= ClassList
;
1054 while (Class
!= NULL
)
1056 if (Class
->atomClassName
== Atom
&&
1057 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1058 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1060 ASSERT(Class
->pclsBase
== Class
);
1067 PrevLink
= &Class
->pclsNext
;
1068 Class
= Class
->pclsNext
;
1075 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1080 if (ClassName
->Length
!= 0)
1086 /* NOTE: Caller has to protect the call with SEH! */
1088 if (ClassName
->Length
!= 0)
1090 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1091 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1093 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1097 /* We need to make a local copy of the class name! The caller could
1098 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1099 We're protected by SEH, but the ranges that might be accessed were
1101 RtlCopyMemory(szBuf
,
1104 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1108 AtomName
= ClassName
->Buffer
;
1110 /* lookup the atom */
1111 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1114 if (NT_SUCCESS(Status
))
1120 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1122 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1126 SetLastNtError(Status
);
1132 ASSERT(IS_ATOM(ClassName
->Buffer
));
1133 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1141 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1142 IN HINSTANCE hInstance OPTIONAL
,
1143 IN PPROCESSINFO pi OPTIONAL
,
1144 OUT PCLS
*BaseClass OPTIONAL
,
1145 OUT PCLS
**Link OPTIONAL
)
1147 RTL_ATOM Atom
= (RTL_ATOM
)0;
1149 ASSERT(BaseClass
!= NULL
);
1151 if (IntGetAtomFromStringOrAtom(ClassName
,
1153 Atom
!= (RTL_ATOM
)0)
1157 /* attempt to locate the class object */
1161 /* Step 1: try to find an exact match of locally registered classes */
1162 Class
= IntFindClass(Atom
,
1164 &pi
->pclsPrivateList
,
1167 { DPRINT("Step 1: 0x%x\n",Class
);
1171 /* Step 2: try to find any globally registered class. The hInstance
1172 is not relevant for global classes */
1173 Class
= IntFindClass(Atom
,
1175 &pi
->pclsPublicList
,
1178 { DPRINT("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1182 /* Step 3: try to find any local class registered by user32 */
1183 Class
= IntFindClass(Atom
,
1185 &pi
->pclsPrivateList
,
1188 { DPRINT("Step 3: 0x%x\n",Class
);
1192 /* Step 4: try to find any global class registered by user32 */
1193 Class
= IntFindClass(Atom
,
1195 &pi
->pclsPublicList
,
1199 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1201 }else{DPRINT("Step 4: 0x%x\n",Class
);}
1211 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1212 IN PUNICODE_STRING ClassName
,
1213 IN PUNICODE_STRING MenuName
,
1221 RTL_ATOM Ret
= (RTL_ATOM
)0;
1223 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1225 pti
= GetW32ThreadInfo();
1229 // Need only to test for two conditions not four....... Fix more whine tests....
1230 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1231 ClassAtom
!= (RTL_ATOM
)0 &&
1232 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1234 Class
= IntFindClass( ClassAtom
,
1236 &pi
->pclsPrivateList
,
1239 if (Class
!= NULL
&& !Class
->Global
)
1241 // local class already exists
1242 DPRINT("Local Class 0x%p does already exist!\n", ClassAtom
);
1243 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1247 if (lpwcx
->style
& CS_GLOBALCLASS
)
1249 Class
= IntFindClass( ClassAtom
,
1251 &pi
->pclsPublicList
,
1254 if (Class
!= NULL
&& Class
->Global
)
1256 DPRINT("Global Class 0x%p does already exist!\n", ClassAtom
);
1257 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1263 Class
= IntCreateClass(lpwcx
,
1275 /* Register the class */
1277 List
= &pi
->pclsPublicList
;
1279 List
= &pi
->pclsPrivateList
;
1281 Class
->pclsNext
= *List
;
1282 (void)InterlockedExchangePointer((PVOID
*)List
,
1285 Ret
= Class
->atomClassName
;
1289 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1296 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1297 IN HINSTANCE hInstance
,
1298 OUT PCLSMENUNAME pClassMenuName
)
1305 pi
= GetW32ProcessInfo();
1307 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1309 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1310 ClassAtom
= IntGetClassAtom(ClassName
,
1315 if (ClassAtom
== (RTL_ATOM
)0)
1317 DPRINT("UserUnregisterClass: No Class found.\n");
1321 ASSERT(Class
!= NULL
);
1323 if (Class
->cWndReferenceCount
!= 0 ||
1324 Class
->pclsClone
!= NULL
)
1326 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1327 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1331 /* must be a base class! */
1332 ASSERT(Class
->pclsBase
== Class
);
1334 /* unlink the class */
1335 *Link
= Class
->pclsNext
;
1337 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1339 DPRINT("Class 0x%x\n", Class
);
1340 DPRINT("UserUnregisterClass: Good Exit!\n");
1341 /* finally free the resources */
1342 IntDestroyClass(Class
);
1345 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1350 UserGetClassName(IN PCLS Class
,
1351 IN OUT PUNICODE_STRING ClassName
,
1354 NTSTATUS Status
= STATUS_SUCCESS
;
1355 WCHAR szStaticTemp
[32];
1356 PWSTR szTemp
= NULL
;
1357 ULONG BufLen
= sizeof(szStaticTemp
);
1360 /* Note: Accessing the buffer in ClassName may raise an exception! */
1366 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1367 UNICODE_STRING UnicodeClassName
;
1369 /* limit the size of the static buffer on the stack to the
1370 size of the buffer provided by the caller */
1371 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1373 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1376 /* find out how big the buffer needs to be */
1377 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1378 Class
->atomClassName
,
1383 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1385 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1387 /* the buffer required exceeds the ansi buffer provided,
1388 pretend like we're using the ansi buffer and limit the
1389 size to the buffer size provided */
1390 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1393 /* allocate a temporary buffer that can hold the unicode class name */
1394 szTemp
= ExAllocatePool(PagedPool
,
1398 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1402 /* query the class name */
1403 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1404 Class
->atomClassName
,
1411 szTemp
= szStaticTemp
;
1413 if (NT_SUCCESS(Status
))
1415 /* convert the atom name to ansi */
1417 RtlInitUnicodeString(&UnicodeClassName
,
1420 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1423 if (!NT_SUCCESS(Status
))
1425 SetLastNtError(Status
);
1430 Ret
= BufLen
/ sizeof(WCHAR
);
1434 BufLen
= ClassName
->MaximumLength
;
1436 /* query the atom name */
1437 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1438 Class
->atomClassName
,
1444 if (!NT_SUCCESS(Status
))
1446 SetLastNtError(Status
);
1450 Ret
= BufLen
/ sizeof(WCHAR
);
1453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1455 SetLastNtError(_SEH2_GetExceptionCode());
1459 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1468 UserGetClassLongPtr(IN PCLS Class
,
1478 TRACE("GetClassLong(%d)\n", Index
);
1479 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1480 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1482 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1486 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1488 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1489 certain architectures, maybe using RtlCopyMemory is a
1490 better choice for those architectures! */
1492 TRACE("Result: %x\n", Ret
);
1498 case GCL_CBWNDEXTRA
:
1499 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1502 case GCL_CBCLSEXTRA
:
1503 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
1506 case GCLP_HBRBACKGROUND
:
1507 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1511 /* FIXME - get handle from pointer to CURSOR object */
1512 Ret
= (ULONG_PTR
)Class
->hCursor
;
1516 /* FIXME - get handle from pointer to ICON object */
1517 Ret
= (ULONG_PTR
)Class
->hIcon
;
1521 /* FIXME - get handle from pointer to ICON object */
1522 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1526 Ret
= (ULONG_PTR
)Class
->hModule
;
1530 /* NOTE: Returns pointer in kernel heap! */
1532 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
1534 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
1538 Ret
= (ULONG_PTR
)Class
->style
;
1542 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
, Ansi
);
1546 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1550 SetLastWin32Error(ERROR_INVALID_INDEX
);
1558 IntSetClassMenuName(IN PCLS Class
,
1559 IN PUNICODE_STRING MenuName
)
1563 /* change the base class first */
1564 Class
= Class
->pclsBase
;
1566 if (MenuName
->Length
!= 0)
1568 ANSI_STRING AnsiString
;
1571 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1573 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1574 AnsiString
.MaximumLength
);
1575 if (strBufW
!= NULL
)
1581 /* copy the unicode string */
1582 RtlCopyMemory(strBufW
,
1585 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1587 /* create an ansi copy of the string */
1588 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1589 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1592 if (!NT_SUCCESS(Status
))
1594 SetLastNtError(Status
);
1600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1602 SetLastNtError(_SEH2_GetExceptionCode());
1608 /* update the base class */
1609 IntFreeClassMenuName(Class
);
1610 Class
->lpszClientUnicodeMenuName
= strBufW
;
1611 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1612 Class
->MenuNameIsString
= TRUE
;
1614 /* update the clones */
1615 Class
= Class
->pclsClone
;
1616 while (Class
!= NULL
)
1618 Class
->lpszClientUnicodeMenuName
= strBufW
;
1619 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1620 Class
->MenuNameIsString
= TRUE
;
1622 Class
= Class
->pclsNext
;
1627 DPRINT1("Failed to copy class menu name!\n");
1628 UserHeapFree(strBufW
);
1632 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1636 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1638 /* update the base class */
1639 IntFreeClassMenuName(Class
);
1640 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1641 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1642 Class
->MenuNameIsString
= FALSE
;
1644 /* update the clones */
1645 Class
= Class
->pclsClone
;
1646 while (Class
!= NULL
)
1648 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1649 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1650 Class
->MenuNameIsString
= FALSE
;
1652 Class
= Class
->pclsNext
;
1662 UserSetClassLongPtr(IN PCLS Class
,
1664 IN ULONG_PTR NewLong
,
1669 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1671 /* change the information in the base class first, then update the clones */
1672 Class
= Class
->pclsBase
;
1678 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1680 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1681 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1683 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1687 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1689 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1690 certain architectures, maybe using RtlCopyMemory is a
1691 better choice for those architectures! */
1695 /* update the clones */
1696 Class
= Class
->pclsClone
;
1697 while (Class
!= NULL
)
1699 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1700 Class
= Class
->pclsNext
;
1708 case GCL_CBWNDEXTRA
:
1709 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1710 Class
->cbwndExtra
= (INT
)NewLong
;
1712 /* update the clones */
1713 Class
= Class
->pclsClone
;
1714 while (Class
!= NULL
)
1716 Class
->cbwndExtra
= (INT
)NewLong
;
1717 Class
= Class
->pclsNext
;
1722 case GCL_CBCLSEXTRA
:
1723 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1726 case GCLP_HBRBACKGROUND
:
1727 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1728 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1730 /* update the clones */
1731 Class
= Class
->pclsClone
;
1732 while (Class
!= NULL
)
1734 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1735 Class
= Class
->pclsNext
;
1740 /* FIXME - get handle from pointer to CURSOR object */
1741 Ret
= (ULONG_PTR
)Class
->hCursor
;
1742 Class
->hCursor
= (HANDLE
)NewLong
;
1744 /* update the clones */
1745 Class
= Class
->pclsClone
;
1746 while (Class
!= NULL
)
1748 Class
->hCursor
= (HANDLE
)NewLong
;
1749 Class
= Class
->pclsNext
;
1754 /* FIXME - get handle from pointer to ICON object */
1755 Ret
= (ULONG_PTR
)Class
->hIcon
;
1756 Class
->hIcon
= (HANDLE
)NewLong
;
1758 /* update the clones */
1759 Class
= Class
->pclsClone
;
1760 while (Class
!= NULL
)
1762 Class
->hIcon
= (HANDLE
)NewLong
;
1763 Class
= Class
->pclsNext
;
1768 /* FIXME - get handle from pointer to ICON object */
1769 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1770 Class
->hIconSm
= (HANDLE
)NewLong
;
1772 /* update the clones */
1773 Class
= Class
->pclsClone
;
1774 while (Class
!= NULL
)
1776 Class
->hIconSm
= (HANDLE
)NewLong
;
1777 Class
= Class
->pclsNext
;
1782 Ret
= (ULONG_PTR
)Class
->hModule
;
1783 Class
->hModule
= (HINSTANCE
)NewLong
;
1785 /* update the clones */
1786 Class
= Class
->pclsClone
;
1787 while (Class
!= NULL
)
1789 Class
->hModule
= (HINSTANCE
)NewLong
;
1790 Class
= Class
->pclsNext
;
1796 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1798 if (!IntSetClassMenuName(Class
,
1801 DPRINT1("Setting the class menu name failed!\n");
1804 /* FIXME - really return NULL? Wine does so... */
1809 Ret
= (ULONG_PTR
)Class
->style
;
1810 Class
->style
= (UINT
)NewLong
;
1812 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1813 move the class to the appropriate list? For now, we save
1814 the original value in Class->Global, so we can always
1815 locate the appropriate list */
1817 /* update the clones */
1818 Class
= Class
->pclsClone
;
1819 while (Class
!= NULL
)
1821 Class
->style
= (UINT
)NewLong
;
1822 Class
= Class
->pclsNext
;
1827 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1834 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1836 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1837 if (!IntSetClassAtom(Class
,
1846 SetLastWin32Error(ERROR_INVALID_INDEX
);
1854 UserGetClassInfo(IN PCLS Class
,
1855 OUT PWNDCLASSEXW lpwcx
,
1857 HINSTANCE hInstance
)
1861 if (!Class
) return FALSE
;
1863 lpwcx
->style
= Class
->style
;
1865 // If fnId is set, clear the global bit. See wine class test check_style.
1867 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1869 pi
= GetW32ProcessInfo();
1871 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1873 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1874 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1875 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1876 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1877 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1879 /* Copy non-string to user first. */
1881 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1883 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1885 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1886 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1887 lpszClientXxxMenuName should already be mapped to user space.
1889 /* Copy string ptr to user. */
1890 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1891 Class
->MenuNameIsString
)
1893 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1894 (PVOID
)Class
->lpszClientAnsiMenuName
:
1895 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1898 if (hInstance
== hModClient
)
1899 lpwcx
->hInstance
= NULL
;
1901 lpwcx
->hInstance
= hInstance
;
1903 /* FIXME - return the string? Okay! This is performed in User32!*/
1904 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1906 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1916 UserRegisterSystemClasses(VOID
)
1919 UNICODE_STRING ClassName
, MenuName
;
1920 PPROCESSINFO ppi
= GetW32ProcessInfo();
1926 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1929 if ( hModClient
== NULL
)
1932 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1933 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1935 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1937 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1939 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1943 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1944 ClassName
.Length
= 0;
1945 ClassName
.MaximumLength
= 0;
1948 wc
.cbSize
= sizeof(wc
);
1949 wc
.style
= DefaultServerClasses
[i
].Style
;
1951 Flags
|= CSF_SERVERSIDEPROC
;
1953 if (DefaultServerClasses
[i
].ProcW
)
1955 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1956 wc
.hInstance
= hModuleWin
;
1960 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1961 wc
.hInstance
= hModClient
;
1965 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1967 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1968 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1969 wc
.lpszMenuName
= NULL
;
1970 wc
.lpszClassName
= ClassName
.Buffer
;
1973 Class
= IntCreateClass( &wc
,
1976 DefaultServerClasses
[i
].fiId
,
1982 Class
->pclsNext
= ppi
->pclsPublicList
;
1983 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1986 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1990 WARN("!!! Registering system class failed!\n");
1994 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1998 /* SYSCALLS *****************************************************************/
2002 NtUserRegisterClassExWOW(
2004 PUNICODE_STRING ClassName
,
2005 PUNICODE_STRING ClsNVersion
,
2006 PCLSMENUNAME pClassMenuName
,
2012 * Registers a new class with the window manager
2014 * lpwcx = Win32 extended window class structure
2015 * bUnicodeClass = Whether to send ANSI or unicode strings
2016 * to window procedures
2018 * Atom identifying the new class
2021 WNDCLASSEXW CapturedClassInfo
= {0};
2022 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2023 RTL_ATOM Ret
= (RTL_ATOM
)0;
2024 PPROCESSINFO ppi
= GetW32ProcessInfo();
2026 if (Flags
& ~(CSF_ANSIPROC
))
2028 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
2029 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2033 UserEnterExclusive();
2035 DPRINT("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2037 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2039 UserRegisterSystemClasses();
2044 /* Probe the parameters and basic parameter checks */
2045 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2047 DPRINT1("NtUserRegisterClassExWOW Wrong cbSize!\n");
2048 goto InvalidParameter
;
2052 sizeof(WNDCLASSEXW
),
2054 RtlCopyMemory(&CapturedClassInfo
,
2056 sizeof(WNDCLASSEXW
));
2058 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2060 ProbeForRead(pClassMenuName
,
2061 sizeof(CLSMENUNAME
),
2064 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2066 if ( CapturedName
.Length
& 1 ||
2067 CapturedMenuName
.Length
& 1 ||
2068 CapturedClassInfo
.cbClsExtra
< 0 ||
2069 CapturedClassInfo
.cbClsExtra
+
2070 CapturedName
.Length
+
2071 CapturedMenuName
.Length
+
2072 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2073 CapturedClassInfo
.cbWndExtra
< 0 ||
2074 CapturedClassInfo
.hInstance
== NULL
)
2076 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2077 goto InvalidParameter
;
2080 if (CapturedName
.Length
!= 0)
2082 ProbeForRead(CapturedName
.Buffer
,
2083 CapturedName
.Length
,
2088 if (!IS_ATOM(CapturedName
.Buffer
))
2090 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2091 goto InvalidParameter
;
2095 if (CapturedMenuName
.Length
!= 0)
2097 ProbeForRead(CapturedMenuName
.Buffer
,
2098 CapturedMenuName
.Length
,
2101 else if (CapturedMenuName
.Buffer
!= NULL
&&
2102 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2104 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2106 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2110 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2111 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2112 // If this pops up we know what todo!
2113 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2116 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2118 /* Register the class */
2119 Ret
= UserRegisterClass(&CapturedClassInfo
,
2125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2127 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2128 SetLastNtError(_SEH2_GetExceptionCode());
2134 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2143 NtUserGetClassLong(IN HWND hWnd
,
2147 PWINDOW_OBJECT Window
;
2150 if (Offset
!= GCLP_WNDPROC
)
2156 UserEnterExclusive();
2159 Window
= UserGetWindowObject(hWnd
);
2162 Ret
= UserGetClassLongPtr(Window
->Wnd
->pcls
,
2167 Offset
== GCLP_MENUNAME
&&
2168 Window
->Wnd
->pcls
->MenuNameIsString
)
2170 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2182 NtUserSetClassLong(HWND hWnd
,
2184 ULONG_PTR dwNewLong
,
2188 PWINDOW_OBJECT Window
;
2191 UserEnterExclusive();
2193 pi
= GetW32ProcessInfo();
2195 Window
= UserGetWindowObject(hWnd
);
2198 if (Window
->pti
->ppi
!= pi
)
2200 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2206 UNICODE_STRING Value
;
2208 /* probe the parameters */
2209 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2211 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2212 if (Value
.Length
& 1)
2214 goto InvalidParameter
;
2217 if (Value
.Length
!= 0)
2219 ProbeForRead(Value
.Buffer
,
2225 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2227 goto InvalidParameter
;
2229 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2232 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2237 dwNewLong
= (ULONG_PTR
)&Value
;
2240 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2245 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2247 SetLastNtError(_SEH2_GetExceptionCode());
2266 * NOTE: Obsoleted in 32-bit windows
2272 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2273 IN HINSTANCE hInstance
,
2274 OUT PCLSMENUNAME pClassMenuName
)
2276 UNICODE_STRING CapturedClassName
;
2279 UserEnterExclusive();
2283 /* probe the paramters */
2284 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2285 if (CapturedClassName
.Length
& 1)
2287 goto InvalidParameter
;
2290 if (CapturedClassName
.Length
!= 0)
2292 ProbeForRead(CapturedClassName
.Buffer
,
2293 CapturedClassName
.Length
,
2298 if (!IS_ATOM(CapturedClassName
.Buffer
))
2301 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2306 /* unregister the class */
2307 Ret
= UserUnregisterClass(&CapturedClassName
,
2309 NULL
); // Null for now~
2311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2313 SetLastNtError(_SEH2_GetExceptionCode());
2321 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2324 HINSTANCE hInstance
,
2325 PUNICODE_STRING ClassName
,
2326 LPWNDCLASSEXW lpWndClassEx
,
2327 LPWSTR
*ppszMenuName
,
2330 UNICODE_STRING CapturedClassName
, SafeClassName
;
2331 WNDCLASSEXW Safewcexw
;
2333 RTL_ATOM ClassAtom
= 0;
2337 /* NOTE: need exclusive lock because getting the wndproc might require the
2338 creation of a call procedure handle */
2339 UserEnterExclusive();
2341 ppi
= GetW32ProcessInfo();
2343 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2345 UserRegisterSystemClasses();
2350 /* probe the paramters */
2351 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2353 if (CapturedClassName
.Length
== 0)
2354 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2356 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2358 if (CapturedClassName
.Length
& 1)
2360 goto InvalidParameter
;
2363 if (CapturedClassName
.Length
!= 0)
2365 ProbeForRead( CapturedClassName
.Buffer
,
2366 CapturedClassName
.Length
,
2369 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2371 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2372 SafeClassName
.MaximumLength
,
2374 RtlCopyMemory( SafeClassName
.Buffer
,
2375 CapturedClassName
.Buffer
,
2376 SafeClassName
.MaximumLength
);
2380 if (!IS_ATOM(CapturedClassName
.Buffer
))
2382 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2383 goto InvalidParameter
;
2386 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2387 SafeClassName
.Length
= 0;
2388 SafeClassName
.MaximumLength
= 0;
2391 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2394 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2399 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2401 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2405 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2410 // If null instance use client.
2411 if (!hInstance
) hInstance
= hModClient
;
2415 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName
, hInstance
);
2416 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2421 if (ClassAtom
!= (RTL_ATOM
)0)
2423 if (hInstance
== NULL
) hInstance
= hModClient
;
2425 Ret
= UserGetClassInfo( Class
,
2432 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2440 /* Emulate Function. */
2441 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2443 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2446 /* We must return the atom of the class here instead of just TRUE. */
2447 /* Undocumented behavior! Return the class atom as a BOOL! */
2448 Ret
= (BOOL
)ClassAtom
;
2451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2453 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2458 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2465 NtUserGetClassName (IN HWND hWnd
,
2466 OUT PUNICODE_STRING ClassName
,
2469 PWINDOW_OBJECT Window
;
2470 UNICODE_STRING CapturedClassName
;
2475 Window
= UserGetWindowObject(hWnd
);
2480 ProbeForWriteUnicodeString(ClassName
);
2481 CapturedClassName
= *ClassName
;
2483 /* get the class name */
2484 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2490 /* update the Length field */
2491 ClassName
->Length
= CapturedClassName
.Length
;
2494 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2496 SetLastNtError(_SEH2_GetExceptionCode());
2506 /* Return Pointer to Class structure. */
2508 NtUserGetWOWClass(HINSTANCE hInstance
,
2509 PUNICODE_STRING ClassName
)
2511 UNICODE_STRING SafeClassName
;
2514 RTL_ATOM ClassAtom
= 0;
2517 UserEnterExclusive();
2519 pi
= GetW32ProcessInfo();
2523 if (ClassName
->Length
!= 0)
2525 ProbeForRead( ClassName
->Buffer
,
2529 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2531 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2532 SafeClassName
.MaximumLength
,
2534 RtlCopyMemory( SafeClassName
.Buffer
,
2536 SafeClassName
.MaximumLength
);
2540 if (!IS_ATOM(ClassName
->Buffer
))
2542 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2547 SafeClassName
.Buffer
= ClassName
->Buffer
;
2548 SafeClassName
.Length
= 0;
2549 SafeClassName
.MaximumLength
= 0;
2553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2555 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2562 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2569 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2573 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2576 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.