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 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
)
1213 PCLS
*ClassLink
, Class
= NULL
;
1217 pti
= PsGetCurrentThreadWin32Thread();
1219 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1221 UserRegisterSystemClasses();
1224 /* Check the class. */
1226 DPRINT("Class %wZ\n", ClassName
);
1228 ClassAtom
= IntGetClassAtom(ClassName
,
1234 if (ClassAtom
== (RTL_ATOM
)0)
1236 if (IS_ATOM(ClassName
->Buffer
))
1238 DPRINT1("Class 0x%p not found\n", (DWORD_PTR
) ClassName
->Buffer
);
1242 DPRINT1("Class \"%wZ\" not found\n", ClassName
);
1245 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS
);
1248 DPRINT("ClassAtom %x\n", ClassAtom
);
1249 Class
= IntReferenceClass(Class
,
1254 DPRINT1("Failed to reference window class!\n");
1262 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1263 IN PUNICODE_STRING ClassName
,
1264 IN PUNICODE_STRING MenuName
,
1272 RTL_ATOM Ret
= (RTL_ATOM
)0;
1274 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1276 pti
= GetW32ThreadInfo();
1280 // Need only to test for two conditions not four....... Fix more whine tests....
1281 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1282 ClassAtom
!= (RTL_ATOM
)0 &&
1283 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1285 Class
= IntFindClass( ClassAtom
,
1287 &pi
->pclsPrivateList
,
1290 if (Class
!= NULL
&& !Class
->Global
)
1292 // local class already exists
1293 DPRINT("Local Class 0x%p does already exist!\n", ClassAtom
);
1294 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1298 if (lpwcx
->style
& CS_GLOBALCLASS
)
1300 Class
= IntFindClass( ClassAtom
,
1302 &pi
->pclsPublicList
,
1305 if (Class
!= NULL
&& Class
->Global
)
1307 DPRINT("Global Class 0x%p does already exist!\n", ClassAtom
);
1308 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1314 Class
= IntCreateClass(lpwcx
,
1326 /* Register the class */
1328 List
= &pi
->pclsPublicList
;
1330 List
= &pi
->pclsPrivateList
;
1332 Class
->pclsNext
= *List
;
1333 (void)InterlockedExchangePointer((PVOID
*)List
,
1336 Ret
= Class
->atomClassName
;
1340 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1347 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1348 IN HINSTANCE hInstance
,
1349 OUT PCLSMENUNAME pClassMenuName
)
1356 pi
= GetW32ProcessInfo();
1358 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1360 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1361 ClassAtom
= IntGetClassAtom(ClassName
,
1366 if (ClassAtom
== (RTL_ATOM
)0)
1368 DPRINT("UserUnregisterClass: No Class found.\n");
1372 ASSERT(Class
!= NULL
);
1374 if (Class
->cWndReferenceCount
!= 0 ||
1375 Class
->pclsClone
!= NULL
)
1377 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1378 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1382 /* must be a base class! */
1383 ASSERT(Class
->pclsBase
== Class
);
1385 /* unlink the class */
1386 *Link
= Class
->pclsNext
;
1388 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1390 DPRINT("Class 0x%x\n", Class
);
1391 DPRINT("UserUnregisterClass: Good Exit!\n");
1392 /* finally free the resources */
1393 IntDestroyClass(Class
);
1396 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1401 UserGetClassName(IN PCLS Class
,
1402 IN OUT PUNICODE_STRING ClassName
,
1405 NTSTATUS Status
= STATUS_SUCCESS
;
1406 WCHAR szStaticTemp
[32];
1407 PWSTR szTemp
= NULL
;
1408 ULONG BufLen
= sizeof(szStaticTemp
);
1411 /* Note: Accessing the buffer in ClassName may raise an exception! */
1417 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1418 UNICODE_STRING UnicodeClassName
;
1420 /* limit the size of the static buffer on the stack to the
1421 size of the buffer provided by the caller */
1422 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1424 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1427 /* find out how big the buffer needs to be */
1428 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1429 Class
->atomClassName
,
1434 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1436 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1438 /* the buffer required exceeds the ansi buffer provided,
1439 pretend like we're using the ansi buffer and limit the
1440 size to the buffer size provided */
1441 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1444 /* allocate a temporary buffer that can hold the unicode class name */
1445 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1450 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1454 /* query the class name */
1455 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1456 Class
->atomClassName
,
1463 szTemp
= szStaticTemp
;
1465 if (NT_SUCCESS(Status
))
1467 /* convert the atom name to ansi */
1469 RtlInitUnicodeString(&UnicodeClassName
,
1472 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1475 if (!NT_SUCCESS(Status
))
1477 SetLastNtError(Status
);
1482 Ret
= BufLen
/ sizeof(WCHAR
);
1486 BufLen
= ClassName
->MaximumLength
;
1488 /* query the atom name */
1489 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1490 Class
->atomClassName
,
1496 if (!NT_SUCCESS(Status
))
1498 SetLastNtError(Status
);
1502 Ret
= BufLen
/ sizeof(WCHAR
);
1505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1507 SetLastNtError(_SEH2_GetExceptionCode());
1511 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1520 IntSetClassMenuName(IN PCLS Class
,
1521 IN PUNICODE_STRING MenuName
)
1525 /* change the base class first */
1526 Class
= Class
->pclsBase
;
1528 if (MenuName
->Length
!= 0)
1530 ANSI_STRING AnsiString
;
1533 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1535 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1536 AnsiString
.MaximumLength
);
1537 if (strBufW
!= NULL
)
1543 /* copy the unicode string */
1544 RtlCopyMemory(strBufW
,
1547 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1549 /* create an ansi copy of the string */
1550 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1551 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1554 if (!NT_SUCCESS(Status
))
1556 SetLastNtError(Status
);
1562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1564 SetLastNtError(_SEH2_GetExceptionCode());
1570 /* update the base class */
1571 IntFreeClassMenuName(Class
);
1572 Class
->lpszClientUnicodeMenuName
= strBufW
;
1573 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1574 Class
->MenuNameIsString
= TRUE
;
1576 /* update the clones */
1577 Class
= Class
->pclsClone
;
1578 while (Class
!= NULL
)
1580 Class
->lpszClientUnicodeMenuName
= strBufW
;
1581 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1582 Class
->MenuNameIsString
= TRUE
;
1584 Class
= Class
->pclsNext
;
1589 DPRINT1("Failed to copy class menu name!\n");
1590 UserHeapFree(strBufW
);
1594 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1598 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1600 /* update the base class */
1601 IntFreeClassMenuName(Class
);
1602 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1603 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1604 Class
->MenuNameIsString
= FALSE
;
1606 /* update the clones */
1607 Class
= Class
->pclsClone
;
1608 while (Class
!= NULL
)
1610 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1611 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1612 Class
->MenuNameIsString
= FALSE
;
1614 Class
= Class
->pclsNext
;
1624 UserSetClassLongPtr(IN PCLS Class
,
1626 IN ULONG_PTR NewLong
,
1631 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1633 /* change the information in the base class first, then update the clones */
1634 Class
= Class
->pclsBase
;
1640 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1642 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1643 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1645 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1649 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1651 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1652 certain architectures, maybe using RtlCopyMemory is a
1653 better choice for those architectures! */
1657 /* update the clones */
1658 Class
= Class
->pclsClone
;
1659 while (Class
!= NULL
)
1661 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1662 Class
= Class
->pclsNext
;
1670 case GCL_CBWNDEXTRA
:
1671 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1672 Class
->cbwndExtra
= (INT
)NewLong
;
1674 /* update the clones */
1675 Class
= Class
->pclsClone
;
1676 while (Class
!= NULL
)
1678 Class
->cbwndExtra
= (INT
)NewLong
;
1679 Class
= Class
->pclsNext
;
1684 case GCL_CBCLSEXTRA
:
1685 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1688 case GCLP_HBRBACKGROUND
:
1689 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1690 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1692 /* update the clones */
1693 Class
= Class
->pclsClone
;
1694 while (Class
!= NULL
)
1696 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1697 Class
= Class
->pclsNext
;
1702 /* FIXME - get handle from pointer to CURSOR object */
1703 Ret
= (ULONG_PTR
)Class
->hCursor
;
1704 Class
->hCursor
= (HANDLE
)NewLong
;
1706 /* update the clones */
1707 Class
= Class
->pclsClone
;
1708 while (Class
!= NULL
)
1710 Class
->hCursor
= (HANDLE
)NewLong
;
1711 Class
= Class
->pclsNext
;
1716 /* FIXME - get handle from pointer to ICON object */
1717 Ret
= (ULONG_PTR
)Class
->hIcon
;
1718 Class
->hIcon
= (HANDLE
)NewLong
;
1720 /* update the clones */
1721 Class
= Class
->pclsClone
;
1722 while (Class
!= NULL
)
1724 Class
->hIcon
= (HANDLE
)NewLong
;
1725 Class
= Class
->pclsNext
;
1730 /* FIXME - get handle from pointer to ICON object */
1731 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1732 Class
->hIconSm
= (HANDLE
)NewLong
;
1734 /* update the clones */
1735 Class
= Class
->pclsClone
;
1736 while (Class
!= NULL
)
1738 Class
->hIconSm
= (HANDLE
)NewLong
;
1739 Class
= Class
->pclsNext
;
1744 Ret
= (ULONG_PTR
)Class
->hModule
;
1745 Class
->hModule
= (HINSTANCE
)NewLong
;
1747 /* update the clones */
1748 Class
= Class
->pclsClone
;
1749 while (Class
!= NULL
)
1751 Class
->hModule
= (HINSTANCE
)NewLong
;
1752 Class
= Class
->pclsNext
;
1758 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1760 if (!IntSetClassMenuName(Class
,
1763 DPRINT1("Setting the class menu name failed!\n");
1766 /* FIXME - really return NULL? Wine does so... */
1771 Ret
= (ULONG_PTR
)Class
->style
;
1772 Class
->style
= (UINT
)NewLong
;
1774 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1775 move the class to the appropriate list? For now, we save
1776 the original value in Class->Global, so we can always
1777 locate the appropriate list */
1779 /* update the clones */
1780 Class
= Class
->pclsClone
;
1781 while (Class
!= NULL
)
1783 Class
->style
= (UINT
)NewLong
;
1784 Class
= Class
->pclsNext
;
1789 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1796 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1798 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1799 if (!IntSetClassAtom(Class
,
1808 SetLastWin32Error(ERROR_INVALID_INDEX
);
1816 UserGetClassInfo(IN PCLS Class
,
1817 OUT PWNDCLASSEXW lpwcx
,
1819 HINSTANCE hInstance
)
1823 if (!Class
) return FALSE
;
1825 lpwcx
->style
= Class
->style
;
1827 // If fnId is set, clear the global bit. See wine class test check_style.
1829 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1831 pi
= GetW32ProcessInfo();
1833 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1835 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1836 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1837 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1838 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1839 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1841 /* Copy non-string to user first. */
1843 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1845 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1847 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1848 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1849 lpszClientXxxMenuName should already be mapped to user space.
1851 /* Copy string ptr to user. */
1852 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1853 Class
->MenuNameIsString
)
1855 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1856 (PVOID
)Class
->lpszClientAnsiMenuName
:
1857 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1860 if (hInstance
== hModClient
)
1861 lpwcx
->hInstance
= NULL
;
1863 lpwcx
->hInstance
= hInstance
;
1865 /* FIXME - return the string? Okay! This is performed in User32!*/
1866 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1868 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1878 UserRegisterSystemClasses(VOID
)
1881 UNICODE_STRING ClassName
, MenuName
;
1882 PPROCESSINFO ppi
= GetW32ProcessInfo();
1888 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1891 if ( hModClient
== NULL
)
1894 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1895 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1897 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1899 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1901 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1905 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1906 ClassName
.Length
= 0;
1907 ClassName
.MaximumLength
= 0;
1910 wc
.cbSize
= sizeof(wc
);
1911 wc
.style
= DefaultServerClasses
[i
].Style
;
1913 Flags
|= CSF_SERVERSIDEPROC
;
1915 if (DefaultServerClasses
[i
].ProcW
)
1917 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1918 wc
.hInstance
= hModuleWin
;
1922 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1923 wc
.hInstance
= hModClient
;
1927 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1929 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1930 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1931 wc
.lpszMenuName
= NULL
;
1932 wc
.lpszClassName
= ClassName
.Buffer
;
1935 Class
= IntCreateClass( &wc
,
1938 DefaultServerClasses
[i
].fiId
,
1944 Class
->pclsNext
= ppi
->pclsPublicList
;
1945 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1948 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1952 WARN("!!! Registering system class failed!\n");
1956 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1960 /* SYSCALLS *****************************************************************/
1964 NtUserRegisterClassExWOW(
1966 PUNICODE_STRING ClassName
,
1967 PUNICODE_STRING ClsNVersion
,
1968 PCLSMENUNAME pClassMenuName
,
1974 * Registers a new class with the window manager
1976 * lpwcx = Win32 extended window class structure
1977 * bUnicodeClass = Whether to send ANSI or unicode strings
1978 * to window procedures
1980 * Atom identifying the new class
1983 WNDCLASSEXW CapturedClassInfo
= {0};
1984 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1985 RTL_ATOM Ret
= (RTL_ATOM
)0;
1986 PPROCESSINFO ppi
= GetW32ProcessInfo();
1988 if (Flags
& ~(CSF_ANSIPROC
))
1990 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
1991 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1995 UserEnterExclusive();
1997 DPRINT("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
1999 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2001 UserRegisterSystemClasses();
2006 /* Probe the parameters and basic parameter checks */
2007 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2009 DPRINT1("NtUserRegisterClassExWOW Wrong cbSize!\n");
2010 goto InvalidParameter
;
2014 sizeof(WNDCLASSEXW
),
2016 RtlCopyMemory(&CapturedClassInfo
,
2018 sizeof(WNDCLASSEXW
));
2020 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2022 ProbeForRead(pClassMenuName
,
2023 sizeof(CLSMENUNAME
),
2026 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2028 if ( CapturedName
.Length
& 1 ||
2029 CapturedMenuName
.Length
& 1 ||
2030 CapturedClassInfo
.cbClsExtra
< 0 ||
2031 CapturedClassInfo
.cbClsExtra
+
2032 CapturedName
.Length
+
2033 CapturedMenuName
.Length
+
2034 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2035 CapturedClassInfo
.cbWndExtra
< 0 ||
2036 CapturedClassInfo
.hInstance
== NULL
)
2038 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2039 goto InvalidParameter
;
2042 if (CapturedName
.Length
!= 0)
2044 ProbeForRead(CapturedName
.Buffer
,
2045 CapturedName
.Length
,
2050 if (!IS_ATOM(CapturedName
.Buffer
))
2052 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2053 goto InvalidParameter
;
2057 if (CapturedMenuName
.Length
!= 0)
2059 ProbeForRead(CapturedMenuName
.Buffer
,
2060 CapturedMenuName
.Length
,
2063 else if (CapturedMenuName
.Buffer
!= NULL
&&
2064 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2066 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2068 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2072 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2073 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2074 // If this pops up we know what todo!
2075 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2078 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2080 /* Register the class */
2081 Ret
= UserRegisterClass(&CapturedClassInfo
,
2087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2089 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2090 SetLastNtError(_SEH2_GetExceptionCode());
2096 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2105 NtUserSetClassLong(HWND hWnd
,
2107 ULONG_PTR dwNewLong
,
2111 PWINDOW_OBJECT Window
;
2114 UserEnterExclusive();
2116 pi
= GetW32ProcessInfo();
2118 Window
= UserGetWindowObject(hWnd
);
2121 if (Window
->pti
->ppi
!= pi
)
2123 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2129 UNICODE_STRING Value
;
2131 /* probe the parameters */
2132 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2134 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2135 if (Value
.Length
& 1)
2137 goto InvalidParameter
;
2140 if (Value
.Length
!= 0)
2142 ProbeForRead(Value
.Buffer
,
2148 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2150 goto InvalidParameter
;
2152 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2155 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2160 dwNewLong
= (ULONG_PTR
)&Value
;
2163 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2170 SetLastNtError(_SEH2_GetExceptionCode());
2189 * NOTE: Obsoleted in 32-bit windows
2195 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2196 IN HINSTANCE hInstance
,
2197 OUT PCLSMENUNAME pClassMenuName
)
2199 UNICODE_STRING CapturedClassName
;
2202 UserEnterExclusive();
2206 /* probe the paramters */
2207 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2208 if (CapturedClassName
.Length
& 1)
2210 goto InvalidParameter
;
2213 if (CapturedClassName
.Length
!= 0)
2215 ProbeForRead(CapturedClassName
.Buffer
,
2216 CapturedClassName
.Length
,
2221 if (!IS_ATOM(CapturedClassName
.Buffer
))
2224 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2229 /* unregister the class */
2230 Ret
= UserUnregisterClass(&CapturedClassName
,
2232 NULL
); // Null for now~
2234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2236 SetLastNtError(_SEH2_GetExceptionCode());
2244 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2247 HINSTANCE hInstance
,
2248 PUNICODE_STRING ClassName
,
2249 LPWNDCLASSEXW lpWndClassEx
,
2250 LPWSTR
*ppszMenuName
,
2253 UNICODE_STRING CapturedClassName
, SafeClassName
;
2254 WNDCLASSEXW Safewcexw
;
2256 RTL_ATOM ClassAtom
= 0;
2260 /* NOTE: need exclusive lock because getting the wndproc might require the
2261 creation of a call procedure handle */
2262 UserEnterExclusive();
2264 ppi
= GetW32ProcessInfo();
2266 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2268 UserRegisterSystemClasses();
2273 /* probe the paramters */
2274 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2276 if (CapturedClassName
.Length
== 0)
2277 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2279 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2281 if (CapturedClassName
.Length
& 1)
2283 goto InvalidParameter
;
2286 if (CapturedClassName
.Length
!= 0)
2288 ProbeForRead( CapturedClassName
.Buffer
,
2289 CapturedClassName
.Length
,
2292 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2294 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2295 SafeClassName
.MaximumLength
,
2297 RtlCopyMemory( SafeClassName
.Buffer
,
2298 CapturedClassName
.Buffer
,
2299 SafeClassName
.MaximumLength
);
2303 if (!IS_ATOM(CapturedClassName
.Buffer
))
2305 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2306 goto InvalidParameter
;
2309 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2310 SafeClassName
.Length
= 0;
2311 SafeClassName
.MaximumLength
= 0;
2314 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2317 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2322 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2324 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2326 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2328 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2333 // If null instance use client.
2334 if (!hInstance
) hInstance
= hModClient
;
2338 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName
, hInstance
);
2339 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2344 if (ClassAtom
!= (RTL_ATOM
)0)
2346 if (hInstance
== NULL
) hInstance
= hModClient
;
2348 Ret
= UserGetClassInfo( Class
,
2355 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2363 /* Emulate Function. */
2364 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2366 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2369 /* We must return the atom of the class here instead of just TRUE. */
2370 /* Undocumented behavior! Return the class atom as a BOOL! */
2371 Ret
= (BOOL
)ClassAtom
;
2374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2376 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2381 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2388 NtUserGetClassName (IN HWND hWnd
,
2389 OUT PUNICODE_STRING ClassName
,
2392 PWINDOW_OBJECT Window
;
2393 UNICODE_STRING CapturedClassName
;
2398 Window
= UserGetWindowObject(hWnd
);
2403 ProbeForWriteUnicodeString(ClassName
);
2404 CapturedClassName
= *ClassName
;
2406 /* get the class name */
2407 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2413 /* update the Length field */
2414 ClassName
->Length
= CapturedClassName
.Length
;
2417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2419 SetLastNtError(_SEH2_GetExceptionCode());
2429 /* Return Pointer to Class structure. */
2431 NtUserGetWOWClass(HINSTANCE hInstance
,
2432 PUNICODE_STRING ClassName
)
2434 UNICODE_STRING SafeClassName
;
2437 RTL_ATOM ClassAtom
= 0;
2440 UserEnterExclusive();
2442 pi
= GetW32ProcessInfo();
2446 if (ClassName
->Length
!= 0)
2448 ProbeForRead( ClassName
->Buffer
,
2452 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2454 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2455 SafeClassName
.MaximumLength
,
2457 RtlCopyMemory( SafeClassName
.Buffer
,
2459 SafeClassName
.MaximumLength
);
2463 if (!IS_ATOM(ClassName
->Buffer
))
2465 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2470 SafeClassName
.Buffer
= ClassName
->Buffer
;
2471 SafeClassName
.Length
= 0;
2472 SafeClassName
.MaximumLength
= 0;
2476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2478 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2485 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2492 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2496 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2499 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.