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 ******************************************************************/
14 DBG_DEFAULT_CHANNEL(UserClass
);
16 REGISTER_SYSCLASS DefaultServerClasses
[] =
18 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
19 CS_GLOBALCLASS
|CS_DBLCLKS
,
23 (HBRUSH
)(COLOR_BACKGROUND
+ 1),
27 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
28 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
29 NULL
, // Use User32 procs
36 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
37 CS_DBLCLKS
|CS_SAVEBITS
,
38 NULL
, // Use User32 procs
41 (HBRUSH
)(COLOR_MENU
+ 1),
46 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
47 NULL
, // Use User32 procs
54 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
56 NULL
, // Use User32 procs
65 NULL
, // Use User32 procs
79 { /* Function Ids to Class indexes. */
80 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
81 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
82 { FNID_MENU
, ICLS_MENU
},
83 { FNID_DESKTOP
, ICLS_DESKTOP
},
84 { FNID_SWITCH
, ICLS_SWITCH
},
85 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
86 { FNID_BUTTON
, ICLS_BUTTON
},
87 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
88 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
89 { FNID_DIALOG
, ICLS_DIALOG
},
90 { FNID_EDIT
, ICLS_EDIT
},
91 { FNID_LISTBOX
, ICLS_LISTBOX
},
92 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
93 { FNID_STATIC
, ICLS_STATIC
},
94 { FNID_IME
, ICLS_IME
},
95 { FNID_GHOST
, ICLS_GHOST
},
96 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
101 LookupFnIdToiCls(int FnId
, int *iCls
)
105 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
107 if (FnidToiCls
[i
].FnId
== FnId
)
109 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
117 /* WINDOWCLASS ***************************************************************/
120 IntFreeClassMenuName(IN OUT PCLS Class
)
122 /* free the menu name, if it was changed and allocated */
123 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
125 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
126 Class
->lpszClientUnicodeMenuName
= NULL
;
127 Class
->lpszClientAnsiMenuName
= NULL
;
132 IntDestroyClass(IN OUT PCLS Class
)
135 /* there shouldn't be any clones anymore */
136 ASSERT(Class
->cWndReferenceCount
== 0);
137 ASSERT(Class
->pclsClone
== NULL
);
139 if (Class
->pclsBase
== Class
)
141 PCALLPROCDATA CallProc
, NextCallProc
;
143 /* Destroy allocated callproc handles */
144 CallProc
= Class
->spcpdFirst
;
145 while (CallProc
!= NULL
)
147 NextCallProc
= CallProc
->spcpdNext
;
149 CallProc
->spcpdNext
= NULL
;
150 DestroyCallProc(NULL
,
153 CallProc
= NextCallProc
;
158 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
162 IntFreeClassMenuName(Class
);
165 pDesk
= Class
->rpdeskParent
;
166 Class
->rpdeskParent
= NULL
;
168 /* free the structure */
171 DesktopHeapFree(pDesk
, Class
);
180 /* clean all process classes. all process windows must cleaned first!! */
181 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
184 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
188 /* free all local classes */
189 Class
= pi
->pclsPrivateList
;
190 while (Class
!= NULL
)
192 pi
->pclsPrivateList
= Class
->pclsNext
;
194 ASSERT(Class
->pclsBase
== Class
);
195 IntDestroyClass(Class
);
197 Class
= pi
->pclsPrivateList
;
200 /* free all global classes */
201 Class
= pi
->pclsPublicList
;
202 while (Class
!= NULL
)
204 pi
->pclsPublicList
= Class
->pclsNext
;
206 ASSERT(Class
->pclsBase
== Class
);
207 IntDestroyClass(Class
);
209 Class
= pi
->pclsPublicList
;
215 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
222 if (ClassName
->Length
!= 0)
224 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
225 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
227 EngSetLastError(ERROR_INVALID_PARAMETER
);
234 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
238 AtomName
= ClassName
->Buffer
;
240 Status
= RtlAddAtomToAtomTable(gAtomTable
,
244 if (!NT_SUCCESS(Status
))
246 SetLastNtError(Status
);
254 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
256 return RtlDeleteAtomFromAtomTable(gAtomTable
,
261 UserAddCallProcToClass(IN OUT PCLS Class
,
262 IN PCALLPROCDATA CallProc
)
266 ASSERT(CallProc
->spcpdNext
== NULL
);
268 BaseClass
= Class
->pclsBase
;
269 ASSERT(CallProc
->spcpdNext
== NULL
);
270 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
271 BaseClass
->spcpdFirst
= CallProc
;
273 /* Update all clones */
274 Class
= Class
->pclsClone
;
275 while (Class
!= NULL
)
277 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
278 Class
= Class
->pclsNext
;
283 IntSetClassAtom(IN OUT PCLS Class
,
284 IN PUNICODE_STRING ClassName
)
286 RTL_ATOM Atom
= (RTL_ATOM
)0;
288 /* update the base class first */
289 Class
= Class
->pclsBase
;
291 if (!IntRegisterClassAtom(ClassName
,
297 IntDeregisterClassAtom(Class
->atomClassName
);
299 Class
->atomClassName
= Atom
;
301 /* update the clones */
302 Class
= Class
->pclsClone
;
303 while (Class
!= NULL
)
305 Class
->atomClassName
= Atom
;
307 Class
= Class
->pclsNext
;
314 // Same as User32:IntGetClsWndProc.
317 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
320 WNDPROC gcpd
= NULL
, Ret
= NULL
;
322 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
324 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
326 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
329 Ret
= GETPFNCLIENTA(i
);
331 Ret
= GETPFNCLIENTW(i
);
336 Ret
= Class
->lpfnWndProc
;
338 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
342 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
343 Ret
= GETPFNCLIENTA(Class
->fnid
);
347 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
348 Ret
= GETPFNCLIENTW(Class
->fnid
);
352 if ( Ret
!= Class
->lpfnWndProc
||
353 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
356 gcpd
= (WNDPROC
)UserGetCPD( Class
,
357 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
360 return (gcpd
? gcpd
: Ret
);
366 IntSetClassWndProc(IN OUT PCLS Class
,
372 WNDPROC Ret
, chWndProc
;
374 Ret
= IntGetClassWndProc(Class
, Ansi
);
376 // If Server Side, downgrade to Client Side.
377 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
379 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
380 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
381 Class
->Unicode
= !Ansi
;
384 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
388 // Check if CallProc handle and retrieve previous call proc address and set.
389 if (IsCallProcHandle(WndProc
))
391 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
392 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
395 Class
->lpfnWndProc
= chWndProc
;
400 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
401 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
403 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
405 chWndProc
= GETPFNSERVER(i
);
408 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
410 chWndProc
= GETPFNSERVER(i
);
414 // If match, set/reset to Server Side and clear ansi.
417 Class
->lpfnWndProc
= chWndProc
;
418 Class
->Unicode
= TRUE
;
419 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
420 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
424 Class
->Unicode
= !Ansi
;
427 Class
->CSF_flags
|= CSF_ANSIPROC
;
429 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
432 /* update the clones */
433 chWndProc
= Class
->lpfnWndProc
;
435 Class
= Class
->pclsClone
;
436 while (Class
!= NULL
)
438 Class
->Unicode
= !Ansi
;
439 Class
->lpfnWndProc
= chWndProc
;
441 Class
= Class
->pclsNext
;
448 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
449 IN OUT PCLS
*ClassLink
,
455 ASSERT(Desktop
!= NULL
);
456 ASSERT(BaseClass
->pclsBase
== BaseClass
);
458 if (BaseClass
->rpdeskParent
== Desktop
)
460 /* it is most likely that a window is created on the same
461 desktop as the window class. */
466 if (BaseClass
->rpdeskParent
== NULL
)
468 ASSERT(BaseClass
->cWndReferenceCount
== 0);
469 ASSERT(BaseClass
->pclsClone
== NULL
);
471 /* Classes are also located in the shared heap when the class
472 was created before the thread attached to a desktop. As soon
473 as a window is created for such a class located on the shared
474 heap, the class is cloned into the desktop heap on which the
475 window is created. */
480 /* The user is asking for a class object on a different desktop,
482 Class
= BaseClass
->pclsClone
;
483 while (Class
!= NULL
)
485 if (Class
->rpdeskParent
== Desktop
)
487 ASSERT(Class
->pclsBase
== BaseClass
);
488 ASSERT(Class
->pclsClone
== NULL
);
492 Class
= Class
->pclsNext
;
498 /* The window is created on a different desktop, we need to
499 clone the class object to the desktop heap of the window! */
500 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
502 Class
= DesktopHeapAlloc(Desktop
,
506 /* simply clone the class */
507 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
509 TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
511 /* restore module address if default user class Ref: Bug 4778 */
512 if ( Class
->hModule
!= hModClient
&&
513 Class
->fnid
<= FNID_GHOST
&&
514 Class
->fnid
>= FNID_BUTTON
)
516 Class
->hModule
= hModClient
;
517 TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class
, Class
->hModule
);
520 /* update some pointers and link the class */
521 Class
->rpdeskParent
= Desktop
;
522 Class
->cWndReferenceCount
= 0;
524 if (BaseClass
->rpdeskParent
== NULL
)
526 /* we don't really need the base class on the shared
527 heap anymore, delete it so the only class left is
528 the clone we just created, which now serves as the
530 ASSERT(BaseClass
->pclsClone
== NULL
);
531 ASSERT(Class
->pclsClone
== NULL
);
532 Class
->pclsBase
= Class
;
533 Class
->pclsNext
= BaseClass
->pclsNext
;
535 /* replace the base class */
536 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
539 /* destroy the obsolete copy on the shared heap */
540 BaseClass
->pclsBase
= NULL
;
541 BaseClass
->pclsClone
= NULL
;
542 IntDestroyClass(BaseClass
);
546 /* link in the clone */
547 Class
->pclsClone
= NULL
;
548 Class
->pclsBase
= BaseClass
;
549 Class
->pclsNext
= BaseClass
->pclsClone
;
550 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
556 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
563 IntReferenceClass(IN OUT PCLS BaseClass
,
564 IN OUT PCLS
*ClassLink
,
568 ASSERT(BaseClass
->pclsBase
== BaseClass
);
570 Class
= IntGetClassForDesktop(BaseClass
,
575 Class
->cWndReferenceCount
++;
583 IntMakeCloneBaseClass(IN OUT PCLS Class
,
584 IN OUT PCLS
*BaseClassLink
,
585 IN OUT PCLS
*CloneLink
)
589 ASSERT(Class
->pclsBase
!= Class
);
590 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
591 ASSERT(Class
->rpdeskParent
!= NULL
);
592 ASSERT(Class
->cWndReferenceCount
!= 0);
593 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
594 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
596 /* unlink the clone */
597 *CloneLink
= Class
->pclsNext
;
598 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
600 /* update the class information to make it a base class */
601 Class
->pclsBase
= Class
;
602 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
604 /* update all clones */
605 Clone
= Class
->pclsClone
;
606 while (Clone
!= NULL
)
608 ASSERT(Clone
->pclsClone
== NULL
);
609 Clone
->pclsBase
= Class
;
611 Clone
= Clone
->pclsNext
;
614 /* link in the new base class */
615 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
621 IntDereferenceClass(IN OUT PCLS Class
,
622 IN PDESKTOPINFO Desktop
,
625 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
627 BaseClass
= Class
->pclsBase
;
629 if (--Class
->cWndReferenceCount
<= 0)
631 if (BaseClass
== Class
)
633 ASSERT(Class
->pclsBase
== Class
);
635 TRACE("IntDereferenceClass 0x%x\n", Class
);
636 /* check if there are clones of the class on other desktops,
637 link the first clone in if possible. If there are no clones
638 then leave the class on the desktop heap. It will get moved
639 to the shared heap when the thread detaches. */
640 if (BaseClass
->pclsClone
!= NULL
)
642 if (BaseClass
->Global
)
643 PrevLink
= &pi
->pclsPublicList
;
645 PrevLink
= &pi
->pclsPrivateList
;
647 CurrentClass
= *PrevLink
;
648 while (CurrentClass
!= BaseClass
)
650 ASSERT(CurrentClass
!= NULL
);
652 PrevLink
= &CurrentClass
->pclsNext
;
653 CurrentClass
= CurrentClass
->pclsNext
;
656 ASSERT(*PrevLink
== BaseClass
);
658 /* make the first clone become the new base class */
659 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
661 &BaseClass
->pclsClone
);
663 /* destroy the class, there's still another clone of the class
664 that now serves as a base class. Make sure we don't destruct
665 resources shared by all classes (Base = NULL)! */
666 BaseClass
->pclsBase
= NULL
;
667 BaseClass
->pclsClone
= NULL
;
668 IntDestroyClass(BaseClass
);
673 TRACE("IntDereferenceClass1 0x%x\n", Class
);
675 /* locate the cloned class and unlink it */
676 PrevLink
= &BaseClass
->pclsClone
;
677 CurrentClass
= BaseClass
->pclsClone
;
678 while (CurrentClass
!= Class
)
680 ASSERT(CurrentClass
!= NULL
);
682 PrevLink
= &CurrentClass
->pclsNext
;
683 CurrentClass
= CurrentClass
->pclsNext
;
686 ASSERT(CurrentClass
== Class
);
688 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
691 ASSERT(Class
->pclsBase
== BaseClass
);
692 ASSERT(Class
->pclsClone
== NULL
);
694 /* the class was just a clone, we don't need it anymore */
695 IntDestroyClass(Class
);
701 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
702 IN OUT PCLS
**ClassLinkPtr
)
707 ASSERT(Class
->pclsBase
== Class
);
708 ASSERT(Class
->rpdeskParent
!= NULL
);
709 ASSERT(Class
->cWndReferenceCount
== 0);
710 ASSERT(Class
->pclsClone
== NULL
);
712 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
714 /* allocate the new base class on the shared heap */
715 NewClass
= UserHeapAlloc(ClassSize
);
716 if (NewClass
!= NULL
)
718 RtlCopyMemory(NewClass
,
722 NewClass
->rpdeskParent
= NULL
;
723 NewClass
->pclsBase
= NewClass
;
725 /* replace the class in the list */
726 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
728 *ClassLinkPtr
= &NewClass
->pclsNext
;
730 /* free the obsolete class on the desktop heap */
731 Class
->pclsBase
= NULL
;
732 IntDestroyClass(Class
);
740 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
741 IN OUT PCLS
*ClassList
,
742 IN BOOL FreeOnFailure
,
745 PCLS Class
, NextClass
, *Link
;
747 /* NOTE: We only need to check base classes! When classes are no longer needed
748 on a desktop, the clones will be freed automatically as soon as possible.
749 However, we need to move base classes to the shared heap, as soon as
750 the last desktop heap where a class is allocated on is about to be destroyed.
751 If we didn't move the class to the shared heap, the class would become
754 ASSERT(Desktop
!= NULL
);
758 while (Class
!= NULL
)
760 NextClass
= Class
->pclsNext
;
762 ASSERT(Class
->pclsBase
== Class
);
764 if (Class
->rpdeskParent
== Desktop
&&
765 Class
->cWndReferenceCount
== 0)
767 /* there shouldn't be any clones around anymore! */
768 ASSERT(Class
->pclsClone
== NULL
);
770 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
771 /* FIXME - We could move the class to another desktop heap if there's still desktops
772 mapped into the process... */
774 /* move the class to the shared heap */
775 if (IntMoveClassToSharedHeap(Class
,
778 ASSERT(*Link
== NextClass
);
782 ASSERT(NextClass
== Class
->pclsNext
);
786 /* unlink the base class */
787 (void)InterlockedExchangePointer((PVOID
*)Link
,
790 /* we can free the old base class now */
791 Class
->pclsBase
= NULL
;
792 IntDestroyClass(Class
);
796 Link
= &Class
->pclsNext
;
802 Link
= &Class
->pclsNext
;
809 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
810 IN BOOL FreeOnFailure
)
815 pi
= GetW32ProcessInfo();
817 /* check all local classes */
818 IntCheckDesktopClasses(Desktop
,
819 &pi
->pclsPrivateList
,
823 /* check all global classes */
824 IntCheckDesktopClasses(Desktop
,
830 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
831 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
839 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
840 IN PUNICODE_STRING ClassName
,
841 IN PUNICODE_STRING MenuName
,
851 PWSTR pszMenuName
= NULL
;
852 NTSTATUS Status
= STATUS_SUCCESS
;
854 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
855 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
857 if (!IntRegisterClassAtom(ClassName
,
860 ERR("Failed to register class atom!\n");
864 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
865 if (MenuName
->Length
!= 0)
867 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
868 RtlUnicodeStringToAnsiSize(MenuName
));
869 if (pszMenuName
== NULL
)
875 Class
= DesktopHeapAlloc(Desktop
,
880 /* FIXME - the class was created before being connected
881 to a desktop. It is possible for the desktop window,
882 but should it be allowed for any other case? */
883 Class
= UserHeapAlloc(ClassSize
);
890 RtlZeroMemory(Class
, ClassSize
);
892 Class
->rpdeskParent
= Desktop
;
893 Class
->pclsBase
= Class
;
894 Class
->atomClassName
= Atom
;
896 Class
->CSF_flags
= dwFlags
;
898 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
900 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
905 PWSTR pszMenuNameBuffer
= pszMenuName
;
907 /* need to protect with SEH since accessing the WNDCLASSEX structure
908 and string buffers might raise an exception! We don't want to
910 // What?! If the user interface was written correctly this would not be an issue!
911 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
912 Class
->style
= lpwcx
->style
;
913 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
914 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
915 Class
->hModule
= lpwcx
->hInstance
;
916 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
917 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
918 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
919 Class
->hbrBackground
= lpwcx
->hbrBackground
;
921 /* make a copy of the string */
922 if (pszMenuNameBuffer
!= NULL
)
924 Class
->MenuNameIsString
= TRUE
;
926 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
927 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
930 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
932 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
935 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
937 /* save an ansi copy of the string */
938 if (pszMenuNameBuffer
!= NULL
)
940 ANSI_STRING AnsiString
;
942 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
943 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
944 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
945 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
948 if (!NT_SUCCESS(Status
))
950 ERR("Failed to convert unicode menu name to ansi!\n");
952 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
957 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
959 /* Save kernel use menu name and ansi class name */
960 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
961 //Class->lpszAnsiClassName = Fixme!
963 /* Server Side overrides class calling type (A/W)!
964 User32 whine test_builtinproc: "deftest"
965 built-in winproc - window A/W type automatically detected */
966 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
970 /* Due to the wine class "deftest" and most likely no FNID to reference
971 from, sort through the Server Side list and compare proc addresses
972 for match. This method will be used in related code.
974 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
975 { // Open Ansi or Unicode, just match, set and break.
976 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
978 WndProc
= GETPFNSERVER(i
);
981 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
983 WndProc
= GETPFNSERVER(i
);
988 { // If a hit, we are Server Side so set the right flags and proc.
989 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
990 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
991 Class
->lpfnWndProc
= WndProc
;
995 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
996 Class
->Unicode
= TRUE
;
998 if (Class
->style
& CS_GLOBALCLASS
)
999 Class
->Global
= TRUE
;
1001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1003 Status
= _SEH2_GetExceptionCode();
1007 if (!NT_SUCCESS(Status
))
1009 ERR("Failed creating the class: 0x%x\n", Status
);
1011 SetLastNtError(Status
);
1013 if (pszMenuName
!= NULL
)
1014 UserHeapFree(pszMenuName
);
1016 DesktopHeapFree(Desktop
,
1020 IntDeregisterClassAtom(Atom
);
1026 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1028 if (pszMenuName
!= NULL
)
1029 UserHeapFree(pszMenuName
);
1031 IntDeregisterClassAtom(Atom
);
1033 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1036 TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
1037 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1043 IntFindClass(IN RTL_ATOM Atom
,
1044 IN HINSTANCE hInstance
,
1046 OUT PCLS
**Link OPTIONAL
)
1048 PCLS Class
, *PrevLink
= ClassList
;
1051 while (Class
!= NULL
)
1053 if (Class
->atomClassName
== Atom
&&
1054 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1055 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1057 ASSERT(Class
->pclsBase
== Class
);
1064 PrevLink
= &Class
->pclsNext
;
1065 Class
= Class
->pclsNext
;
1072 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1077 if (ClassName
->Length
!= 0)
1083 /* NOTE: Caller has to protect the call with SEH! */
1085 if (ClassName
->Length
!= 0)
1087 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1088 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1090 EngSetLastError(ERROR_INVALID_PARAMETER
);
1094 /* We need to make a local copy of the class name! The caller could
1095 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1096 We're protected by SEH, but the ranges that might be accessed were
1098 RtlCopyMemory(szBuf
,
1101 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1105 AtomName
= ClassName
->Buffer
;
1107 /* lookup the atom */
1108 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1111 if (NT_SUCCESS(Status
))
1117 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1119 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1123 SetLastNtError(Status
);
1129 ASSERT(IS_ATOM(ClassName
->Buffer
));
1130 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1138 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1139 IN HINSTANCE hInstance OPTIONAL
,
1140 IN PPROCESSINFO pi OPTIONAL
,
1141 OUT PCLS
*BaseClass OPTIONAL
,
1142 OUT PCLS
**Link OPTIONAL
)
1144 RTL_ATOM Atom
= (RTL_ATOM
)0;
1146 ASSERT(BaseClass
!= NULL
);
1148 if (IntGetAtomFromStringOrAtom(ClassName
,
1150 Atom
!= (RTL_ATOM
)0)
1154 /* attempt to locate the class object */
1158 /* Step 1: try to find an exact match of locally registered classes */
1159 Class
= IntFindClass(Atom
,
1161 &pi
->pclsPrivateList
,
1164 { TRACE("Step 1: 0x%x\n",Class
);
1168 /* Step 2: try to find any globally registered class. The hInstance
1169 is not relevant for global classes */
1170 Class
= IntFindClass(Atom
,
1172 &pi
->pclsPublicList
,
1175 { TRACE("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1179 /* Step 3: try to find any local class registered by user32 */
1180 Class
= IntFindClass(Atom
,
1182 &pi
->pclsPrivateList
,
1185 { TRACE("Step 3: 0x%x\n",Class
);
1189 /* Step 4: try to find any global class registered by user32 */
1190 Class
= IntFindClass(Atom
,
1192 &pi
->pclsPublicList
,
1196 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1198 }else{TRACE("Step 4: 0x%x\n",Class
);}
1208 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
)
1210 PCLS
*ClassLink
, Class
= NULL
;
1214 pti
= PsGetCurrentThreadWin32Thread();
1216 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1218 UserRegisterSystemClasses();
1221 /* Check the class. */
1223 TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName
, hInstance
);
1225 ClassAtom
= IntGetClassAtom(ClassName
,
1231 if (ClassAtom
== (RTL_ATOM
)0)
1233 if (IS_ATOM(ClassName
->Buffer
))
1235 ERR("Class 0x%p not found\n", (DWORD_PTR
) ClassName
->Buffer
);
1239 ERR("Class \"%wZ\" not found\n", ClassName
);
1242 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1246 TRACE("Referencing Class 0x%x with atom 0x%x\n", Class
, ClassAtom
);
1247 Class
= IntReferenceClass(Class
,
1252 ERR("Failed to reference window class!\n");
1260 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1261 IN PUNICODE_STRING ClassName
,
1262 IN PUNICODE_STRING MenuName
,
1270 RTL_ATOM Ret
= (RTL_ATOM
)0;
1272 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1274 pti
= GetW32ThreadInfo();
1278 // Need only to test for two conditions not four....... Fix more whine tests....
1279 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1280 ClassAtom
!= (RTL_ATOM
)0 &&
1281 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1283 Class
= IntFindClass( ClassAtom
,
1285 &pi
->pclsPrivateList
,
1288 if (Class
!= NULL
&& !Class
->Global
)
1290 // local class already exists
1291 TRACE("Local Class 0x%p does already exist!\n", ClassAtom
);
1292 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1296 if (lpwcx
->style
& CS_GLOBALCLASS
)
1298 /* HACK: allow global classes to be re-registered*/
1299 Class
= IntFindClass( ClassAtom
,
1301 &pi
->pclsPublicList
,
1304 if (Class
!= NULL
&& Class
->Global
)
1306 TRACE("Global Class 0x%p does already exist!\n", ClassAtom
);
1307 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1313 Class
= IntCreateClass(lpwcx
,
1325 /* Register the class */
1327 List
= &pi
->pclsPublicList
;
1329 List
= &pi
->pclsPrivateList
;
1331 Class
->pclsNext
= *List
;
1332 (void)InterlockedExchangePointer((PVOID
*)List
,
1335 Ret
= Class
->atomClassName
;
1339 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1346 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1347 IN HINSTANCE hInstance
,
1348 OUT PCLSMENUNAME pClassMenuName
)
1355 pi
= GetW32ProcessInfo();
1357 TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1359 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1360 ClassAtom
= IntGetClassAtom(ClassName
,
1365 if (ClassAtom
== (RTL_ATOM
)0)
1367 TRACE("UserUnregisterClass: No Class found.\n");
1371 ASSERT(Class
!= NULL
);
1373 if (Class
->cWndReferenceCount
!= 0 ||
1374 Class
->pclsClone
!= NULL
)
1376 TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1377 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1381 /* must be a base class! */
1382 ASSERT(Class
->pclsBase
== Class
);
1384 /* unlink the class */
1385 *Link
= Class
->pclsNext
;
1387 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1389 TRACE("Class 0x%x\n", Class
);
1390 TRACE("UserUnregisterClass: Good Exit!\n");
1391 /* finally free the resources */
1392 IntDestroyClass(Class
);
1395 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1400 UserGetClassName(IN PCLS Class
,
1401 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 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1454 /* query the class name */
1455 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1456 Atom
? Atom
: 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 Atom
? Atom
: 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 ERR("Failed to copy class menu name!\n");
1590 UserHeapFree(strBufW
);
1594 EngSetLastError(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 EngSetLastError(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 EngSetLastError(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 ERR("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 EngSetLastError(ERROR_INVALID_INDEX
);
1816 UserGetClassInfo(IN PCLS Class
,
1817 OUT PWNDCLASSEXW lpwcx
,
1819 HINSTANCE hInstance
)
1821 if (!Class
) return FALSE
;
1823 lpwcx
->style
= Class
->style
;
1825 // If fnId is set, clear the global bit. See wine class test check_style.
1827 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1829 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1831 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1832 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1833 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1834 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1835 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1837 /* Copy non-string to user first. */
1839 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1841 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1843 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1844 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1845 lpszClientXxxMenuName should already be mapped to user space.
1847 /* Copy string ptr to user. */
1848 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1849 Class
->MenuNameIsString
)
1851 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1852 (PVOID
)Class
->lpszClientAnsiMenuName
:
1853 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1856 if (hInstance
== hModClient
)
1857 lpwcx
->hInstance
= NULL
;
1859 lpwcx
->hInstance
= hInstance
;
1861 /* FIXME - return the string? Okay! This is performed in User32!*/
1862 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1864 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1874 UserRegisterSystemClasses(VOID
)
1877 UNICODE_STRING ClassName
, MenuName
;
1878 PPROCESSINFO ppi
= GetW32ProcessInfo();
1884 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1887 if ( hModClient
== NULL
)
1890 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1891 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1893 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1895 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1897 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1901 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1902 ClassName
.Length
= 0;
1903 ClassName
.MaximumLength
= 0;
1906 wc
.cbSize
= sizeof(wc
);
1907 wc
.style
= DefaultServerClasses
[i
].Style
;
1909 Flags
|= CSF_SERVERSIDEPROC
;
1911 if (DefaultServerClasses
[i
].ProcW
)
1913 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1914 wc
.hInstance
= hModuleWin
;
1918 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1919 wc
.hInstance
= hModClient
;
1923 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1925 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1926 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1927 wc
.lpszMenuName
= NULL
;
1928 wc
.lpszClassName
= ClassName
.Buffer
;
1931 Class
= IntCreateClass( &wc
,
1934 DefaultServerClasses
[i
].fiId
,
1940 Class
->pclsNext
= ppi
->pclsPublicList
;
1941 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1944 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1948 ERR("!!! Registering system class failed!\n");
1952 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1956 /* SYSCALLS *****************************************************************/
1960 NtUserRegisterClassExWOW(
1962 PUNICODE_STRING ClassName
,
1963 PUNICODE_STRING ClsNVersion
,
1964 PCLSMENUNAME pClassMenuName
,
1970 * Registers a new class with the window manager
1972 * lpwcx = Win32 extended window class structure
1973 * bUnicodeClass = Whether to send ANSI or unicode strings
1974 * to window procedures
1976 * Atom identifying the new class
1979 WNDCLASSEXW CapturedClassInfo
= {0};
1980 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1981 RTL_ATOM Ret
= (RTL_ATOM
)0;
1982 PPROCESSINFO ppi
= GetW32ProcessInfo();
1984 if (Flags
& ~(CSF_ANSIPROC
))
1986 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
1987 EngSetLastError(ERROR_INVALID_FLAGS
);
1991 UserEnterExclusive();
1993 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
1995 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1997 UserRegisterSystemClasses();
2002 /* Probe the parameters and basic parameter checks */
2003 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2005 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2006 goto InvalidParameter
;
2010 sizeof(WNDCLASSEXW
),
2012 RtlCopyMemory(&CapturedClassInfo
,
2014 sizeof(WNDCLASSEXW
));
2016 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2018 ProbeForRead(pClassMenuName
,
2019 sizeof(CLSMENUNAME
),
2022 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2024 if ( CapturedName
.Length
& 1 ||
2025 CapturedMenuName
.Length
& 1 ||
2026 CapturedClassInfo
.cbClsExtra
< 0 ||
2027 CapturedClassInfo
.cbClsExtra
+
2028 CapturedName
.Length
+
2029 CapturedMenuName
.Length
+
2030 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2031 CapturedClassInfo
.cbWndExtra
< 0 ||
2032 CapturedClassInfo
.hInstance
== NULL
)
2034 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2035 goto InvalidParameter
;
2038 if (CapturedName
.Length
!= 0)
2040 ProbeForRead(CapturedName
.Buffer
,
2041 CapturedName
.Length
,
2046 if (!IS_ATOM(CapturedName
.Buffer
))
2048 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2049 goto InvalidParameter
;
2053 if (CapturedMenuName
.Length
!= 0)
2055 ProbeForRead(CapturedMenuName
.Buffer
,
2056 CapturedMenuName
.Length
,
2059 else if (CapturedMenuName
.Buffer
!= NULL
&&
2060 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2062 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2064 EngSetLastError(ERROR_INVALID_PARAMETER
);
2068 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2069 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2070 // If this pops up we know what todo!
2071 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2074 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2076 /* Register the class */
2077 Ret
= UserRegisterClass(&CapturedClassInfo
,
2083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2085 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2086 SetLastNtError(_SEH2_GetExceptionCode());
2092 ERR("NtUserRegisterClassExWOW Null Return!\n");
2101 NtUserSetClassLong(HWND hWnd
,
2103 ULONG_PTR dwNewLong
,
2110 UserEnterExclusive();
2112 pi
= GetW32ProcessInfo();
2114 Window
= UserGetWindowObject(hWnd
);
2117 if (Window
->head
.pti
->ppi
!= pi
)
2119 EngSetLastError(ERROR_ACCESS_DENIED
);
2125 UNICODE_STRING Value
;
2127 /* probe the parameters */
2128 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2130 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2131 if (Value
.Length
& 1)
2133 goto InvalidParameter
;
2136 if (Value
.Length
!= 0)
2138 ProbeForRead(Value
.Buffer
,
2144 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2146 goto InvalidParameter
;
2148 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2151 EngSetLastError(ERROR_INVALID_PARAMETER
);
2156 dwNewLong
= (ULONG_PTR
)&Value
;
2159 Ret
= UserSetClassLongPtr(Window
->pcls
,
2164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2166 SetLastNtError(_SEH2_GetExceptionCode());
2185 * NOTE: Obsoleted in 32-bit windows
2191 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2192 IN HINSTANCE hInstance
,
2193 OUT PCLSMENUNAME pClassMenuName
)
2195 UNICODE_STRING CapturedClassName
;
2198 UserEnterExclusive();
2202 /* probe the paramters */
2203 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2204 if (CapturedClassName
.Length
& 1)
2206 goto InvalidParameter
;
2209 if (CapturedClassName
.Length
!= 0)
2211 ProbeForRead(CapturedClassName
.Buffer
,
2212 CapturedClassName
.Length
,
2217 if (!IS_ATOM(CapturedClassName
.Buffer
))
2220 EngSetLastError(ERROR_INVALID_PARAMETER
);
2225 /* unregister the class */
2226 Ret
= UserUnregisterClass(&CapturedClassName
,
2228 NULL
); // Null for now~
2230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2232 SetLastNtError(_SEH2_GetExceptionCode());
2240 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2243 HINSTANCE hInstance
,
2244 PUNICODE_STRING ClassName
,
2245 LPWNDCLASSEXW lpWndClassEx
,
2246 LPWSTR
*ppszMenuName
,
2249 UNICODE_STRING CapturedClassName
, SafeClassName
;
2250 WNDCLASSEXW Safewcexw
;
2252 RTL_ATOM ClassAtom
= 0;
2256 /* NOTE: need exclusive lock because getting the wndproc might require the
2257 creation of a call procedure handle */
2258 UserEnterExclusive();
2260 ppi
= GetW32ProcessInfo();
2262 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2264 UserRegisterSystemClasses();
2269 /* probe the paramters */
2270 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2272 if (CapturedClassName
.Length
== 0)
2274 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2278 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2281 if (CapturedClassName
.Length
& 1)
2283 EngSetLastError(ERROR_INVALID_PARAMETER
);
2288 if (CapturedClassName
.Length
!= 0)
2290 ProbeForRead( CapturedClassName
.Buffer
,
2291 CapturedClassName
.Length
,
2294 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2296 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2297 SafeClassName
.MaximumLength
,
2299 RtlCopyMemory( SafeClassName
.Buffer
,
2300 CapturedClassName
.Buffer
,
2301 SafeClassName
.MaximumLength
);
2305 if (!IS_ATOM(CapturedClassName
.Buffer
))
2307 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2308 EngSetLastError(ERROR_INVALID_PARAMETER
);
2313 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2314 SafeClassName
.Length
= 0;
2315 SafeClassName
.MaximumLength
= 0;
2318 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2320 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2324 SetLastNtError(_SEH2_GetExceptionCode());
2329 // If null instance use client.
2330 if (!hInstance
) hInstance
= hModClient
;
2334 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName
, hInstance
);
2335 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2340 if (ClassAtom
!= (RTL_ATOM
)0)
2342 if (hInstance
== NULL
) hInstance
= hModClient
;
2344 Ret
= UserGetClassInfo( Class
,
2351 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2359 /* Emulate Function. */
2360 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2362 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2365 /* We must return the atom of the class here instead of just TRUE. */
2366 /* Undocumented behavior! Return the class atom as a BOOL! */
2367 Ret
= (BOOL
)ClassAtom
;
2370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2372 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2377 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2384 NtUserGetClassName (IN HWND hWnd
,
2386 OUT PUNICODE_STRING ClassName
)
2389 UNICODE_STRING CapturedClassName
;
2395 Window
= UserGetWindowObject(hWnd
);
2398 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2400 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2402 Atom
= gpsi
->atomSysClass
[iCls
];
2408 ProbeForWriteUnicodeString(ClassName
);
2409 CapturedClassName
= *ClassName
;
2411 /* get the class name */
2412 Ret
= UserGetClassName(Window
->pcls
,
2419 /* update the Length field */
2420 ClassName
->Length
= CapturedClassName
.Length
;
2423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2425 SetLastNtError(_SEH2_GetExceptionCode());
2435 /* Return Pointer to Class structure. */
2437 NtUserGetWOWClass(HINSTANCE hInstance
,
2438 PUNICODE_STRING ClassName
)
2440 UNICODE_STRING SafeClassName
;
2443 RTL_ATOM ClassAtom
= 0;
2446 UserEnterExclusive();
2448 pi
= GetW32ProcessInfo();
2452 if (ClassName
->Length
!= 0)
2454 ProbeForRead( ClassName
->Buffer
,
2458 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2460 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2461 SafeClassName
.MaximumLength
,
2463 RtlCopyMemory( SafeClassName
.Buffer
,
2465 SafeClassName
.MaximumLength
);
2469 if (!IS_ATOM(ClassName
->Buffer
))
2471 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2476 SafeClassName
.Buffer
= ClassName
->Buffer
;
2477 SafeClassName
.Length
= 0;
2478 SafeClassName
.MaximumLength
= 0;
2482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2484 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2491 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2498 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2502 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2505 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.