2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
8 * 06-06-2001 CSH Created
10 /* INCLUDES ******************************************************************/
20 REGISTER_SYSCLASS DefaultServerClasses
[] =
22 /* { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
23 CS_GLOBALCLASS|CS_DBLCLKS,
27 (HBRUSH)(COLOR_BACKGROUND+1),
31 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
32 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
33 NULL
, // Use User32 procs
40 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
41 CS_DBLCLKS
|CS_SAVEBITS
,
42 NULL
, // Use User32 procs
45 (HBRUSH
)(COLOR_MENU
+ 1),
50 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
51 NULL
, // Use User32 procs
58 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
60 NULL
, // Use User32 procs
69 NULL
, // Use User32 procs
83 { /* Function Ids to Class indexes. */
84 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
85 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
86 { FNID_MENU
, ICLS_MENU
},
87 { FNID_DESKTOP
, ICLS_DESKTOP
},
88 { FNID_SWITCH
, ICLS_SWITCH
},
89 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
90 { FNID_BUTTON
, ICLS_BUTTON
},
91 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
92 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
93 { FNID_DIALOG
, ICLS_DIALOG
},
94 { FNID_EDIT
, ICLS_EDIT
},
95 { FNID_LISTBOX
, ICLS_LISTBOX
},
96 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
97 { FNID_STATIC
, ICLS_STATIC
},
98 { FNID_IME
, ICLS_IME
},
99 { FNID_GHOST
, ICLS_GHOST
},
100 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
105 LookupFnIdToiCls(int FnId
, int *iCls
)
109 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
111 if (FnidToiCls
[i
].FnId
== FnId
)
113 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
121 /* WINDOWCLASS ***************************************************************/
124 IntFreeClassMenuName(IN OUT PCLS Class
)
126 /* free the menu name, if it was changed and allocated */
127 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
129 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
130 Class
->lpszClientUnicodeMenuName
= NULL
;
131 Class
->lpszClientAnsiMenuName
= NULL
;
136 IntDestroyClass(IN OUT PCLS Class
)
139 /* there shouldn't be any clones anymore */
140 ASSERT(Class
->cWndReferenceCount
== 0);
141 ASSERT(Class
->pclsClone
== NULL
);
143 if (Class
->pclsBase
== Class
)
145 PCALLPROCDATA CallProc
, NextCallProc
;
147 /* Destroy allocated callproc handles */
148 CallProc
= Class
->spcpdFirst
;
149 while (CallProc
!= NULL
)
151 NextCallProc
= CallProc
->spcpdNext
;
153 CallProc
->spcpdNext
= NULL
;
154 DestroyCallProc(NULL
,
157 CallProc
= NextCallProc
;
162 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
166 IntFreeClassMenuName(Class
);
169 pDesk
= Class
->rpdeskParent
;
170 Class
->rpdeskParent
= NULL
;
172 /* free the structure */
175 DesktopHeapFree(pDesk
, Class
);
184 /* clean all process classes. all process windows must cleaned first!! */
185 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
188 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
192 /* free all local classes */
193 Class
= pi
->pclsPrivateList
;
194 while (Class
!= NULL
)
196 pi
->pclsPrivateList
= Class
->pclsNext
;
198 ASSERT(Class
->pclsBase
== Class
);
199 IntDestroyClass(Class
);
201 Class
= pi
->pclsPrivateList
;
204 /* free all global classes */
205 Class
= pi
->pclsPublicList
;
206 while (Class
!= NULL
)
208 pi
->pclsPublicList
= Class
->pclsNext
;
210 ASSERT(Class
->pclsBase
== Class
);
211 IntDestroyClass(Class
);
213 Class
= pi
->pclsPublicList
;
219 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
226 if (ClassName
->Length
!= 0)
228 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
229 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
231 EngSetLastError(ERROR_INVALID_PARAMETER
);
238 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
242 AtomName
= ClassName
->Buffer
;
244 Status
= RtlAddAtomToAtomTable(gAtomTable
,
248 if (!NT_SUCCESS(Status
))
250 SetLastNtError(Status
);
258 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
260 return RtlDeleteAtomFromAtomTable(gAtomTable
,
265 UserAddCallProcToClass(IN OUT PCLS Class
,
266 IN PCALLPROCDATA CallProc
)
270 ASSERT(CallProc
->spcpdNext
== NULL
);
272 BaseClass
= Class
->pclsBase
;
273 ASSERT(CallProc
->spcpdNext
== NULL
);
274 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
275 BaseClass
->spcpdFirst
= CallProc
;
277 /* Update all clones */
278 Class
= Class
->pclsClone
;
279 while (Class
!= NULL
)
281 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
282 Class
= Class
->pclsNext
;
287 IntSetClassAtom(IN OUT PCLS Class
,
288 IN PUNICODE_STRING ClassName
)
290 RTL_ATOM Atom
= (RTL_ATOM
)0;
292 /* update the base class first */
293 Class
= Class
->pclsBase
;
295 if (!IntRegisterClassAtom(ClassName
,
301 IntDeregisterClassAtom(Class
->atomClassName
);
303 Class
->atomClassName
= Atom
;
305 /* update the clones */
306 Class
= Class
->pclsClone
;
307 while (Class
!= NULL
)
309 Class
->atomClassName
= Atom
;
311 Class
= Class
->pclsNext
;
318 // Same as User32:IntGetClsWndProc.
321 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
324 WNDPROC gcpd
= NULL
, Ret
= NULL
;
326 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
328 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
330 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
333 Ret
= GETPFNCLIENTA(i
);
335 Ret
= GETPFNCLIENTW(i
);
340 Ret
= Class
->lpfnWndProc
;
342 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
346 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
347 Ret
= GETPFNCLIENTA(Class
->fnid
);
351 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
352 Ret
= GETPFNCLIENTW(Class
->fnid
);
356 if ( Ret
!= Class
->lpfnWndProc
||
357 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
360 gcpd
= (WNDPROC
)UserGetCPD( Class
,
361 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
364 return (gcpd
? gcpd
: Ret
);
370 IntSetClassWndProc(IN OUT PCLS Class
,
376 WNDPROC Ret
, chWndProc
;
378 Ret
= IntGetClassWndProc(Class
, Ansi
);
380 // If Server Side, downgrade to Client Side.
381 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
383 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
384 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
385 Class
->Unicode
= !Ansi
;
388 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
392 // Check if CallProc handle and retrieve previous call proc address and set.
393 if (IsCallProcHandle(WndProc
))
395 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
396 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
399 Class
->lpfnWndProc
= chWndProc
;
404 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
405 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
407 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
409 chWndProc
= GETPFNSERVER(i
);
412 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
414 chWndProc
= GETPFNSERVER(i
);
418 // If match, set/reset to Server Side and clear ansi.
421 Class
->lpfnWndProc
= chWndProc
;
422 Class
->Unicode
= TRUE
;
423 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
424 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
428 Class
->Unicode
= !Ansi
;
431 Class
->CSF_flags
|= CSF_ANSIPROC
;
433 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
436 /* update the clones */
437 chWndProc
= Class
->lpfnWndProc
;
439 Class
= Class
->pclsClone
;
440 while (Class
!= NULL
)
442 Class
->Unicode
= !Ansi
;
443 Class
->lpfnWndProc
= chWndProc
;
445 Class
= Class
->pclsNext
;
452 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
453 IN OUT PCLS
*ClassLink
,
459 ASSERT(Desktop
!= NULL
);
460 ASSERT(BaseClass
->pclsBase
== BaseClass
);
462 if (BaseClass
->rpdeskParent
== Desktop
)
464 /* it is most likely that a window is created on the same
465 desktop as the window class. */
470 if (BaseClass
->rpdeskParent
== NULL
)
472 ASSERT(BaseClass
->cWndReferenceCount
== 0);
473 ASSERT(BaseClass
->pclsClone
== NULL
);
475 /* Classes are also located in the shared heap when the class
476 was created before the thread attached to a desktop. As soon
477 as a window is created for such a class located on the shared
478 heap, the class is cloned into the desktop heap on which the
479 window is created. */
484 /* The user is asking for a class object on a different desktop,
486 Class
= BaseClass
->pclsClone
;
487 while (Class
!= NULL
)
489 if (Class
->rpdeskParent
== Desktop
)
491 ASSERT(Class
->pclsBase
== BaseClass
);
492 ASSERT(Class
->pclsClone
== NULL
);
496 Class
= Class
->pclsNext
;
502 /* The window is created on a different desktop, we need to
503 clone the class object to the desktop heap of the window! */
504 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
506 Class
= DesktopHeapAlloc(Desktop
,
510 /* simply clone the class */
511 RtlCopyMemory( Class
, BaseClass
, ClassSize
);
513 DPRINT("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
515 /* restore module address if default user class Ref: Bug 4778 */
516 if ( Class
->hModule
!= hModClient
&&
517 Class
->fnid
<= FNID_GHOST
&&
518 Class
->fnid
>= FNID_BUTTON
)
520 Class
->hModule
= hModClient
;
521 DPRINT("Clone Class 0x%x Reset hM 0x%x\n",Class
, Class
->hModule
);
524 /* update some pointers and link the class */
525 Class
->rpdeskParent
= Desktop
;
526 Class
->cWndReferenceCount
= 0;
528 if (BaseClass
->rpdeskParent
== NULL
)
530 /* we don't really need the base class on the shared
531 heap anymore, delete it so the only class left is
532 the clone we just created, which now serves as the
534 ASSERT(BaseClass
->pclsClone
== NULL
);
535 ASSERT(Class
->pclsClone
== NULL
);
536 Class
->pclsBase
= Class
;
537 Class
->pclsNext
= BaseClass
->pclsNext
;
539 /* replace the base class */
540 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
543 /* destroy the obsolete copy on the shared heap */
544 BaseClass
->pclsBase
= NULL
;
545 BaseClass
->pclsClone
= NULL
;
546 IntDestroyClass(BaseClass
);
550 /* link in the clone */
551 Class
->pclsClone
= NULL
;
552 Class
->pclsBase
= BaseClass
;
553 Class
->pclsNext
= BaseClass
->pclsClone
;
554 (void)InterlockedExchangePointer((PVOID
*)&BaseClass
->pclsClone
,
560 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
567 IntReferenceClass(IN OUT PCLS BaseClass
,
568 IN OUT PCLS
*ClassLink
,
572 ASSERT(BaseClass
->pclsBase
== BaseClass
);
574 Class
= IntGetClassForDesktop(BaseClass
,
579 Class
->cWndReferenceCount
++;
587 IntMakeCloneBaseClass(IN OUT PCLS Class
,
588 IN OUT PCLS
*BaseClassLink
,
589 IN OUT PCLS
*CloneLink
)
593 ASSERT(Class
->pclsBase
!= Class
);
594 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
595 ASSERT(Class
->rpdeskParent
!= NULL
);
596 ASSERT(Class
->cWndReferenceCount
!= 0);
597 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
598 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
600 /* unlink the clone */
601 *CloneLink
= Class
->pclsNext
;
602 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
604 /* update the class information to make it a base class */
605 Class
->pclsBase
= Class
;
606 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
608 /* update all clones */
609 Clone
= Class
->pclsClone
;
610 while (Clone
!= NULL
)
612 ASSERT(Clone
->pclsClone
== NULL
);
613 Clone
->pclsBase
= Class
;
615 Clone
= Clone
->pclsNext
;
618 /* link in the new base class */
619 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
625 IntDereferenceClass(IN OUT PCLS Class
,
626 IN PDESKTOPINFO Desktop
,
629 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
631 BaseClass
= Class
->pclsBase
;
633 if (--Class
->cWndReferenceCount
<= 0)
635 if (BaseClass
== Class
)
637 ASSERT(Class
->pclsBase
== Class
);
639 DPRINT("IntDereferenceClass 0x%x\n", Class
);
640 /* check if there are clones of the class on other desktops,
641 link the first clone in if possible. If there are no clones
642 then leave the class on the desktop heap. It will get moved
643 to the shared heap when the thread detaches. */
644 if (BaseClass
->pclsClone
!= NULL
)
646 if (BaseClass
->Global
)
647 PrevLink
= &pi
->pclsPublicList
;
649 PrevLink
= &pi
->pclsPrivateList
;
651 CurrentClass
= *PrevLink
;
652 while (CurrentClass
!= BaseClass
)
654 ASSERT(CurrentClass
!= NULL
);
656 PrevLink
= &CurrentClass
->pclsNext
;
657 CurrentClass
= CurrentClass
->pclsNext
;
660 ASSERT(*PrevLink
== BaseClass
);
662 /* make the first clone become the new base class */
663 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
665 &BaseClass
->pclsClone
);
667 /* destroy the class, there's still another clone of the class
668 that now serves as a base class. Make sure we don't destruct
669 resources shared by all classes (Base = NULL)! */
670 BaseClass
->pclsBase
= NULL
;
671 BaseClass
->pclsClone
= NULL
;
672 IntDestroyClass(BaseClass
);
677 DPRINT("IntDereferenceClass1 0x%x\n", Class
);
679 /* locate the cloned class and unlink it */
680 PrevLink
= &BaseClass
->pclsClone
;
681 CurrentClass
= BaseClass
->pclsClone
;
682 while (CurrentClass
!= Class
)
684 ASSERT(CurrentClass
!= NULL
);
686 PrevLink
= &CurrentClass
->pclsNext
;
687 CurrentClass
= CurrentClass
->pclsNext
;
690 ASSERT(CurrentClass
== Class
);
692 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
695 ASSERT(Class
->pclsBase
== BaseClass
);
696 ASSERT(Class
->pclsClone
== NULL
);
698 /* the class was just a clone, we don't need it anymore */
699 IntDestroyClass(Class
);
705 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
706 IN OUT PCLS
**ClassLinkPtr
)
711 ASSERT(Class
->pclsBase
== Class
);
712 ASSERT(Class
->rpdeskParent
!= NULL
);
713 ASSERT(Class
->cWndReferenceCount
== 0);
714 ASSERT(Class
->pclsClone
== NULL
);
716 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
718 /* allocate the new base class on the shared heap */
719 NewClass
= UserHeapAlloc(ClassSize
);
720 if (NewClass
!= NULL
)
722 RtlCopyMemory(NewClass
,
726 NewClass
->rpdeskParent
= NULL
;
727 NewClass
->pclsBase
= NewClass
;
729 /* replace the class in the list */
730 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
732 *ClassLinkPtr
= &NewClass
->pclsNext
;
734 /* free the obsolete class on the desktop heap */
735 Class
->pclsBase
= NULL
;
736 IntDestroyClass(Class
);
744 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
745 IN OUT PCLS
*ClassList
,
746 IN BOOL FreeOnFailure
,
749 PCLS Class
, NextClass
, *Link
;
751 /* NOTE: We only need to check base classes! When classes are no longer needed
752 on a desktop, the clones will be freed automatically as soon as possible.
753 However, we need to move base classes to the shared heap, as soon as
754 the last desktop heap where a class is allocated on is about to be destroyed.
755 If we didn't move the class to the shared heap, the class would become
758 ASSERT(Desktop
!= NULL
);
762 while (Class
!= NULL
)
764 NextClass
= Class
->pclsNext
;
766 ASSERT(Class
->pclsBase
== Class
);
768 if (Class
->rpdeskParent
== Desktop
&&
769 Class
->cWndReferenceCount
== 0)
771 /* there shouldn't be any clones around anymore! */
772 ASSERT(Class
->pclsClone
== NULL
);
774 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
775 /* FIXME - We could move the class to another desktop heap if there's still desktops
776 mapped into the process... */
778 /* move the class to the shared heap */
779 if (IntMoveClassToSharedHeap(Class
,
782 ASSERT(*Link
== NextClass
);
786 ASSERT(NextClass
== Class
->pclsNext
);
790 /* unlink the base class */
791 (void)InterlockedExchangePointer((PVOID
*)Link
,
794 /* we can free the old base class now */
795 Class
->pclsBase
= NULL
;
796 IntDestroyClass(Class
);
800 Link
= &Class
->pclsNext
;
806 Link
= &Class
->pclsNext
;
813 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
814 IN BOOL FreeOnFailure
)
819 pi
= GetW32ProcessInfo();
821 /* check all local classes */
822 IntCheckDesktopClasses(Desktop
,
823 &pi
->pclsPrivateList
,
827 /* check all global classes */
828 IntCheckDesktopClasses(Desktop
,
834 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
835 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
843 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
844 IN PUNICODE_STRING ClassName
,
845 IN PUNICODE_STRING MenuName
,
855 PWSTR pszMenuName
= NULL
;
856 NTSTATUS Status
= STATUS_SUCCESS
;
858 DPRINT("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
859 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
861 if (!IntRegisterClassAtom(ClassName
,
864 DPRINT1("Failed to register class atom!\n");
868 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
869 if (MenuName
->Length
!= 0)
871 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
872 RtlUnicodeStringToAnsiSize(MenuName
));
873 if (pszMenuName
== NULL
)
879 Class
= DesktopHeapAlloc(Desktop
,
884 /* FIXME - the class was created before being connected
885 to a desktop. It is possible for the desktop window,
886 but should it be allowed for any other case? */
887 Class
= UserHeapAlloc(ClassSize
);
894 RtlZeroMemory(Class
, ClassSize
);
896 Class
->rpdeskParent
= Desktop
;
897 Class
->pclsBase
= Class
;
898 Class
->atomClassName
= Atom
;
900 Class
->CSF_flags
= dwFlags
;
902 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
904 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
909 PWSTR pszMenuNameBuffer
= pszMenuName
;
911 /* need to protect with SEH since accessing the WNDCLASSEX structure
912 and string buffers might raise an exception! We don't want to
914 // What?! If the user interface was written correctly this would not be an issue!
915 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
916 Class
->style
= lpwcx
->style
;
917 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
918 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
919 Class
->hModule
= lpwcx
->hInstance
;
920 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
921 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
922 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
923 Class
->hbrBackground
= lpwcx
->hbrBackground
;
925 /* make a copy of the string */
926 if (pszMenuNameBuffer
!= NULL
)
928 Class
->MenuNameIsString
= TRUE
;
930 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
931 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
934 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
936 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
939 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
941 /* save an ansi copy of the string */
942 if (pszMenuNameBuffer
!= NULL
)
944 ANSI_STRING AnsiString
;
946 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
947 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
948 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
949 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
952 if (!NT_SUCCESS(Status
))
954 DPRINT1("Failed to convert unicode menu name to ansi!\n");
956 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
961 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
963 /* Save kernel use menu name and ansi class name */
964 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
965 //Class->lpszAnsiClassName = Fixme!
967 /* Server Side overrides class calling type (A/W)!
968 User32 whine test_builtinproc: "deftest"
969 built-in winproc - window A/W type automatically detected */
970 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
974 /* Due to the wine class "deftest" and most likely no FNID to reference
975 from, sort through the Server Side list and compare proc addresses
976 for match. This method will be used in related code.
978 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
979 { // Open Ansi or Unicode, just match, set and break.
980 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
982 WndProc
= GETPFNSERVER(i
);
985 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
987 WndProc
= GETPFNSERVER(i
);
992 { // If a hit, we are Server Side so set the right flags and proc.
993 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
994 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
995 Class
->lpfnWndProc
= WndProc
;
999 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
1000 Class
->Unicode
= TRUE
;
1002 if (Class
->style
& CS_GLOBALCLASS
)
1003 Class
->Global
= TRUE
;
1005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1007 Status
= _SEH2_GetExceptionCode();
1011 if (!NT_SUCCESS(Status
))
1013 DPRINT1("Failed creating the class: 0x%x\n", Status
);
1015 SetLastNtError(Status
);
1017 if (pszMenuName
!= NULL
)
1018 UserHeapFree(pszMenuName
);
1020 DesktopHeapFree(Desktop
,
1024 IntDeregisterClassAtom(Atom
);
1030 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1032 if (pszMenuName
!= NULL
)
1033 UserHeapFree(pszMenuName
);
1035 IntDeregisterClassAtom(Atom
);
1037 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1044 IntFindClass(IN RTL_ATOM Atom
,
1045 IN HINSTANCE hInstance
,
1047 OUT PCLS
**Link OPTIONAL
)
1049 PCLS Class
, *PrevLink
= ClassList
;
1052 while (Class
!= NULL
)
1054 if (Class
->atomClassName
== Atom
&&
1055 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1056 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1058 ASSERT(Class
->pclsBase
== Class
);
1065 PrevLink
= &Class
->pclsNext
;
1066 Class
= Class
->pclsNext
;
1073 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1078 if (ClassName
->Length
!= 0)
1084 /* NOTE: Caller has to protect the call with SEH! */
1086 if (ClassName
->Length
!= 0)
1088 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1089 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1091 EngSetLastError(ERROR_INVALID_PARAMETER
);
1095 /* We need to make a local copy of the class name! The caller could
1096 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1097 We're protected by SEH, but the ranges that might be accessed were
1099 RtlCopyMemory(szBuf
,
1102 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1106 AtomName
= ClassName
->Buffer
;
1108 /* lookup the atom */
1109 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1112 if (NT_SUCCESS(Status
))
1118 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1120 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1124 SetLastNtError(Status
);
1130 ASSERT(IS_ATOM(ClassName
->Buffer
));
1131 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1139 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1140 IN HINSTANCE hInstance OPTIONAL
,
1141 IN PPROCESSINFO pi OPTIONAL
,
1142 OUT PCLS
*BaseClass OPTIONAL
,
1143 OUT PCLS
**Link OPTIONAL
)
1145 RTL_ATOM Atom
= (RTL_ATOM
)0;
1147 ASSERT(BaseClass
!= NULL
);
1149 if (IntGetAtomFromStringOrAtom(ClassName
,
1151 Atom
!= (RTL_ATOM
)0)
1155 /* attempt to locate the class object */
1159 /* Step 1: try to find an exact match of locally registered classes */
1160 Class
= IntFindClass(Atom
,
1162 &pi
->pclsPrivateList
,
1165 { DPRINT("Step 1: 0x%x\n",Class
);
1169 /* Step 2: try to find any globally registered class. The hInstance
1170 is not relevant for global classes */
1171 Class
= IntFindClass(Atom
,
1173 &pi
->pclsPublicList
,
1176 { DPRINT("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1180 /* Step 3: try to find any local class registered by user32 */
1181 Class
= IntFindClass(Atom
,
1183 &pi
->pclsPrivateList
,
1186 { DPRINT("Step 3: 0x%x\n",Class
);
1190 /* Step 4: try to find any global class registered by user32 */
1191 Class
= IntFindClass(Atom
,
1193 &pi
->pclsPublicList
,
1197 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
1199 }else{DPRINT("Step 4: 0x%x\n",Class
);}
1209 IntGetAndReferenceClass(PUNICODE_STRING ClassName
, HINSTANCE hInstance
)
1211 PCLS
*ClassLink
, Class
= NULL
;
1215 pti
= PsGetCurrentThreadWin32Thread();
1217 if ( !(pti
->ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
1219 UserRegisterSystemClasses();
1222 /* Check the class. */
1224 DPRINT("Class %wZ\n", ClassName
);
1226 ClassAtom
= IntGetClassAtom(ClassName
,
1232 if (ClassAtom
== (RTL_ATOM
)0)
1234 if (IS_ATOM(ClassName
->Buffer
))
1236 DPRINT1("Class 0x%p not found\n", (DWORD_PTR
) ClassName
->Buffer
);
1240 DPRINT1("Class \"%wZ\" not found\n", ClassName
);
1243 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS
);
1246 DPRINT("ClassAtom %x\n", ClassAtom
);
1247 Class
= IntReferenceClass(Class
,
1252 DPRINT1("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 DPRINT("Local Class 0x%p does already exist!\n", ClassAtom
);
1292 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1296 if (lpwcx
->style
& CS_GLOBALCLASS
)
1298 Class
= IntFindClass( ClassAtom
,
1300 &pi
->pclsPublicList
,
1303 if (Class
!= NULL
&& Class
->Global
)
1305 DPRINT("Global Class 0x%p does already exist!\n", ClassAtom
);
1306 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS
);
1312 Class
= IntCreateClass(lpwcx
,
1324 /* Register the class */
1326 List
= &pi
->pclsPublicList
;
1328 List
= &pi
->pclsPrivateList
;
1330 Class
->pclsNext
= *List
;
1331 (void)InterlockedExchangePointer((PVOID
*)List
,
1334 Ret
= Class
->atomClassName
;
1338 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1345 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1346 IN HINSTANCE hInstance
,
1347 OUT PCLSMENUNAME pClassMenuName
)
1354 pi
= GetW32ProcessInfo();
1356 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1358 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1359 ClassAtom
= IntGetClassAtom(ClassName
,
1364 if (ClassAtom
== (RTL_ATOM
)0)
1366 DPRINT("UserUnregisterClass: No Class found.\n");
1370 ASSERT(Class
!= NULL
);
1372 if (Class
->cWndReferenceCount
!= 0 ||
1373 Class
->pclsClone
!= NULL
)
1375 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1376 EngSetLastError(ERROR_CLASS_HAS_WINDOWS
);
1380 /* must be a base class! */
1381 ASSERT(Class
->pclsBase
== Class
);
1383 /* unlink the class */
1384 *Link
= Class
->pclsNext
;
1386 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1388 DPRINT("Class 0x%x\n", Class
);
1389 DPRINT("UserUnregisterClass: Good Exit!\n");
1390 /* finally free the resources */
1391 IntDestroyClass(Class
);
1394 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1399 UserGetClassName(IN PCLS Class
,
1400 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 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 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
= 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 DPRINT1("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 (Index
+ sizeof(ULONG_PTR
) < Index
||
1641 Index
+ sizeof(ULONG_PTR
) > 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 DPRINT1("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 WARN("!!! 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 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
1985 EngSetLastError(ERROR_INVALID_FLAGS
);
1989 UserEnterExclusive();
1991 DPRINT("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 DPRINT1("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
+
2026 CapturedName
.Length
+
2027 CapturedMenuName
.Length
+
2028 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2029 CapturedClassInfo
.cbWndExtra
< 0 ||
2030 CapturedClassInfo
.hInstance
== NULL
)
2032 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2033 goto InvalidParameter
;
2036 if (CapturedName
.Length
!= 0)
2038 ProbeForRead(CapturedName
.Buffer
,
2039 CapturedName
.Length
,
2044 if (!IS_ATOM(CapturedName
.Buffer
))
2046 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2047 goto InvalidParameter
;
2051 if (CapturedMenuName
.Length
!= 0)
2053 ProbeForRead(CapturedMenuName
.Buffer
,
2054 CapturedMenuName
.Length
,
2057 else if (CapturedMenuName
.Buffer
!= NULL
&&
2058 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2060 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2062 EngSetLastError(ERROR_INVALID_PARAMETER
);
2066 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2067 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2068 // If this pops up we know what todo!
2069 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2072 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2074 /* Register the class */
2075 Ret
= UserRegisterClass(&CapturedClassInfo
,
2081 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2083 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2084 SetLastNtError(_SEH2_GetExceptionCode());
2090 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2099 NtUserSetClassLong(HWND hWnd
,
2101 ULONG_PTR dwNewLong
,
2108 UserEnterExclusive();
2110 pi
= GetW32ProcessInfo();
2112 Window
= UserGetWindowObject(hWnd
);
2115 if (Window
->head
.pti
->ppi
!= pi
)
2117 EngSetLastError(ERROR_ACCESS_DENIED
);
2123 UNICODE_STRING Value
;
2125 /* probe the parameters */
2126 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2128 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2129 if (Value
.Length
& 1)
2131 goto InvalidParameter
;
2134 if (Value
.Length
!= 0)
2136 ProbeForRead(Value
.Buffer
,
2142 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2144 goto InvalidParameter
;
2146 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2149 EngSetLastError(ERROR_INVALID_PARAMETER
);
2154 dwNewLong
= (ULONG_PTR
)&Value
;
2157 Ret
= UserSetClassLongPtr(Window
->pcls
,
2162 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2164 SetLastNtError(_SEH2_GetExceptionCode());
2183 * NOTE: Obsoleted in 32-bit windows
2189 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2190 IN HINSTANCE hInstance
,
2191 OUT PCLSMENUNAME pClassMenuName
)
2193 UNICODE_STRING CapturedClassName
;
2196 UserEnterExclusive();
2200 /* probe the paramters */
2201 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2202 if (CapturedClassName
.Length
& 1)
2204 goto InvalidParameter
;
2207 if (CapturedClassName
.Length
!= 0)
2209 ProbeForRead(CapturedClassName
.Buffer
,
2210 CapturedClassName
.Length
,
2215 if (!IS_ATOM(CapturedClassName
.Buffer
))
2218 EngSetLastError(ERROR_INVALID_PARAMETER
);
2223 /* unregister the class */
2224 Ret
= UserUnregisterClass(&CapturedClassName
,
2226 NULL
); // Null for now~
2228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2230 SetLastNtError(_SEH2_GetExceptionCode());
2238 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2241 HINSTANCE hInstance
,
2242 PUNICODE_STRING ClassName
,
2243 LPWNDCLASSEXW lpWndClassEx
,
2244 LPWSTR
*ppszMenuName
,
2247 UNICODE_STRING CapturedClassName
, SafeClassName
;
2248 WNDCLASSEXW Safewcexw
;
2250 RTL_ATOM ClassAtom
= 0;
2254 /* NOTE: need exclusive lock because getting the wndproc might require the
2255 creation of a call procedure handle */
2256 UserEnterExclusive();
2258 ppi
= GetW32ProcessInfo();
2260 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2262 UserRegisterSystemClasses();
2267 /* probe the paramters */
2268 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2270 if (CapturedClassName
.Length
== 0)
2271 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2273 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2275 if (CapturedClassName
.Length
& 1)
2277 EngSetLastError(ERROR_INVALID_PARAMETER
);
2282 if (CapturedClassName
.Length
!= 0)
2284 ProbeForRead( CapturedClassName
.Buffer
,
2285 CapturedClassName
.Length
,
2288 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2290 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2291 SafeClassName
.MaximumLength
,
2293 RtlCopyMemory( SafeClassName
.Buffer
,
2294 CapturedClassName
.Buffer
,
2295 SafeClassName
.MaximumLength
);
2299 if (!IS_ATOM(CapturedClassName
.Buffer
))
2301 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2302 EngSetLastError(ERROR_INVALID_PARAMETER
);
2307 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2308 SafeClassName
.Length
= 0;
2309 SafeClassName
.MaximumLength
= 0;
2312 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2314 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2318 SetLastNtError(_SEH2_GetExceptionCode());
2323 // If null instance use client.
2324 if (!hInstance
) hInstance
= hModClient
;
2328 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName
, hInstance
);
2329 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2334 if (ClassAtom
!= (RTL_ATOM
)0)
2336 if (hInstance
== NULL
) hInstance
= hModClient
;
2338 Ret
= UserGetClassInfo( Class
,
2345 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2353 /* Emulate Function. */
2354 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2356 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2359 /* We must return the atom of the class here instead of just TRUE. */
2360 /* Undocumented behavior! Return the class atom as a BOOL! */
2361 Ret
= (BOOL
)ClassAtom
;
2364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2366 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2371 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2378 NtUserGetClassName (IN HWND hWnd
,
2379 OUT PUNICODE_STRING ClassName
,
2383 UNICODE_STRING CapturedClassName
;
2388 Window
= UserGetWindowObject(hWnd
);
2393 ProbeForWriteUnicodeString(ClassName
);
2394 CapturedClassName
= *ClassName
;
2396 /* get the class name */
2397 Ret
= UserGetClassName(Window
->pcls
,
2403 /* update the Length field */
2404 ClassName
->Length
= CapturedClassName
.Length
;
2407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2409 SetLastNtError(_SEH2_GetExceptionCode());
2419 /* Return Pointer to Class structure. */
2421 NtUserGetWOWClass(HINSTANCE hInstance
,
2422 PUNICODE_STRING ClassName
)
2424 UNICODE_STRING SafeClassName
;
2427 RTL_ATOM ClassAtom
= 0;
2430 UserEnterExclusive();
2432 pi
= GetW32ProcessInfo();
2436 if (ClassName
->Length
!= 0)
2438 ProbeForRead( ClassName
->Buffer
,
2442 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2444 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2445 SafeClassName
.MaximumLength
,
2447 RtlCopyMemory( SafeClassName
.Buffer
,
2449 SafeClassName
.MaximumLength
);
2453 if (!IS_ATOM(ClassName
->Buffer
))
2455 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2460 SafeClassName
.Buffer
= ClassName
->Buffer
;
2461 SafeClassName
.Length
= 0;
2462 SafeClassName
.MaximumLength
= 0;
2466 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2468 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2475 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2482 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST
);
2486 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2489 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.