2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
10 DBG_DEFAULT_CHANNEL(UserClass
);
12 REGISTER_SYSCLASS DefaultServerClasses
[] =
14 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8001))),
15 CS_GLOBALCLASS
|CS_DBLCLKS
,
19 (HBRUSH
)(COLOR_BACKGROUND
+ 1),
23 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
24 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
25 NULL
, // Use User32 procs
32 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
33 CS_DBLCLKS
|CS_SAVEBITS
,
34 NULL
, // Use User32 procs
37 (HBRUSH
)(COLOR_MENU
+ 1),
42 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
43 NULL
, // Use User32 procs
44 sizeof(SBWND
)-sizeof(WND
),
50 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
52 NULL
, // Use User32 procs
61 NULL
, // Use User32 procs
75 { /* Function Ids to Class indexes. */
76 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
77 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
78 { FNID_MENU
, ICLS_MENU
},
79 { FNID_DESKTOP
, ICLS_DESKTOP
},
80 { FNID_SWITCH
, ICLS_SWITCH
},
81 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
82 { FNID_BUTTON
, ICLS_BUTTON
},
83 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
84 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
85 { FNID_DIALOG
, ICLS_DIALOG
},
86 { FNID_EDIT
, ICLS_EDIT
},
87 { FNID_LISTBOX
, ICLS_LISTBOX
},
88 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
89 { FNID_STATIC
, ICLS_STATIC
},
90 { FNID_IME
, ICLS_IME
},
91 { FNID_GHOST
, ICLS_GHOST
},
92 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
97 LookupFnIdToiCls(int FnId
, int *iCls
)
101 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
103 if (FnidToiCls
[i
].FnId
== FnId
)
105 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
113 /* WINDOWCLASS ***************************************************************/
116 IntFreeClassMenuName(IN OUT PCLS Class
)
118 /* Free the menu name, if it was changed and allocated */
119 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
121 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
122 Class
->lpszClientUnicodeMenuName
= NULL
;
123 Class
->lpszClientAnsiMenuName
= NULL
;
128 IntDestroyClass(IN OUT PCLS Class
)
132 /* There shouldn't be any clones anymore */
133 ASSERT(Class
->cWndReferenceCount
== 0);
134 ASSERT(Class
->pclsClone
== NULL
);
136 if (Class
->pclsBase
== Class
)
138 PCALLPROCDATA CallProc
, NextCallProc
;
140 /* Destroy allocated callproc handles */
141 CallProc
= Class
->spcpdFirst
;
142 while (CallProc
!= NULL
)
144 NextCallProc
= CallProc
->spcpdNext
;
146 CallProc
->spcpdNext
= NULL
;
147 DestroyCallProc(NULL
,
150 CallProc
= NextCallProc
;
155 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
159 IntFreeClassMenuName(Class
);
162 pDesk
= Class
->rpdeskParent
;
163 Class
->rpdeskParent
= NULL
;
165 /* Free the structure */
168 DesktopHeapFree(pDesk
, Class
);
177 /* Clean all process classes. all process windows must cleaned first!! */
178 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
181 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
185 /* Free all local classes */
186 Class
= pi
->pclsPrivateList
;
187 while (Class
!= NULL
)
189 pi
->pclsPrivateList
= Class
->pclsNext
;
191 ASSERT(Class
->pclsBase
== Class
);
192 IntDestroyClass(Class
);
194 Class
= pi
->pclsPrivateList
;
197 /* Free all global classes */
198 Class
= pi
->pclsPublicList
;
199 while (Class
!= NULL
)
201 pi
->pclsPublicList
= Class
->pclsNext
;
203 ASSERT(Class
->pclsBase
== Class
);
204 IntDestroyClass(Class
);
206 Class
= pi
->pclsPublicList
;
212 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
219 if (ClassName
->Length
!= 0)
221 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
222 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
224 EngSetLastError(ERROR_INVALID_PARAMETER
);
231 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
235 AtomName
= ClassName
->Buffer
;
237 Status
= RtlAddAtomToAtomTable(gAtomTable
,
241 if (!NT_SUCCESS(Status
))
243 SetLastNtError(Status
);
251 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
253 return RtlDeleteAtomFromAtomTable(gAtomTable
,
258 UserAddCallProcToClass(IN OUT PCLS Class
,
259 IN PCALLPROCDATA CallProc
)
263 ASSERT(CallProc
->spcpdNext
== NULL
);
265 BaseClass
= Class
->pclsBase
;
266 ASSERT(CallProc
->spcpdNext
== NULL
);
267 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
268 BaseClass
->spcpdFirst
= CallProc
;
270 /* Update all clones */
271 Class
= Class
->pclsClone
;
272 while (Class
!= NULL
)
274 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
275 Class
= Class
->pclsNext
;
280 IntSetClassAtom(IN OUT PCLS Class
,
281 IN PUNICODE_STRING ClassName
)
283 RTL_ATOM Atom
= (RTL_ATOM
)0;
285 /* Update the base class first */
286 Class
= Class
->pclsBase
;
288 if (!IntRegisterClassAtom(ClassName
,
294 IntDeregisterClassAtom(Class
->atomClassName
);
296 Class
->atomClassName
= Atom
;
298 /* Update the clones */
299 Class
= Class
->pclsClone
;
300 while (Class
!= NULL
)
302 Class
->atomClassName
= Atom
;
304 Class
= Class
->pclsNext
;
311 // Same as User32:IntGetClsWndProc.
314 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
317 WNDPROC gcpd
= NULL
, Ret
= NULL
;
319 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
321 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
323 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
326 Ret
= GETPFNCLIENTA(i
);
328 Ret
= GETPFNCLIENTW(i
);
333 Ret
= Class
->lpfnWndProc
;
335 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
339 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
340 Ret
= GETPFNCLIENTA(Class
->fnid
);
344 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
345 Ret
= GETPFNCLIENTW(Class
->fnid
);
349 if ( Ret
!= Class
->lpfnWndProc
||
350 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
353 gcpd
= (WNDPROC
)UserGetCPD( Class
,
354 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
357 return (gcpd
? gcpd
: Ret
);
363 IntSetClassWndProc(IN OUT PCLS Class
,
369 WNDPROC Ret
, chWndProc
;
371 Ret
= IntGetClassWndProc(Class
, Ansi
);
373 // If Server Side, downgrade to Client Side.
374 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
376 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
377 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
378 Class
->Unicode
= !Ansi
;
381 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
385 // Check if CallProc handle and retrieve previous call proc address and set.
386 if (IsCallProcHandle(WndProc
))
388 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
389 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
392 Class
->lpfnWndProc
= chWndProc
;
397 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
398 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
400 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
402 chWndProc
= GETPFNSERVER(i
);
405 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
407 chWndProc
= GETPFNSERVER(i
);
411 // If match, set/reset to Server Side and clear ansi.
414 Class
->lpfnWndProc
= chWndProc
;
415 Class
->Unicode
= TRUE
;
416 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
417 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
421 Class
->Unicode
= !Ansi
;
424 Class
->CSF_flags
|= CSF_ANSIPROC
;
426 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
429 /* Update the clones */
430 chWndProc
= Class
->lpfnWndProc
;
432 Class
= Class
->pclsClone
;
433 while (Class
!= NULL
)
435 Class
->Unicode
= !Ansi
;
436 Class
->lpfnWndProc
= chWndProc
;
438 Class
= Class
->pclsNext
;
445 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
446 IN OUT PCLS
*ClassLink
,
452 ASSERT(Desktop
!= NULL
);
453 ASSERT(BaseClass
->pclsBase
== BaseClass
);
455 if (BaseClass
->rpdeskParent
== Desktop
)
457 /* It is most likely that a window is created on the same
458 desktop as the window class. */
463 if (BaseClass
->rpdeskParent
== NULL
)
465 ASSERT(BaseClass
->cWndReferenceCount
== 0);
466 ASSERT(BaseClass
->pclsClone
== NULL
);
468 /* Classes are also located in the shared heap when the class
469 was created before the thread attached to a desktop. As soon
470 as a window is created for such a class located on the shared
471 heap, the class is cloned into the desktop heap on which the
472 window is created. */
477 /* The user is asking for a class object on a different desktop,
479 Class
= BaseClass
->pclsClone
;
480 while (Class
!= NULL
)
482 if (Class
->rpdeskParent
== Desktop
)
484 ASSERT(Class
->pclsBase
== BaseClass
);
485 ASSERT(Class
->pclsClone
== NULL
);
489 Class
= Class
->pclsNext
;
495 /* The window is created on a different desktop, we need to
496 clone the class object to the desktop heap of the window! */
497 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
499 Class
= DesktopHeapAlloc(Desktop
,
503 /* Simply clone the class */
504 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
506 TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
508 /* Restore module address if default user class Ref: Bug 4778 */
509 if ( Class
->hModule
!= hModClient
&&
510 Class
->fnid
<= FNID_GHOST
&&
511 Class
->fnid
>= FNID_BUTTON
)
513 Class
->hModule
= hModClient
;
514 TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class
, Class
->hModule
);
517 /* Update some pointers and link the class */
518 Class
->rpdeskParent
= Desktop
;
519 Class
->cWndReferenceCount
= 0;
521 if (BaseClass
->rpdeskParent
== NULL
)
523 /* We don't really need the base class on the shared
524 heap anymore, delete it so the only class left is
525 the clone we just created, which now serves as the
527 ASSERT(BaseClass
->pclsClone
== NULL
);
528 ASSERT(Class
->pclsClone
== NULL
);
529 Class
->pclsBase
= Class
;
530 Class
->pclsNext
= BaseClass
->pclsNext
;
532 /* Replace the base class */
533 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
536 /* Destroy the obsolete copy on the shared heap */
537 BaseClass
->pclsBase
= NULL
;
538 BaseClass
->pclsClone
= NULL
;
539 IntDestroyClass(BaseClass
);
543 /* Link in the clone */
544 Class
->pclsClone
= NULL
;
545 Class
->pclsBase
= BaseClass
;
546 Class
->pclsNext
= BaseClass
->pclsClone
;
547 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
553 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
560 IntReferenceClass(IN OUT PCLS BaseClass
,
561 IN OUT PCLS
*ClassLink
,
565 ASSERT(BaseClass
->pclsBase
== BaseClass
);
567 Class
= IntGetClassForDesktop(BaseClass
,
572 Class
->cWndReferenceCount
++;
580 IntMakeCloneBaseClass(IN OUT PCLS Class
,
581 IN OUT PCLS
*BaseClassLink
,
582 IN OUT PCLS
*CloneLink
)
586 ASSERT(Class
->pclsBase
!= Class
);
587 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
588 ASSERT(Class
->rpdeskParent
!= NULL
);
589 ASSERT(Class
->cWndReferenceCount
!= 0);
590 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
591 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
593 /* Unlink the clone */
594 *CloneLink
= Class
->pclsNext
;
595 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
597 /* Update the class information to make it a base class */
598 Class
->pclsBase
= Class
;
599 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
601 /* Update all clones */
602 Clone
= Class
->pclsClone
;
603 while (Clone
!= NULL
)
605 ASSERT(Clone
->pclsClone
== NULL
);
606 Clone
->pclsBase
= Class
;
608 Clone
= Clone
->pclsNext
;
611 /* Link in the new base class */
612 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
618 IntDereferenceClass(IN OUT PCLS Class
,
619 IN PDESKTOPINFO Desktop
,
622 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
624 ASSERT(Class
->cWndReferenceCount
>= 1);
626 BaseClass
= Class
->pclsBase
;
628 if (--Class
->cWndReferenceCount
== 0)
630 if (BaseClass
== Class
)
632 ASSERT(Class
->pclsBase
== Class
);
634 TRACE("IntDereferenceClass 0x%x\n", Class
);
635 /* Check if there are clones of the class on other desktops,
636 link the first clone in if possible. If there are no clones
637 then leave the class on the desktop heap. It will get moved
638 to the shared heap when the thread detaches. */
639 if (BaseClass
->pclsClone
!= NULL
)
641 if (BaseClass
->Global
)
642 PrevLink
= &pi
->pclsPublicList
;
644 PrevLink
= &pi
->pclsPrivateList
;
646 CurrentClass
= *PrevLink
;
647 while (CurrentClass
!= BaseClass
)
649 ASSERT(CurrentClass
!= NULL
);
651 PrevLink
= &CurrentClass
->pclsNext
;
652 CurrentClass
= CurrentClass
->pclsNext
;
655 ASSERT(*PrevLink
== BaseClass
);
657 /* Make the first clone become the new base class */
658 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
660 &BaseClass
->pclsClone
);
662 /* Destroy the class, there's still another clone of the class
663 that now serves as a base class. Make sure we don't destruct
664 resources shared by all classes (Base = NULL)! */
665 BaseClass
->pclsBase
= NULL
;
666 BaseClass
->pclsClone
= NULL
;
667 IntDestroyClass(BaseClass
);
672 TRACE("IntDereferenceClass1 0x%x\n", Class
);
674 /* Locate the cloned class and unlink it */
675 PrevLink
= &BaseClass
->pclsClone
;
676 CurrentClass
= BaseClass
->pclsClone
;
677 while (CurrentClass
!= Class
)
679 ASSERT(CurrentClass
!= NULL
);
681 PrevLink
= &CurrentClass
->pclsNext
;
682 CurrentClass
= CurrentClass
->pclsNext
;
685 ASSERT(CurrentClass
== Class
);
687 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
690 ASSERT(Class
->pclsBase
== BaseClass
);
691 ASSERT(Class
->pclsClone
== NULL
);
693 /* The class was just a clone, we don't need it anymore */
694 IntDestroyClass(Class
);
700 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
701 IN OUT PCLS
**ClassLinkPtr
)
706 ASSERT(Class
->pclsBase
== Class
);
707 ASSERT(Class
->rpdeskParent
!= NULL
);
708 ASSERT(Class
->cWndReferenceCount
== 0);
709 ASSERT(Class
->pclsClone
== NULL
);
711 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
713 /* Allocate the new base class on the shared heap */
714 NewClass
= UserHeapAlloc(ClassSize
);
715 if (NewClass
!= NULL
)
717 RtlCopyMemory(NewClass
,
721 NewClass
->rpdeskParent
= NULL
;
722 NewClass
->pclsBase
= NewClass
;
724 /* Replace the class in the list */
725 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
727 *ClassLinkPtr
= &NewClass
->pclsNext
;
729 /* Free the obsolete class on the desktop heap */
730 Class
->pclsBase
= NULL
;
731 IntDestroyClass(Class
);
739 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
740 IN OUT PCLS
*ClassList
,
741 IN BOOL FreeOnFailure
,
744 PCLS Class
, NextClass
, *Link
;
746 /* NOTE: We only need to check base classes! When classes are no longer needed
747 on a desktop, the clones will be freed automatically as soon as possible.
748 However, we need to move base classes to the shared heap, as soon as
749 the last desktop heap where a class is allocated on is about to be destroyed.
750 If we didn't move the class to the shared heap, the class would become
753 ASSERT(Desktop
!= NULL
);
757 while (Class
!= NULL
)
759 NextClass
= Class
->pclsNext
;
761 ASSERT(Class
->pclsBase
== Class
);
763 if (Class
->rpdeskParent
== Desktop
&&
764 Class
->cWndReferenceCount
== 0)
766 /* There shouldn't be any clones around anymore! */
767 ASSERT(Class
->pclsClone
== NULL
);
769 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
770 /* FIXME: We could move the class to another desktop heap if there's still desktops
771 mapped into the process... */
773 /* Move the class to the shared heap */
774 if (IntMoveClassToSharedHeap(Class
,
777 ASSERT(*Link
== NextClass
);
781 ASSERT(NextClass
== Class
->pclsNext
);
785 /* Unlink the base class */
786 (void)InterlockedExchangePointer((PVOID
*)Link
,
789 /* We can free the old base class now */
790 Class
->pclsBase
= NULL
;
791 IntDestroyClass(Class
);
795 Link
= &Class
->pclsNext
;
801 Link
= &Class
->pclsNext
;
808 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
809 IN BOOL FreeOnFailure
)
814 pi
= GetW32ProcessInfo();
816 /* Check all local classes */
817 IntCheckDesktopClasses(Desktop
,
818 &pi
->pclsPrivateList
,
822 /* Check all global classes */
823 IntCheckDesktopClasses(Desktop
,
829 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
830 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
838 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
839 IN PUNICODE_STRING ClassName
,
840 IN PUNICODE_STRING MenuName
,
850 PWSTR pszMenuName
= NULL
;
851 NTSTATUS Status
= STATUS_SUCCESS
;
853 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
854 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
856 if (!IntRegisterClassAtom(ClassName
,
859 ERR("Failed to register class atom!\n");
863 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
864 if (MenuName
->Length
!= 0)
866 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
867 RtlUnicodeStringToAnsiSize(MenuName
));
868 if (pszMenuName
== NULL
)
874 Class
= DesktopHeapAlloc(Desktop
,
879 /* FIXME: The class was created before being connected
880 to a desktop. It is possible for the desktop window,
881 but should it be allowed for any other case? */
882 Class
= UserHeapAlloc(ClassSize
);
889 RtlZeroMemory(Class
, ClassSize
);
891 Class
->rpdeskParent
= Desktop
;
892 Class
->pclsBase
= Class
;
893 Class
->atomClassName
= Atom
;
895 Class
->CSF_flags
= dwFlags
;
897 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
899 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
904 PWSTR pszMenuNameBuffer
= pszMenuName
;
906 /* Need to protect with SEH since accessing the WNDCLASSEX structure
907 and string buffers might raise an exception! We don't want to
909 // What?! If the user interface was written correctly this would not be an issue!
910 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
911 Class
->style
= lpwcx
->style
;
912 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
913 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
914 Class
->hModule
= lpwcx
->hInstance
;
915 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
916 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
917 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
918 Class
->hbrBackground
= lpwcx
->hbrBackground
;
920 /* Make a copy of the string */
921 if (pszMenuNameBuffer
!= NULL
)
923 Class
->MenuNameIsString
= TRUE
;
925 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
926 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
929 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
931 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
934 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
936 /* Save an ANSI copy of the string */
937 if (pszMenuNameBuffer
!= NULL
)
939 ANSI_STRING AnsiString
;
941 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
942 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
943 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
944 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
947 if (!NT_SUCCESS(Status
))
949 ERR("Failed to convert unicode menu name to ansi!\n");
951 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
956 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
958 /* Save kernel use menu name and ansi class name */
959 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // FIXME!
960 //Class->lpszAnsiClassName = FIXME
962 /* Server Side overrides class calling type (A/W)!
963 User32 whine test_builtinproc: "deftest"
964 built-in winproc - window A/W type automatically detected */
965 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
969 /* Due to the wine class "deftest" and most likely no FNID to reference
970 from, sort through the Server Side list and compare proc addresses
971 for match. This method will be used in related code.
973 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
974 { // Open ANSI or Unicode, just match, set and break.
975 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
977 WndProc
= GETPFNSERVER(i
);
980 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
982 WndProc
= GETPFNSERVER(i
);
987 { // If a hit, we are Server Side so set the right flags and proc.
988 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
989 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
990 Class
->lpfnWndProc
= WndProc
;
994 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
995 Class
->Unicode
= TRUE
;
997 if (Class
->style
& CS_GLOBALCLASS
)
998 Class
->Global
= TRUE
;
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1002 Status
= _SEH2_GetExceptionCode();
1006 if (!NT_SUCCESS(Status
))
1008 ERR("Failed creating the class: 0x%x\n", Status
);
1010 SetLastNtError(Status
);
1012 if (pszMenuName
!= NULL
)
1013 UserHeapFree(pszMenuName
);
1015 DesktopHeapFree(Desktop
,
1019 IntDeregisterClassAtom(Atom
);
1025 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1027 if (pszMenuName
!= NULL
)
1028 UserHeapFree(pszMenuName
);
1030 IntDeregisterClassAtom(Atom
);
1032 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1035 TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
1036 Class
, ClassName
, Class
->lpfnWndProc
, Atom
, Class
->hModule
, Class
->Global
);
1042 IntFindClass(IN RTL_ATOM Atom
,
1043 IN HINSTANCE hInstance
,
1045 OUT PCLS
**Link OPTIONAL
)
1047 PCLS Class
, *PrevLink
= ClassList
;
1050 while (Class
!= NULL
)
1052 if (Class
->atomClassName
== Atom
&&
1053 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1054 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1056 ASSERT(Class
->pclsBase
== Class
);
1063 PrevLink
= &Class
->pclsNext
;
1064 Class
= Class
->pclsNext
;
1071 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1076 if (ClassName
->Length
!= 0)
1082 /* NOTE: Caller has to protect the call with SEH! */
1084 if (ClassName
->Length
!= 0)
1086 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1087 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1089 EngSetLastError(ERROR_INVALID_PARAMETER
);
1093 /* We need to make a local copy of the class name! The caller could
1094 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1095 We're protected by SEH, but the ranges that might be accessed were
1097 RtlCopyMemory(szBuf
,
1100 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1104 AtomName
= ClassName
->Buffer
;
1106 /* Lookup the atom */
1107 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1110 if (NT_SUCCESS(Status
))
1116 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1118 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1122 SetLastNtError(Status
);
1128 ASSERT(IS_ATOM(ClassName
->Buffer
));
1129 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1137 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1138 IN HINSTANCE hInstance OPTIONAL
,
1139 IN PPROCESSINFO pi OPTIONAL
,
1140 OUT PCLS
*BaseClass OPTIONAL
,
1141 OUT PCLS
**Link OPTIONAL
)
1143 RTL_ATOM Atom
= (RTL_ATOM
)0;
1145 ASSERT(BaseClass
!= NULL
);
1147 if (IntGetAtomFromStringOrAtom(ClassName
,
1149 Atom
!= (RTL_ATOM
)0)
1153 /* Attempt to locate the class object */
1157 /* Step 1: Try to find an exact match of locally registered classes */
1158 Class
= IntFindClass(Atom
,
1160 &pi
->pclsPrivateList
,
1163 { TRACE("Step 1: 0x%x\n",Class
);
1167 /* Step 2: Try to find any globally registered class. The hInstance
1168 is not relevant for global classes */
1169 Class
= IntFindClass(Atom
,
1171 &pi
->pclsPublicList
,
1174 { TRACE("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1178 /* Step 3: Try to find any local class registered by user32 */
1179 Class
= IntFindClass(Atom
,
1181 &pi
->pclsPrivateList
,
1184 { TRACE("Step 3: 0x%x\n",Class
);
1188 /* Step 4: Try to find any global class registered by user32 */
1189 Class
= IntFindClass(Atom
,
1191 &pi
->pclsPublicList
,
1195 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1197 }else{TRACE("Step 4: 0x%x\n",Class
);}
1207 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
)
1209 PCLS
*ClassLink
, Class
= NULL
;
1213 pti
= PsGetCurrentThreadWin32Thread();
1215 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1217 UserRegisterSystemClasses();
1220 /* Check the class. */
1222 TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName
, hInstance
);
1224 ClassAtom
= IntGetClassAtom(ClassName
,
1230 if (ClassAtom
== (RTL_ATOM
)0)
1232 if (IS_ATOM(ClassName
->Buffer
))
1234 ERR("Class 0x%p not found\n", (DWORD_PTR
) ClassName
->Buffer
);
1238 ERR("Class \"%wZ\" not found\n", ClassName
);
1241 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1245 TRACE("Referencing Class 0x%x with atom 0x%x\n", Class
, ClassAtom
);
1246 Class
= IntReferenceClass(Class
,
1251 ERR("Failed to reference window class!\n");
1259 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1260 IN PUNICODE_STRING ClassName
,
1261 IN PUNICODE_STRING MenuName
,
1269 RTL_ATOM Ret
= (RTL_ATOM
)0;
1271 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1273 pti
= GetW32ThreadInfo();
1277 // Need only to test for two conditions not four....... Fix more whine tests....
1278 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1279 ClassAtom
!= (RTL_ATOM
)0 &&
1280 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1282 Class
= IntFindClass( ClassAtom
,
1284 &pi
->pclsPrivateList
,
1287 if (Class
!= NULL
&& !Class
->Global
)
1289 // Local class already exists
1290 TRACE("Local Class 0x%p does already exist!\n", ClassAtom
);
1291 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1295 if (lpwcx
->style
& CS_GLOBALCLASS
)
1297 Class
= IntFindClass( ClassAtom
,
1299 &pi
->pclsPublicList
,
1302 if (Class
!= NULL
&& Class
->Global
)
1304 TRACE("Global Class 0x%p does already exist!\n", ClassAtom
);
1305 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1311 Class
= IntCreateClass(lpwcx
,
1323 /* Register the class */
1325 List
= &pi
->pclsPublicList
;
1327 List
= &pi
->pclsPrivateList
;
1329 Class
->pclsNext
= *List
;
1330 (void)InterlockedExchangePointer((PVOID
*)List
,
1333 Ret
= Class
->atomClassName
;
1337 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1344 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1345 IN HINSTANCE hInstance
,
1346 OUT PCLSMENUNAME pClassMenuName
)
1353 pi
= GetW32ProcessInfo();
1355 TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1357 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1358 ClassAtom
= IntGetClassAtom(ClassName
,
1363 if (ClassAtom
== (RTL_ATOM
)0)
1365 TRACE("UserUnregisterClass: No Class found.\n");
1369 ASSERT(Class
!= NULL
);
1371 if (Class
->cWndReferenceCount
!= 0 ||
1372 Class
->pclsClone
!= NULL
)
1374 TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1375 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1379 /* Must be a base class! */
1380 ASSERT(Class
->pclsBase
== Class
);
1382 /* Unlink the class */
1383 *Link
= Class
->pclsNext
;
1385 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1387 TRACE("Class 0x%x\n", Class
);
1388 TRACE("UserUnregisterClass: Good Exit!\n");
1389 /* Finally free the resources */
1390 IntDestroyClass(Class
);
1393 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1398 UserGetClassName(IN PCLS Class
,
1399 IN OUT PUNICODE_STRING ClassName
,
1403 NTSTATUS Status
= STATUS_SUCCESS
;
1404 WCHAR szStaticTemp
[32];
1405 PWSTR szTemp
= NULL
;
1406 ULONG BufLen
= sizeof(szStaticTemp
);
1409 /* Note: Accessing the buffer in ClassName may raise an exception! */
1415 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1416 UNICODE_STRING UnicodeClassName
;
1418 /* Limit the size of the static buffer on the stack to the
1419 size of the buffer provided by the caller */
1420 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1422 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1425 /* Find out how big the buffer needs to be */
1426 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1427 Class
->atomClassName
,
1432 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1434 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1436 /* The buffer required exceeds the ansi buffer provided,
1437 pretend like we're using the ansi buffer and limit the
1438 size to the buffer size provided */
1439 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1442 /* Allocate a temporary buffer that can hold the unicode class name */
1443 szTemp
= ExAllocatePoolWithTag(PagedPool
,
1448 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1452 /* Query the class name */
1453 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1454 Atom
? Atom
: Class
->atomClassName
,
1461 szTemp
= szStaticTemp
;
1463 if (NT_SUCCESS(Status
))
1465 /* Convert the atom name to ansi */
1467 RtlInitUnicodeString(&UnicodeClassName
,
1470 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1473 if (!NT_SUCCESS(Status
))
1475 SetLastNtError(Status
);
1480 Ret
= BufLen
/ sizeof(WCHAR
);
1484 BufLen
= ClassName
->MaximumLength
;
1486 /* Query the atom name */
1487 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1488 Atom
? Atom
: Class
->atomClassName
,
1494 if (!NT_SUCCESS(Status
))
1496 SetLastNtError(Status
);
1500 Ret
= BufLen
/ sizeof(WCHAR
);
1503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1505 SetLastNtError(_SEH2_GetExceptionCode());
1509 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1518 IntSetClassMenuName(IN PCLS Class
,
1519 IN PUNICODE_STRING MenuName
)
1523 /* Change the base class first */
1524 Class
= Class
->pclsBase
;
1526 if (MenuName
->Length
!= 0)
1528 ANSI_STRING AnsiString
;
1531 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(MenuName
);
1533 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1534 AnsiString
.MaximumLength
);
1535 if (strBufW
!= NULL
)
1541 /* Copy the unicode string */
1542 RtlCopyMemory(strBufW
,
1545 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1547 /* Create an ANSI copy of the string */
1548 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1549 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1552 if (!NT_SUCCESS(Status
))
1554 SetLastNtError(Status
);
1560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1562 SetLastNtError(_SEH2_GetExceptionCode());
1568 /* Update the base class */
1569 IntFreeClassMenuName(Class
);
1570 Class
->lpszClientUnicodeMenuName
= strBufW
;
1571 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1572 Class
->MenuNameIsString
= TRUE
;
1574 /* Update the clones */
1575 Class
= Class
->pclsClone
;
1576 while (Class
!= NULL
)
1578 Class
->lpszClientUnicodeMenuName
= strBufW
;
1579 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1580 Class
->MenuNameIsString
= TRUE
;
1582 Class
= Class
->pclsNext
;
1587 ERR("Failed to copy class menu name!\n");
1588 UserHeapFree(strBufW
);
1592 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1596 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1598 /* Update the base class */
1599 IntFreeClassMenuName(Class
);
1600 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1601 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1602 Class
->MenuNameIsString
= FALSE
;
1604 /* Update the clones */
1605 Class
= Class
->pclsClone
;
1606 while (Class
!= NULL
)
1608 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1609 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1610 Class
->MenuNameIsString
= FALSE
;
1612 Class
= Class
->pclsNext
;
1622 UserSetClassLongPtr(IN PCLS Class
,
1624 IN ULONG_PTR NewLong
,
1629 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1631 /* Change the information in the base class first, then update the clones */
1632 Class
= Class
->pclsBase
;
1638 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1640 if (((ULONG
)Index
+ sizeof(ULONG_PTR
)) < (ULONG
)Index
||
1641 ((ULONG
)Index
+ sizeof(ULONG_PTR
)) > (ULONG
)Class
->cbclsExtra
)
1643 EngSetLastError(ERROR_INVALID_PARAMETER
);
1647 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1649 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1650 certain architectures, maybe using RtlCopyMemory is a
1651 better choice for those architectures! */
1655 /* Update the clones */
1656 Class
= Class
->pclsClone
;
1657 while (Class
!= NULL
)
1659 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1660 Class
= Class
->pclsNext
;
1668 case GCL_CBWNDEXTRA
:
1669 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1670 Class
->cbwndExtra
= (INT
)NewLong
;
1672 /* Update the clones */
1673 Class
= Class
->pclsClone
;
1674 while (Class
!= NULL
)
1676 Class
->cbwndExtra
= (INT
)NewLong
;
1677 Class
= Class
->pclsNext
;
1682 case GCL_CBCLSEXTRA
:
1683 EngSetLastError(ERROR_INVALID_PARAMETER
);
1686 case GCLP_HBRBACKGROUND
:
1687 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1688 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1690 /* Update the clones */
1691 Class
= Class
->pclsClone
;
1692 while (Class
!= NULL
)
1694 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1695 Class
= Class
->pclsNext
;
1700 /* FIXME: Get handle from pointer to CURSOR object */
1701 Ret
= (ULONG_PTR
)Class
->hCursor
;
1702 Class
->hCursor
= (HANDLE
)NewLong
;
1704 /* Update the clones */
1705 Class
= Class
->pclsClone
;
1706 while (Class
!= NULL
)
1708 Class
->hCursor
= (HANDLE
)NewLong
;
1709 Class
= Class
->pclsNext
;
1714 /* FIXME: Get handle from pointer to ICON object */
1715 Ret
= (ULONG_PTR
)Class
->hIcon
;
1716 Class
->hIcon
= (HANDLE
)NewLong
;
1718 /* Update the clones */
1719 Class
= Class
->pclsClone
;
1720 while (Class
!= NULL
)
1722 Class
->hIcon
= (HANDLE
)NewLong
;
1723 Class
= Class
->pclsNext
;
1728 /* FIXME: Get handle from pointer to ICON object */
1729 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1730 Class
->hIconSm
= (HANDLE
)NewLong
;
1732 /* Update the clones */
1733 Class
= Class
->pclsClone
;
1734 while (Class
!= NULL
)
1736 Class
->hIconSm
= (HANDLE
)NewLong
;
1737 Class
= Class
->pclsNext
;
1742 Ret
= (ULONG_PTR
)Class
->hModule
;
1743 Class
->hModule
= (HINSTANCE
)NewLong
;
1745 /* Update the clones */
1746 Class
= Class
->pclsClone
;
1747 while (Class
!= NULL
)
1749 Class
->hModule
= (HINSTANCE
)NewLong
;
1750 Class
= Class
->pclsNext
;
1756 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1758 if (!IntSetClassMenuName(Class
,
1761 ERR("Setting the class menu name failed!\n");
1764 /* FIXME: Really return NULL? Wine does so... */
1769 Ret
= (ULONG_PTR
)Class
->style
;
1770 Class
->style
= (UINT
)NewLong
;
1772 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
1773 move the class to the appropriate list? For now, we save
1774 the original value in Class->Global, so we can always
1775 locate the appropriate list */
1777 /* Update the clones */
1778 Class
= Class
->pclsClone
;
1779 while (Class
!= NULL
)
1781 Class
->style
= (UINT
)NewLong
;
1782 Class
= Class
->pclsNext
;
1787 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1794 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1796 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1797 if (!IntSetClassAtom(Class
,
1806 EngSetLastError(ERROR_INVALID_INDEX
);
1814 UserGetClassInfo(IN PCLS Class
,
1815 OUT PWNDCLASSEXW lpwcx
,
1817 HINSTANCE hInstance
)
1819 if (!Class
) return FALSE
;
1821 lpwcx
->style
= Class
->style
;
1823 // If fnId is set, clear the global bit. See wine class test check_style.
1825 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1827 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1829 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1830 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1831 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME: Get handle from pointer */
1832 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME: Get handle from pointer */
1833 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1835 /* Copy non-string to user first. */
1837 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1839 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1841 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
1842 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1843 * lpszClientXxxMenuName should already be mapped to user space.
1845 /* Copy string ptr to user. */
1846 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1847 Class
->MenuNameIsString
)
1849 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1850 (PVOID
)Class
->lpszClientAnsiMenuName
:
1851 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1854 if (hInstance
== hModClient
)
1855 lpwcx
->hInstance
= NULL
;
1857 lpwcx
->hInstance
= hInstance
;
1859 /* FIXME: Return the string? Okay! This is performed in User32! */
1860 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1862 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME: Get handle from pointer */
1872 UserRegisterSystemClasses(VOID
)
1875 UNICODE_STRING ClassName
, MenuName
;
1876 PPROCESSINFO ppi
= GetW32ProcessInfo();
1882 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1885 if ( hModClient
== NULL
)
1888 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1889 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1891 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1893 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1895 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1899 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1900 ClassName
.Length
= 0;
1901 ClassName
.MaximumLength
= 0;
1904 wc
.cbSize
= sizeof(wc
);
1905 wc
.style
= DefaultServerClasses
[i
].Style
;
1907 Flags
|= CSF_SERVERSIDEPROC
;
1909 if (DefaultServerClasses
[i
].ProcW
)
1911 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1912 wc
.hInstance
= hModuleWin
;
1916 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1917 wc
.hInstance
= hModClient
;
1921 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1923 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1924 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1925 wc
.lpszMenuName
= NULL
;
1926 wc
.lpszClassName
= ClassName
.Buffer
;
1929 Class
= IntCreateClass( &wc
,
1932 DefaultServerClasses
[i
].fiId
,
1938 Class
->pclsNext
= ppi
->pclsPublicList
;
1939 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1942 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1946 ERR("!!! Registering system class failed!\n");
1950 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1954 /* SYSCALLS *****************************************************************/
1958 NtUserRegisterClassExWOW(
1960 PUNICODE_STRING ClassName
,
1961 PUNICODE_STRING ClsNVersion
,
1962 PCLSMENUNAME pClassMenuName
,
1968 * Registers a new class with the window manager
1970 * lpwcx = Win32 extended window class structure
1971 * bUnicodeClass = Whether to send ANSI or unicode strings
1972 * to window procedures
1974 * Atom identifying the new class
1977 WNDCLASSEXW CapturedClassInfo
= {0};
1978 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
1979 RTL_ATOM Ret
= (RTL_ATOM
)0;
1980 PPROCESSINFO ppi
= GetW32ProcessInfo();
1982 if (Flags
& ~(CSF_ANSIPROC
))
1984 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
1985 EngSetLastError(ERROR_INVALID_FLAGS
);
1989 UserEnterExclusive();
1991 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
1993 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1995 UserRegisterSystemClasses();
2000 /* Probe the parameters and basic parameter checks */
2001 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2003 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2004 goto InvalidParameter
;
2008 sizeof(WNDCLASSEXW
),
2010 RtlCopyMemory(&CapturedClassInfo
,
2012 sizeof(WNDCLASSEXW
));
2014 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2016 ProbeForRead(pClassMenuName
,
2017 sizeof(CLSMENUNAME
),
2020 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2022 if ( (CapturedName
.Length
& 1) ||
2023 (CapturedMenuName
.Length
& 1) ||
2024 (CapturedClassInfo
.cbClsExtra
< 0) ||
2025 ((CapturedClassInfo
.cbClsExtra
+ CapturedName
.Length
+
2026 CapturedMenuName
.Length
+ sizeof(CLS
))
2027 < (ULONG
)CapturedClassInfo
.cbClsExtra
) ||
2028 (CapturedClassInfo
.cbWndExtra
< 0) ||
2029 (CapturedClassInfo
.hInstance
== NULL
) )
2031 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2032 goto InvalidParameter
;
2035 if (CapturedName
.Length
!= 0)
2037 ProbeForRead(CapturedName
.Buffer
,
2038 CapturedName
.Length
,
2043 if (!IS_ATOM(CapturedName
.Buffer
))
2045 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2046 goto InvalidParameter
;
2050 if (CapturedMenuName
.Length
!= 0)
2052 ProbeForRead(CapturedMenuName
.Buffer
,
2053 CapturedMenuName
.Length
,
2056 else if (CapturedMenuName
.Buffer
!= NULL
&&
2057 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2059 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2061 EngSetLastError(ERROR_INVALID_PARAMETER
);
2065 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2066 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2067 // If this pops up we know what todo!
2068 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2071 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2073 /* Register the class */
2074 Ret
= UserRegisterClass(&CapturedClassInfo
,
2080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2082 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2083 SetLastNtError(_SEH2_GetExceptionCode());
2089 ERR("NtUserRegisterClassExWOW Null Return!\n");
2098 NtUserSetClassLong(HWND hWnd
,
2100 ULONG_PTR dwNewLong
,
2107 UserEnterExclusive();
2109 pi
= GetW32ProcessInfo();
2111 Window
= UserGetWindowObject(hWnd
);
2114 if (Window
->head
.pti
->ppi
!= pi
)
2116 EngSetLastError(ERROR_ACCESS_DENIED
);
2122 UNICODE_STRING Value
;
2124 /* Probe the parameters */
2125 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2127 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2128 if (Value
.Length
& 1)
2130 goto InvalidParameter
;
2133 if (Value
.Length
!= 0)
2135 ProbeForRead(Value
.Buffer
,
2141 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2143 goto InvalidParameter
;
2145 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2148 EngSetLastError(ERROR_INVALID_PARAMETER
);
2153 dwNewLong
= (ULONG_PTR
)&Value
;
2156 Ret
= UserSetClassLongPtr(Window
->pcls
,
2161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2163 SetLastNtError(_SEH2_GetExceptionCode());
2182 * NOTE: Obsoleted in 32-bit windows
2188 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2189 IN HINSTANCE hInstance
,
2190 OUT PCLSMENUNAME pClassMenuName
)
2192 UNICODE_STRING CapturedClassName
;
2195 UserEnterExclusive();
2199 /* Probe the paramters */
2200 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2201 if (CapturedClassName
.Length
& 1)
2203 goto InvalidParameter
;
2206 if (CapturedClassName
.Length
!= 0)
2208 ProbeForRead(CapturedClassName
.Buffer
,
2209 CapturedClassName
.Length
,
2214 if (!IS_ATOM(CapturedClassName
.Buffer
))
2217 EngSetLastError(ERROR_INVALID_PARAMETER
);
2222 /* Unregister the class */
2223 Ret
= UserUnregisterClass(&CapturedClassName
,
2225 NULL
); // Null for now~
2227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2229 SetLastNtError(_SEH2_GetExceptionCode());
2237 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2240 HINSTANCE hInstance
,
2241 PUNICODE_STRING ClassName
,
2242 LPWNDCLASSEXW lpWndClassEx
,
2243 LPWSTR
*ppszMenuName
,
2246 UNICODE_STRING CapturedClassName
, SafeClassName
;
2247 WNDCLASSEXW Safewcexw
;
2249 RTL_ATOM ClassAtom
= 0;
2253 /* NOTE: Need exclusive lock because getting the wndproc might require the
2254 creation of a call procedure handle */
2255 UserEnterExclusive();
2257 ppi
= GetW32ProcessInfo();
2259 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2261 UserRegisterSystemClasses();
2266 /* Probe the paramters */
2267 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2269 if (CapturedClassName
.Length
== 0)
2271 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2275 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2278 if (CapturedClassName
.Length
& 1)
2280 EngSetLastError(ERROR_INVALID_PARAMETER
);
2285 if (CapturedClassName
.Length
!= 0)
2287 ProbeForRead( CapturedClassName
.Buffer
,
2288 CapturedClassName
.Length
,
2291 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2293 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2294 SafeClassName
.MaximumLength
,
2296 RtlCopyMemory( SafeClassName
.Buffer
,
2297 CapturedClassName
.Buffer
,
2298 SafeClassName
.MaximumLength
);
2302 if (!IS_ATOM(CapturedClassName
.Buffer
))
2304 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2305 EngSetLastError(ERROR_INVALID_PARAMETER
);
2310 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2311 SafeClassName
.Length
= 0;
2312 SafeClassName
.MaximumLength
= 0;
2315 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2317 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2321 SetLastNtError(_SEH2_GetExceptionCode());
2326 // If null instance use client.
2327 if (!hInstance
) hInstance
= hModClient
;
2331 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName
, hInstance
);
2332 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2337 if (ClassAtom
!= (RTL_ATOM
)0)
2339 if (hInstance
== NULL
) hInstance
= hModClient
;
2341 Ret
= UserGetClassInfo( Class
,
2348 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2356 /* Emulate Function. */
2357 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2359 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2362 /* We must return the atom of the class here instead of just TRUE. */
2363 /* Undocumented behavior! Return the class atom as a BOOL! */
2364 Ret
= (BOOL
)ClassAtom
;
2367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2369 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2374 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2381 NtUserGetClassName (IN HWND hWnd
,
2383 OUT PUNICODE_STRING ClassName
)
2386 UNICODE_STRING CapturedClassName
;
2392 Window
= UserGetWindowObject(hWnd
);
2395 if (Real
&& Window
->fnid
&& !(Window
->fnid
& FNID_DESTROY
))
2397 if (LookupFnIdToiCls(Window
->fnid
, &iCls
))
2399 Atom
= gpsi
->atomSysClass
[iCls
];
2405 ProbeForWriteUnicodeString(ClassName
);
2406 CapturedClassName
= *ClassName
;
2408 /* Get the class name */
2409 Ret
= UserGetClassName(Window
->pcls
,
2416 /* Update the Length field */
2417 ClassName
->Length
= CapturedClassName
.Length
;
2420 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2422 SetLastNtError(_SEH2_GetExceptionCode());
2432 /* Return Pointer to Class structure. */
2434 NtUserGetWOWClass(HINSTANCE hInstance
,
2435 PUNICODE_STRING ClassName
)
2437 UNICODE_STRING SafeClassName
;
2440 RTL_ATOM ClassAtom
= 0;
2443 UserEnterExclusive();
2445 pi
= GetW32ProcessInfo();
2449 if (ClassName
->Length
!= 0)
2451 ProbeForRead( ClassName
->Buffer
,
2455 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2457 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2458 SafeClassName
.MaximumLength
,
2460 RtlCopyMemory( SafeClassName
.Buffer
,
2462 SafeClassName
.MaximumLength
);
2466 if (!IS_ATOM(ClassName
->Buffer
))
2468 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2473 SafeClassName
.Buffer
= ClassName
->Buffer
;
2474 SafeClassName
.Length
= 0;
2475 SafeClassName
.MaximumLength
= 0;
2479 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2481 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2488 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2495 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2499 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2502 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.