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>
10 DBG_DEFAULT_CHANNEL(UserClass
);
12 REGISTER_SYSCLASS DefaultServerClasses
[] =
14 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
15 CS_GLOBALCLASS
|CS_DBLCLKS
,
19 (HBRUSH
)(COLOR_BACKGROUND
+ 1),
23 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
24 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
25 NULL
, // Use User32 procs
32 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
33 CS_DBLCLKS
|CS_SAVEBITS
,
34 NULL
, // Use User32 procs
37 (HBRUSH
)(COLOR_MENU
+ 1),
42 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
43 NULL
, // Use User32 procs
50 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
52 NULL
, // Use User32 procs
61 NULL
, // Use User32 procs
75 { /* Function Ids to Class indexes. */
76 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
77 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
78 { FNID_MENU
, ICLS_MENU
},
79 { FNID_DESKTOP
, ICLS_DESKTOP
},
80 { FNID_SWITCH
, ICLS_SWITCH
},
81 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
82 { FNID_BUTTON
, ICLS_BUTTON
},
83 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
84 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
85 { FNID_DIALOG
, ICLS_DIALOG
},
86 { FNID_EDIT
, ICLS_EDIT
},
87 { FNID_LISTBOX
, ICLS_LISTBOX
},
88 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
89 { FNID_STATIC
, ICLS_STATIC
},
90 { FNID_IME
, ICLS_IME
},
91 { FNID_GHOST
, ICLS_GHOST
},
92 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
97 LookupFnIdToiCls(int FnId
, int *iCls
)
101 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
103 if (FnidToiCls
[i
].FnId
== FnId
)
105 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
113 /* WINDOWCLASS ***************************************************************/
116 IntFreeClassMenuName(IN OUT PCLS Class
)
118 /* free the menu name, if it was changed and allocated */
119 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
121 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
122 Class
->lpszClientUnicodeMenuName
= NULL
;
123 Class
->lpszClientAnsiMenuName
= NULL
;
128 IntDestroyClass(IN OUT PCLS Class
)
131 /* there shouldn't be any clones anymore */
132 ASSERT(Class
->cWndReferenceCount
== 0);
133 ASSERT(Class
->pclsClone
== NULL
);
135 if (Class
->pclsBase
== Class
)
137 PCALLPROCDATA CallProc
, NextCallProc
;
139 /* Destroy allocated callproc handles */
140 CallProc
= Class
->spcpdFirst
;
141 while (CallProc
!= NULL
)
143 NextCallProc
= CallProc
->spcpdNext
;
145 CallProc
->spcpdNext
= NULL
;
146 DestroyCallProc(NULL
,
149 CallProc
= NextCallProc
;
154 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
158 IntFreeClassMenuName(Class
);
161 pDesk
= Class
->rpdeskParent
;
162 Class
->rpdeskParent
= NULL
;
164 /* free the structure */
167 DesktopHeapFree(pDesk
, Class
);
176 /* clean all process classes. all process windows must cleaned first!! */
177 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
180 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
184 /* free all local classes */
185 Class
= pi
->pclsPrivateList
;
186 while (Class
!= NULL
)
188 pi
->pclsPrivateList
= Class
->pclsNext
;
190 ASSERT(Class
->pclsBase
== Class
);
191 IntDestroyClass(Class
);
193 Class
= pi
->pclsPrivateList
;
196 /* free all global classes */
197 Class
= pi
->pclsPublicList
;
198 while (Class
!= NULL
)
200 pi
->pclsPublicList
= Class
->pclsNext
;
202 ASSERT(Class
->pclsBase
== Class
);
203 IntDestroyClass(Class
);
205 Class
= pi
->pclsPublicList
;
211 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
218 if (ClassName
->Length
!= 0)
220 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
221 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
223 EngSetLastError(ERROR_INVALID_PARAMETER
);
230 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
234 AtomName
= ClassName
->Buffer
;
236 Status
= RtlAddAtomToAtomTable(gAtomTable
,
240 if (!NT_SUCCESS(Status
))
242 SetLastNtError(Status
);
250 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
252 return RtlDeleteAtomFromAtomTable(gAtomTable
,
257 UserAddCallProcToClass(IN OUT PCLS Class
,
258 IN PCALLPROCDATA CallProc
)
262 ASSERT(CallProc
->spcpdNext
== NULL
);
264 BaseClass
= Class
->pclsBase
;
265 ASSERT(CallProc
->spcpdNext
== NULL
);
266 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
267 BaseClass
->spcpdFirst
= CallProc
;
269 /* Update all clones */
270 Class
= Class
->pclsClone
;
271 while (Class
!= NULL
)
273 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
274 Class
= Class
->pclsNext
;
279 IntSetClassAtom(IN OUT PCLS Class
,
280 IN PUNICODE_STRING ClassName
)
282 RTL_ATOM Atom
= (RTL_ATOM
)0;
284 /* update the base class first */
285 Class
= Class
->pclsBase
;
287 if (!IntRegisterClassAtom(ClassName
,
293 IntDeregisterClassAtom(Class
->atomClassName
);
295 Class
->atomClassName
= Atom
;
297 /* update the clones */
298 Class
= Class
->pclsClone
;
299 while (Class
!= NULL
)
301 Class
->atomClassName
= Atom
;
303 Class
= Class
->pclsNext
;
310 // Same as User32:IntGetClsWndProc.
313 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
316 WNDPROC gcpd
= NULL
, Ret
= NULL
;
318 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
320 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
322 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
325 Ret
= GETPFNCLIENTA(i
);
327 Ret
= GETPFNCLIENTW(i
);
332 Ret
= Class
->lpfnWndProc
;
334 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
338 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
339 Ret
= GETPFNCLIENTA(Class
->fnid
);
343 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
344 Ret
= GETPFNCLIENTW(Class
->fnid
);
348 if ( Ret
!= Class
->lpfnWndProc
||
349 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
352 gcpd
= (WNDPROC
)UserGetCPD( Class
,
353 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
356 return (gcpd
? gcpd
: Ret
);
362 IntSetClassWndProc(IN OUT PCLS Class
,
368 WNDPROC Ret
, chWndProc
;
370 Ret
= IntGetClassWndProc(Class
, Ansi
);
372 // If Server Side, downgrade to Client Side.
373 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
375 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
376 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
377 Class
->Unicode
= !Ansi
;
380 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
384 // Check if CallProc handle and retrieve previous call proc address and set.
385 if (IsCallProcHandle(WndProc
))
387 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
388 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
391 Class
->lpfnWndProc
= chWndProc
;
396 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
397 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
399 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
401 chWndProc
= GETPFNSERVER(i
);
404 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
406 chWndProc
= GETPFNSERVER(i
);
410 // If match, set/reset to Server Side and clear ansi.
413 Class
->lpfnWndProc
= chWndProc
;
414 Class
->Unicode
= TRUE
;
415 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
416 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
420 Class
->Unicode
= !Ansi
;
423 Class
->CSF_flags
|= CSF_ANSIPROC
;
425 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
428 /* update the clones */
429 chWndProc
= Class
->lpfnWndProc
;
431 Class
= Class
->pclsClone
;
432 while (Class
!= NULL
)
434 Class
->Unicode
= !Ansi
;
435 Class
->lpfnWndProc
= chWndProc
;
437 Class
= Class
->pclsNext
;
444 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
445 IN OUT PCLS
*ClassLink
,
451 ASSERT(Desktop
!= NULL
);
452 ASSERT(BaseClass
->pclsBase
== BaseClass
);
454 if (BaseClass
->rpdeskParent
== Desktop
)
456 /* it is most likely that a window is created on the same
457 desktop as the window class. */
462 if (BaseClass
->rpdeskParent
== NULL
)
464 ASSERT(BaseClass
->cWndReferenceCount
== 0);
465 ASSERT(BaseClass
->pclsClone
== NULL
);
467 /* Classes are also located in the shared heap when the class
468 was created before the thread attached to a desktop. As soon
469 as a window is created for such a class located on the shared
470 heap, the class is cloned into the desktop heap on which the
471 window is created. */
476 /* The user is asking for a class object on a different desktop,
478 Class
= BaseClass
->pclsClone
;
479 while (Class
!= NULL
)
481 if (Class
->rpdeskParent
== Desktop
)
483 ASSERT(Class
->pclsBase
== BaseClass
);
484 ASSERT(Class
->pclsClone
== NULL
);
488 Class
= Class
->pclsNext
;
494 /* The window is created on a different desktop, we need to
495 clone the class object to the desktop heap of the window! */
496 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
498 Class
= DesktopHeapAlloc(Desktop
,
502 /* simply clone the class */
503 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
505 TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
507 /* restore module address if default user class Ref: Bug 4778 */
508 if ( Class
->hModule
!= hModClient
&&
509 Class
->fnid
<= FNID_GHOST
&&
510 Class
->fnid
>= FNID_BUTTON
)
512 Class
->hModule
= hModClient
;
513 TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class
, Class
->hModule
);
516 /* update some pointers and link the class */
517 Class
->rpdeskParent
= Desktop
;
518 Class
->cWndReferenceCount
= 0;
520 if (BaseClass
->rpdeskParent
== NULL
)
522 /* we don't really need the base class on the shared
523 heap anymore, delete it so the only class left is
524 the clone we just created, which now serves as the
526 ASSERT(BaseClass
->pclsClone
== NULL
);
527 ASSERT(Class
->pclsClone
== NULL
);
528 Class
->pclsBase
= Class
;
529 Class
->pclsNext
= BaseClass
->pclsNext
;
531 /* replace the base class */
532 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
535 /* destroy the obsolete copy on the shared heap */
536 BaseClass
->pclsBase
= NULL
;
537 BaseClass
->pclsClone
= NULL
;
538 IntDestroyClass(BaseClass
);
542 /* link in the clone */
543 Class
->pclsClone
= NULL
;
544 Class
->pclsBase
= BaseClass
;
545 Class
->pclsNext
= BaseClass
->pclsClone
;
546 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
552 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
559 IntReferenceClass(IN OUT PCLS BaseClass
,
560 IN OUT PCLS
*ClassLink
,
564 ASSERT(BaseClass
->pclsBase
== BaseClass
);
566 Class
= IntGetClassForDesktop(BaseClass
,
571 Class
->cWndReferenceCount
++;
579 IntMakeCloneBaseClass(IN OUT PCLS Class
,
580 IN OUT PCLS
*BaseClassLink
,
581 IN OUT PCLS
*CloneLink
)
585 ASSERT(Class
->pclsBase
!= Class
);
586 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
587 ASSERT(Class
->rpdeskParent
!= NULL
);
588 ASSERT(Class
->cWndReferenceCount
!= 0);
589 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
590 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
592 /* unlink the clone */
593 *CloneLink
= Class
->pclsNext
;
594 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
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 TRACE("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 TRACE("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 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
827 EngSetLastError(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 TRACE("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 ERR("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 ERR("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 ERR("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 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1024 if (pszMenuName
!= NULL
)
1025 UserHeapFree(pszMenuName
);
1027 IntDeregisterClassAtom(Atom
);
1029 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1032 TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
1033 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1039 IntFindClass(IN RTL_ATOM Atom
,
1040 IN HINSTANCE hInstance
,
1042 OUT PCLS
**Link OPTIONAL
)
1044 PCLS Class
, *PrevLink
= ClassList
;
1047 while (Class
!= NULL
)
1049 if (Class
->atomClassName
== Atom
&&
1050 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1051 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1053 ASSERT(Class
->pclsBase
== Class
);
1060 PrevLink
= &Class
->pclsNext
;
1061 Class
= Class
->pclsNext
;
1068 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1073 if (ClassName
->Length
!= 0)
1079 /* NOTE: Caller has to protect the call with SEH! */
1081 if (ClassName
->Length
!= 0)
1083 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1084 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1086 EngSetLastError(ERROR_INVALID_PARAMETER
);
1090 /* We need to make a local copy of the class name! The caller could
1091 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1092 We're protected by SEH, but the ranges that might be accessed were
1094 RtlCopyMemory(szBuf
,
1097 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1101 AtomName
= ClassName
->Buffer
;
1103 /* lookup the atom */
1104 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1107 if (NT_SUCCESS(Status
))
1113 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1115 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1119 SetLastNtError(Status
);
1125 ASSERT(IS_ATOM(ClassName
->Buffer
));
1126 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1134 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1135 IN HINSTANCE hInstance OPTIONAL
,
1136 IN PPROCESSINFO pi OPTIONAL
,
1137 OUT PCLS
*BaseClass OPTIONAL
,
1138 OUT PCLS
**Link OPTIONAL
)
1140 RTL_ATOM Atom
= (RTL_ATOM
)0;
1142 ASSERT(BaseClass
!= NULL
);
1144 if (IntGetAtomFromStringOrAtom(ClassName
,
1146 Atom
!= (RTL_ATOM
)0)
1150 /* attempt to locate the class object */
1154 /* Step 1: try to find an exact match of locally registered classes */
1155 Class
= IntFindClass(Atom
,
1157 &pi
->pclsPrivateList
,
1160 { TRACE("Step 1: 0x%x\n",Class
);
1164 /* Step 2: try to find any globally registered class. The hInstance
1165 is not relevant for global classes */
1166 Class
= IntFindClass(Atom
,
1168 &pi
->pclsPublicList
,
1171 { TRACE("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1175 /* Step 3: try to find any local class registered by user32 */
1176 Class
= IntFindClass(Atom
,
1178 &pi
->pclsPrivateList
,
1181 { TRACE("Step 3: 0x%x\n",Class
);
1185 /* Step 4: try to find any global class registered by user32 */
1186 Class
= IntFindClass(Atom
,
1188 &pi
->pclsPublicList
,
1192 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1194 }else{TRACE("Step 4: 0x%x\n",Class
);}
1204 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
)
1206 PCLS
*ClassLink
, Class
= NULL
;
1210 pti
= PsGetCurrentThreadWin32Thread();
1212 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1214 UserRegisterSystemClasses();
1217 /* Check the class. */
1219 TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName
, hInstance
);
1221 ClassAtom
= IntGetClassAtom(ClassName
,
1227 if (ClassAtom
== (RTL_ATOM
)0)
1229 if (IS_ATOM(ClassName
->Buffer
))
1231 ERR("Class 0x%p not found\n", (DWORD_PTR
) ClassName
->Buffer
);
1235 ERR("Class \"%wZ\" not found\n", ClassName
);
1238 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1242 TRACE("Referencing Class 0x%x with atom 0x%x\n", Class
, ClassAtom
);
1243 Class
= IntReferenceClass(Class
,
1248 ERR("Failed to reference window class!\n");
1256 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1257 IN PUNICODE_STRING ClassName
,
1258 IN PUNICODE_STRING MenuName
,
1266 RTL_ATOM Ret
= (RTL_ATOM
)0;
1268 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1270 pti
= GetW32ThreadInfo();
1274 // Need only to test for two conditions not four....... Fix more whine tests....
1275 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1276 ClassAtom
!= (RTL_ATOM
)0 &&
1277 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1279 Class
= IntFindClass( ClassAtom
,
1281 &pi
->pclsPrivateList
,
1284 if (Class
!= NULL
&& !Class
->Global
)
1286 // local class already exists
1287 TRACE("Local Class 0x%p does already exist!\n", ClassAtom
);
1288 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1292 if (lpwcx
->style
& CS_GLOBALCLASS
)
1294 /* HACK: allow global classes to be re-registered*/
1295 Class
= IntFindClass( ClassAtom
,
1297 &pi
->pclsPublicList
,
1300 if (Class
!= NULL
&& Class
->Global
)
1302 TRACE("Global Class 0x%p does already exist!\n", ClassAtom
);
1303 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1309 Class
= IntCreateClass(lpwcx
,
1321 /* Register the class */
1323 List
= &pi
->pclsPublicList
;
1325 List
= &pi
->pclsPrivateList
;
1327 Class
->pclsNext
= *List
;
1328 (void)InterlockedExchangePointer((PVOID
*)List
,
1331 Ret
= Class
->atomClassName
;
1335 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1342 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1343 IN HINSTANCE hInstance
,
1344 OUT PCLSMENUNAME pClassMenuName
)
1351 pi
= GetW32ProcessInfo();
1353 TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1355 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1356 ClassAtom
= IntGetClassAtom(ClassName
,
1361 if (ClassAtom
== (RTL_ATOM
)0)
1363 TRACE("UserUnregisterClass: No Class found.\n");
1367 ASSERT(Class
!= NULL
);
1369 if (Class
->cWndReferenceCount
!= 0 ||
1370 Class
->pclsClone
!= NULL
)
1372 TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1373 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1377 /* must be a base class! */
1378 ASSERT(Class
->pclsBase
== Class
);
1380 /* unlink the class */
1381 *Link
= Class
->pclsNext
;
1383 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1385 TRACE("Class 0x%x\n", Class
);
1386 TRACE("UserUnregisterClass: Good Exit!\n");
1387 /* finally free the resources */
1388 IntDestroyClass(Class
);
1391 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1396 UserGetClassName(IN PCLS Class
,
1397 IN OUT PUNICODE_STRING ClassName
,
1401 NTSTATUS Status
= STATUS_SUCCESS
;
1402 WCHAR szStaticTemp
[32];
1403 PWSTR szTemp
= NULL
;
1404 ULONG BufLen
= sizeof(szStaticTemp
);
1407 /* Note: Accessing the buffer in ClassName may raise an exception! */
1413 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1414 UNICODE_STRING UnicodeClassName
;
1416 /* limit the size of the static buffer on the stack to the
1417 size of the buffer provided by the caller */
1418 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1420 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1423 /* find out how big the buffer needs to be */
1424 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1425 Class
->atomClassName
,
1430 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1432 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1434 /* the buffer required exceeds the ansi buffer provided,
1435 pretend like we're using the ansi buffer and limit the
1436 size to the buffer size provided */
1437 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1440 /* allocate a temporary buffer that can hold the unicode class name */
1441 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1446 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1450 /* query the class name */
1451 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1452 Atom
? Atom
: Class
->atomClassName
,
1459 szTemp
= szStaticTemp
;
1461 if (NT_SUCCESS(Status
))
1463 /* convert the atom name to ansi */
1465 RtlInitUnicodeString(&UnicodeClassName
,
1468 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1471 if (!NT_SUCCESS(Status
))
1473 SetLastNtError(Status
);
1478 Ret
= BufLen
/ sizeof(WCHAR
);
1482 BufLen
= ClassName
->MaximumLength
;
1484 /* query the atom name */
1485 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1486 Atom
? Atom
: Class
->atomClassName
,
1492 if (!NT_SUCCESS(Status
))
1494 SetLastNtError(Status
);
1498 Ret
= BufLen
/ sizeof(WCHAR
);
1501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1503 SetLastNtError(_SEH2_GetExceptionCode());
1507 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1516 IntSetClassMenuName(IN PCLS Class
,
1517 IN PUNICODE_STRING MenuName
)
1521 /* change the base class first */
1522 Class
= Class
->pclsBase
;
1524 if (MenuName
->Length
!= 0)
1526 ANSI_STRING AnsiString
;
1529 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1531 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1532 AnsiString
.MaximumLength
);
1533 if (strBufW
!= NULL
)
1539 /* copy the unicode string */
1540 RtlCopyMemory(strBufW
,
1543 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1545 /* create an ansi copy of the string */
1546 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1547 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1550 if (!NT_SUCCESS(Status
))
1552 SetLastNtError(Status
);
1558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1560 SetLastNtError(_SEH2_GetExceptionCode());
1566 /* update the base class */
1567 IntFreeClassMenuName(Class
);
1568 Class
->lpszClientUnicodeMenuName
= strBufW
;
1569 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1570 Class
->MenuNameIsString
= TRUE
;
1572 /* update the clones */
1573 Class
= Class
->pclsClone
;
1574 while (Class
!= NULL
)
1576 Class
->lpszClientUnicodeMenuName
= strBufW
;
1577 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1578 Class
->MenuNameIsString
= TRUE
;
1580 Class
= Class
->pclsNext
;
1585 ERR("Failed to copy class menu name!\n");
1586 UserHeapFree(strBufW
);
1590 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1594 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1596 /* update the base class */
1597 IntFreeClassMenuName(Class
);
1598 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1599 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1600 Class
->MenuNameIsString
= FALSE
;
1602 /* update the clones */
1603 Class
= Class
->pclsClone
;
1604 while (Class
!= NULL
)
1606 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1607 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1608 Class
->MenuNameIsString
= FALSE
;
1610 Class
= Class
->pclsNext
;
1620 UserSetClassLongPtr(IN PCLS Class
,
1622 IN ULONG_PTR NewLong
,
1627 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1629 /* change the information in the base class first, then update the clones */
1630 Class
= Class
->pclsBase
;
1636 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1638 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1639 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1641 EngSetLastError(ERROR_INVALID_PARAMETER
);
1645 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1647 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1648 certain architectures, maybe using RtlCopyMemory is a
1649 better choice for those architectures! */
1653 /* update the clones */
1654 Class
= Class
->pclsClone
;
1655 while (Class
!= NULL
)
1657 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1658 Class
= Class
->pclsNext
;
1666 case GCL_CBWNDEXTRA
:
1667 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1668 Class
->cbwndExtra
= (INT
)NewLong
;
1670 /* update the clones */
1671 Class
= Class
->pclsClone
;
1672 while (Class
!= NULL
)
1674 Class
->cbwndExtra
= (INT
)NewLong
;
1675 Class
= Class
->pclsNext
;
1680 case GCL_CBCLSEXTRA
:
1681 EngSetLastError(ERROR_INVALID_PARAMETER
);
1684 case GCLP_HBRBACKGROUND
:
1685 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1686 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1688 /* update the clones */
1689 Class
= Class
->pclsClone
;
1690 while (Class
!= NULL
)
1692 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1693 Class
= Class
->pclsNext
;
1698 /* FIXME - get handle from pointer to CURSOR object */
1699 Ret
= (ULONG_PTR
)Class
->hCursor
;
1700 Class
->hCursor
= (HANDLE
)NewLong
;
1702 /* update the clones */
1703 Class
= Class
->pclsClone
;
1704 while (Class
!= NULL
)
1706 Class
->hCursor
= (HANDLE
)NewLong
;
1707 Class
= Class
->pclsNext
;
1712 /* FIXME - get handle from pointer to ICON object */
1713 Ret
= (ULONG_PTR
)Class
->hIcon
;
1714 Class
->hIcon
= (HANDLE
)NewLong
;
1716 /* update the clones */
1717 Class
= Class
->pclsClone
;
1718 while (Class
!= NULL
)
1720 Class
->hIcon
= (HANDLE
)NewLong
;
1721 Class
= Class
->pclsNext
;
1726 /* FIXME - get handle from pointer to ICON object */
1727 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1728 Class
->hIconSm
= (HANDLE
)NewLong
;
1730 /* update the clones */
1731 Class
= Class
->pclsClone
;
1732 while (Class
!= NULL
)
1734 Class
->hIconSm
= (HANDLE
)NewLong
;
1735 Class
= Class
->pclsNext
;
1740 Ret
= (ULONG_PTR
)Class
->hModule
;
1741 Class
->hModule
= (HINSTANCE
)NewLong
;
1743 /* update the clones */
1744 Class
= Class
->pclsClone
;
1745 while (Class
!= NULL
)
1747 Class
->hModule
= (HINSTANCE
)NewLong
;
1748 Class
= Class
->pclsNext
;
1754 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1756 if (!IntSetClassMenuName(Class
,
1759 ERR("Setting the class menu name failed!\n");
1762 /* FIXME - really return NULL? Wine does so... */
1767 Ret
= (ULONG_PTR
)Class
->style
;
1768 Class
->style
= (UINT
)NewLong
;
1770 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1771 move the class to the appropriate list? For now, we save
1772 the original value in Class->Global, so we can always
1773 locate the appropriate list */
1775 /* update the clones */
1776 Class
= Class
->pclsClone
;
1777 while (Class
!= NULL
)
1779 Class
->style
= (UINT
)NewLong
;
1780 Class
= Class
->pclsNext
;
1785 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1792 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1794 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1795 if (!IntSetClassAtom(Class
,
1804 EngSetLastError(ERROR_INVALID_INDEX
);
1812 UserGetClassInfo(IN PCLS Class
,
1813 OUT PWNDCLASSEXW lpwcx
,
1815 HINSTANCE hInstance
)
1817 if (!Class
) return FALSE
;
1819 lpwcx
->style
= Class
->style
;
1821 // If fnId is set, clear the global bit. See wine class test check_style.
1823 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1825 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1827 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1828 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1829 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1830 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1831 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1833 /* Copy non-string to user first. */
1835 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1837 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1839 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1840 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1841 lpszClientXxxMenuName should already be mapped to user space.
1843 /* Copy string ptr to user. */
1844 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1845 Class
->MenuNameIsString
)
1847 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1848 (PVOID
)Class
->lpszClientAnsiMenuName
:
1849 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1852 if (hInstance
== hModClient
)
1853 lpwcx
->hInstance
= NULL
;
1855 lpwcx
->hInstance
= hInstance
;
1857 /* FIXME - return the string? Okay! This is performed in User32!*/
1858 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1860 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1870 UserRegisterSystemClasses(VOID
)
1873 UNICODE_STRING ClassName
, MenuName
;
1874 PPROCESSINFO ppi
= GetW32ProcessInfo();
1880 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1883 if ( hModClient
== NULL
)
1886 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1887 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1889 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1891 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1893 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1897 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1898 ClassName
.Length
= 0;
1899 ClassName
.MaximumLength
= 0;
1902 wc
.cbSize
= sizeof(wc
);
1903 wc
.style
= DefaultServerClasses
[i
].Style
;
1905 Flags
|= CSF_SERVERSIDEPROC
;
1907 if (DefaultServerClasses
[i
].ProcW
)
1909 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1910 wc
.hInstance
= hModuleWin
;
1914 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1915 wc
.hInstance
= hModClient
;
1919 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1921 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1922 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1923 wc
.lpszMenuName
= NULL
;
1924 wc
.lpszClassName
= ClassName
.Buffer
;
1927 Class
= IntCreateClass( &wc
,
1930 DefaultServerClasses
[i
].fiId
,
1936 Class
->pclsNext
= ppi
->pclsPublicList
;
1937 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1940 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1944 ERR("!!! Registering system class failed!\n");
1948 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1952 /* SYSCALLS *****************************************************************/
1956 NtUserRegisterClassExWOW(
1958 PUNICODE_STRING ClassName
,
1959 PUNICODE_STRING ClsNVersion
,
1960 PCLSMENUNAME pClassMenuName
,
1966 * Registers a new class with the window manager
1968 * lpwcx = Win32 extended window class structure
1969 * bUnicodeClass = Whether to send ANSI or unicode strings
1970 * to window procedures
1972 * Atom identifying the new class
1975 WNDCLASSEXW CapturedClassInfo
= {0};
1976 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1977 RTL_ATOM Ret
= (RTL_ATOM
)0;
1978 PPROCESSINFO ppi
= GetW32ProcessInfo();
1980 if (Flags
& ~(CSF_ANSIPROC
))
1982 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
1983 EngSetLastError(ERROR_INVALID_FLAGS
);
1987 UserEnterExclusive();
1989 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
1991 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1993 UserRegisterSystemClasses();
1998 /* Probe the parameters and basic parameter checks */
1999 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2001 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2002 goto InvalidParameter
;
2006 sizeof(WNDCLASSEXW
),
2008 RtlCopyMemory(&CapturedClassInfo
,
2010 sizeof(WNDCLASSEXW
));
2012 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2014 ProbeForRead(pClassMenuName
,
2015 sizeof(CLSMENUNAME
),
2018 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2020 if ( CapturedName
.Length
& 1 ||
2021 CapturedMenuName
.Length
& 1 ||
2022 CapturedClassInfo
.cbClsExtra
< 0 ||
2023 CapturedClassInfo
.cbClsExtra
+
2024 CapturedName
.Length
+
2025 CapturedMenuName
.Length
+
2026 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2027 CapturedClassInfo
.cbWndExtra
< 0 ||
2028 CapturedClassInfo
.hInstance
== NULL
)
2030 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2031 goto InvalidParameter
;
2034 if (CapturedName
.Length
!= 0)
2036 ProbeForRead(CapturedName
.Buffer
,
2037 CapturedName
.Length
,
2042 if (!IS_ATOM(CapturedName
.Buffer
))
2044 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2045 goto InvalidParameter
;
2049 if (CapturedMenuName
.Length
!= 0)
2051 ProbeForRead(CapturedMenuName
.Buffer
,
2052 CapturedMenuName
.Length
,
2055 else if (CapturedMenuName
.Buffer
!= NULL
&&
2056 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2058 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2060 EngSetLastError(ERROR_INVALID_PARAMETER
);
2064 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2065 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2066 // If this pops up we know what todo!
2067 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2070 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2072 /* Register the class */
2073 Ret
= UserRegisterClass(&CapturedClassInfo
,
2079 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2081 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2082 SetLastNtError(_SEH2_GetExceptionCode());
2088 ERR("NtUserRegisterClassExWOW Null Return!\n");
2097 NtUserSetClassLong(HWND hWnd
,
2099 ULONG_PTR dwNewLong
,
2106 UserEnterExclusive();
2108 pi
= GetW32ProcessInfo();
2110 Window
= UserGetWindowObject(hWnd
);
2113 if (Window
->head
.pti
->ppi
!= pi
)
2115 EngSetLastError(ERROR_ACCESS_DENIED
);
2121 UNICODE_STRING Value
;
2123 /* probe the parameters */
2124 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2126 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2127 if (Value
.Length
& 1)
2129 goto InvalidParameter
;
2132 if (Value
.Length
!= 0)
2134 ProbeForRead(Value
.Buffer
,
2140 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2142 goto InvalidParameter
;
2144 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2147 EngSetLastError(ERROR_INVALID_PARAMETER
);
2152 dwNewLong
= (ULONG_PTR
)&Value
;
2155 Ret
= UserSetClassLongPtr(Window
->pcls
,
2160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2162 SetLastNtError(_SEH2_GetExceptionCode());
2181 * NOTE: Obsoleted in 32-bit windows
2187 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2188 IN HINSTANCE hInstance
,
2189 OUT PCLSMENUNAME pClassMenuName
)
2191 UNICODE_STRING CapturedClassName
;
2194 UserEnterExclusive();
2198 /* probe the paramters */
2199 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2200 if (CapturedClassName
.Length
& 1)
2202 goto InvalidParameter
;
2205 if (CapturedClassName
.Length
!= 0)
2207 ProbeForRead(CapturedClassName
.Buffer
,
2208 CapturedClassName
.Length
,
2213 if (!IS_ATOM(CapturedClassName
.Buffer
))
2216 EngSetLastError(ERROR_INVALID_PARAMETER
);
2221 /* unregister the class */
2222 Ret
= UserUnregisterClass(&CapturedClassName
,
2224 NULL
); // Null for now~
2226 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2228 SetLastNtError(_SEH2_GetExceptionCode());
2236 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2239 HINSTANCE hInstance
,
2240 PUNICODE_STRING ClassName
,
2241 LPWNDCLASSEXW lpWndClassEx
,
2242 LPWSTR
*ppszMenuName
,
2245 UNICODE_STRING CapturedClassName
, SafeClassName
;
2246 WNDCLASSEXW Safewcexw
;
2248 RTL_ATOM ClassAtom
= 0;
2252 /* NOTE: need exclusive lock because getting the wndproc might require the
2253 creation of a call procedure handle */
2254 UserEnterExclusive();
2256 ppi
= GetW32ProcessInfo();
2258 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2260 UserRegisterSystemClasses();
2265 /* probe the paramters */
2266 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2268 if (CapturedClassName
.Length
== 0)
2270 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2274 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2277 if (CapturedClassName
.Length
& 1)
2279 EngSetLastError(ERROR_INVALID_PARAMETER
);
2284 if (CapturedClassName
.Length
!= 0)
2286 ProbeForRead( CapturedClassName
.Buffer
,
2287 CapturedClassName
.Length
,
2290 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2292 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2293 SafeClassName
.MaximumLength
,
2295 RtlCopyMemory( SafeClassName
.Buffer
,
2296 CapturedClassName
.Buffer
,
2297 SafeClassName
.MaximumLength
);
2301 if (!IS_ATOM(CapturedClassName
.Buffer
))
2303 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2304 EngSetLastError(ERROR_INVALID_PARAMETER
);
2309 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2310 SafeClassName
.Length
= 0;
2311 SafeClassName
.MaximumLength
= 0;
2314 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2316 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2320 SetLastNtError(_SEH2_GetExceptionCode());
2325 // If null instance use client.
2326 if (!hInstance
) hInstance
= hModClient
;
2330 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName
, hInstance
);
2331 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2336 if (ClassAtom
!= (RTL_ATOM
)0)
2338 if (hInstance
== NULL
) hInstance
= hModClient
;
2340 Ret
= UserGetClassInfo( Class
,
2347 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2355 /* Emulate Function. */
2356 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2358 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2361 /* We must return the atom of the class here instead of just TRUE. */
2362 /* Undocumented behavior! Return the class atom as a BOOL! */
2363 Ret
= (BOOL
)ClassAtom
;
2366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2368 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2373 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2380 NtUserGetClassName (IN HWND hWnd
,
2382 OUT PUNICODE_STRING ClassName
)
2385 UNICODE_STRING CapturedClassName
;
2391 Window
= UserGetWindowObject(hWnd
);
2394 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2396 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2398 Atom
= gpsi
->atomSysClass
[iCls
];
2404 ProbeForWriteUnicodeString(ClassName
);
2405 CapturedClassName
= *ClassName
;
2407 /* get the class name */
2408 Ret
= UserGetClassName(Window
->pcls
,
2415 /* update the Length field */
2416 ClassName
->Length
= CapturedClassName
.Length
;
2419 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2421 SetLastNtError(_SEH2_GetExceptionCode());
2431 /* Return Pointer to Class structure. */
2433 NtUserGetWOWClass(HINSTANCE hInstance
,
2434 PUNICODE_STRING ClassName
)
2436 UNICODE_STRING SafeClassName
;
2439 RTL_ATOM ClassAtom
= 0;
2442 UserEnterExclusive();
2444 pi
= GetW32ProcessInfo();
2448 if (ClassName
->Length
!= 0)
2450 ProbeForRead( ClassName
->Buffer
,
2454 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2456 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2457 SafeClassName
.MaximumLength
,
2459 RtlCopyMemory( SafeClassName
.Buffer
,
2461 SafeClassName
.MaximumLength
);
2465 if (!IS_ATOM(ClassName
->Buffer
))
2467 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2472 SafeClassName
.Buffer
= ClassName
->Buffer
;
2473 SafeClassName
.Length
= 0;
2474 SafeClassName
.MaximumLength
= 0;
2478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2480 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2487 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2494 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2498 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2501 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.