2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
8 * 06-06-2001 CSH Created
10 /* INCLUDES ******************************************************************/
20 REGISTER_SYSCLASS DefaultServerClasses
[] =
22 /* { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
23 CS_GLOBALCLASS|CS_DBLCLKS,
27 (HBRUSH)(COLOR_BACKGROUND+1),
31 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8003))),
32 CS_VREDRAW
|CS_HREDRAW
|CS_SAVEBITS
,
33 NULL
, // Use User32 procs
40 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8000))),
41 CS_DBLCLKS
|CS_SAVEBITS
,
42 NULL
, // Use User32 procs
45 (HBRUSH
)(COLOR_MENU
+ 1),
50 CS_DBLCLKS
|CS_VREDRAW
|CS_HREDRAW
|CS_PARENTDC
,
51 NULL
, // Use User32 procs
58 { ((PWSTR
)((ULONG_PTR
)(WORD
)(0x8004))), // IconTitle is here for now...
60 NULL
, // Use User32 procs
69 NULL
, // Use User32 procs
83 { /* Function Ids to Class indexes. */
84 { FNID_SCROLLBAR
, ICLS_SCROLLBAR
},
85 { FNID_ICONTITLE
, ICLS_ICONTITLE
},
86 { FNID_MENU
, ICLS_MENU
},
87 { FNID_DESKTOP
, ICLS_DESKTOP
},
88 { FNID_SWITCH
, ICLS_SWITCH
},
89 { FNID_MESSAGEWND
, ICLS_HWNDMESSAGE
},
90 { FNID_BUTTON
, ICLS_BUTTON
},
91 { FNID_COMBOBOX
, ICLS_COMBOBOX
},
92 { FNID_COMBOLBOX
, ICLS_COMBOLBOX
},
93 { FNID_DIALOG
, ICLS_DIALOG
},
94 { FNID_EDIT
, ICLS_EDIT
},
95 { FNID_LISTBOX
, ICLS_LISTBOX
},
96 { FNID_MDICLIENT
, ICLS_MDICLIENT
},
97 { FNID_STATIC
, ICLS_STATIC
},
98 { FNID_IME
, ICLS_IME
},
99 { FNID_GHOST
, ICLS_GHOST
},
100 { FNID_TOOLTIPS
, ICLS_TOOLTIPS
}
105 LookupFnIdToiCls(int FnId
, int *iCls
)
109 for ( i
= 0; i
< ARRAYSIZE(FnidToiCls
); i
++)
111 if (FnidToiCls
[i
].FnId
== FnId
)
113 if (iCls
) *iCls
= FnidToiCls
[i
].ClsId
;
121 /* WINDOWCLASS ***************************************************************/
124 IntFreeClassMenuName(IN OUT PCLS Class
)
126 /* free the menu name, if it was changed and allocated */
127 if (Class
->lpszClientUnicodeMenuName
!= NULL
&& Class
->MenuNameIsString
)
129 UserHeapFree(Class
->lpszClientUnicodeMenuName
);
130 Class
->lpszClientUnicodeMenuName
= NULL
;
131 Class
->lpszClientAnsiMenuName
= NULL
;
136 IntDestroyClass(IN OUT PCLS Class
)
139 /* there shouldn't be any clones anymore */
140 ASSERT(Class
->cWndReferenceCount
== 0);
141 ASSERT(Class
->pclsClone
== NULL
);
143 if (Class
->pclsBase
== Class
)
145 PCALLPROCDATA CallProc
, NextCallProc
;
147 /* Destroy allocated callproc handles */
148 CallProc
= Class
->spcpdFirst
;
149 while (CallProc
!= NULL
)
151 NextCallProc
= CallProc
->spcpdNext
;
153 CallProc
->spcpdNext
= NULL
;
154 DestroyCallProc(NULL
,
157 CallProc
= NextCallProc
;
162 DceFreeClassDCE(((PDCE
)Class
->pdce
)->hDC
);
166 IntFreeClassMenuName(Class
);
169 pDesk
= Class
->rpdeskParent
;
170 Class
->rpdeskParent
= NULL
;
172 /* free the structure */
175 DesktopHeapFree(pDesk
, Class
);
184 /* clean all process classes. all process windows must cleaned first!! */
185 void FASTCALL
DestroyProcessClasses(PPROCESSINFO Process
)
188 PPROCESSINFO pi
= (PPROCESSINFO
)Process
;
192 /* free all local classes */
193 Class
= pi
->pclsPrivateList
;
194 while (Class
!= NULL
)
196 pi
->pclsPrivateList
= Class
->pclsNext
;
198 ASSERT(Class
->pclsBase
== Class
);
199 IntDestroyClass(Class
);
201 Class
= pi
->pclsPrivateList
;
204 /* free all global classes */
205 Class
= pi
->pclsPublicList
;
206 while (Class
!= NULL
)
208 pi
->pclsPublicList
= Class
->pclsNext
;
210 ASSERT(Class
->pclsBase
== Class
);
211 IntDestroyClass(Class
);
213 Class
= pi
->pclsPublicList
;
219 IntRegisterClassAtom(IN PUNICODE_STRING ClassName
,
226 if (ClassName
->Length
!= 0)
228 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
229 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
231 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
238 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
242 AtomName
= ClassName
->Buffer
;
244 Status
= RtlAddAtomToAtomTable(gAtomTable
,
248 if (!NT_SUCCESS(Status
))
250 SetLastNtError(Status
);
258 IntDeregisterClassAtom(IN RTL_ATOM Atom
)
260 return RtlDeleteAtomFromAtomTable(gAtomTable
,
265 UserAddCallProcToClass(IN OUT PCLS Class
,
266 IN PCALLPROCDATA CallProc
)
270 ASSERT(CallProc
->spcpdNext
== NULL
);
272 BaseClass
= Class
->pclsBase
;
273 ASSERT(CallProc
->spcpdNext
== NULL
);
274 CallProc
->spcpdNext
= BaseClass
->spcpdFirst
;
275 BaseClass
->spcpdFirst
= CallProc
;
277 /* Update all clones */
278 Class
= Class
->pclsClone
;
279 while (Class
!= NULL
)
281 Class
->spcpdFirst
= BaseClass
->spcpdFirst
;
282 Class
= Class
->pclsNext
;
287 IntSetClassAtom(IN OUT PCLS Class
,
288 IN PUNICODE_STRING ClassName
)
290 RTL_ATOM Atom
= (RTL_ATOM
)0;
292 /* update the base class first */
293 Class
= Class
->pclsBase
;
295 if (!IntRegisterClassAtom(ClassName
,
301 IntDeregisterClassAtom(Class
->atomClassName
);
303 Class
->atomClassName
= Atom
;
305 /* update the clones */
306 Class
= Class
->pclsClone
;
307 while (Class
!= NULL
)
309 Class
->atomClassName
= Atom
;
311 Class
= Class
->pclsNext
;
318 // Same as User32:IntGetClsWndProc.
321 IntGetClassWndProc(PCLS Class
, BOOL Ansi
)
324 WNDPROC gcpd
= NULL
, Ret
= NULL
;
326 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
328 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
330 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
333 Ret
= GETPFNCLIENTA(i
);
335 Ret
= GETPFNCLIENTW(i
);
340 Ret
= Class
->lpfnWndProc
;
342 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
346 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
347 Ret
= GETPFNCLIENTA(Class
->fnid
);
351 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
352 Ret
= GETPFNCLIENTW(Class
->fnid
);
356 if ( Ret
!= Class
->lpfnWndProc
||
357 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
360 gcpd
= (WNDPROC
)UserGetCPD( Class
,
361 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDClass
,
364 return (gcpd
? gcpd
: Ret
);
370 IntSetClassWndProc(IN OUT PCLS Class
,
376 WNDPROC Ret
, chWndProc
;
378 Ret
= IntGetClassWndProc(Class
, Ansi
);
380 // If Server Side, downgrade to Client Side.
381 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
383 if (Ansi
) Class
->CSF_flags
|= CSF_ANSIPROC
;
384 Class
->CSF_flags
&= ~CSF_SERVERSIDEPROC
;
385 Class
->Unicode
= !Ansi
;
388 if (!WndProc
) WndProc
= Class
->lpfnWndProc
;
392 // Check if CallProc handle and retrieve previous call proc address and set.
393 if (IsCallProcHandle(WndProc
))
395 pcpd
= UserGetObject(gHandleTable
, WndProc
, otCallProc
);
396 if (pcpd
) chWndProc
= pcpd
->pfnClientPrevious
;
399 Class
->lpfnWndProc
= chWndProc
;
404 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
405 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
407 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
409 chWndProc
= GETPFNSERVER(i
);
412 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
414 chWndProc
= GETPFNSERVER(i
);
418 // If match, set/reset to Server Side and clear ansi.
421 Class
->lpfnWndProc
= chWndProc
;
422 Class
->Unicode
= TRUE
;
423 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
424 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
428 Class
->Unicode
= !Ansi
;
431 Class
->CSF_flags
|= CSF_ANSIPROC
;
433 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
436 /* update the clones */
437 chWndProc
= Class
->lpfnWndProc
;
439 Class
= Class
->pclsClone
;
440 while (Class
!= NULL
)
442 Class
->Unicode
= !Ansi
;
443 Class
->lpfnWndProc
= chWndProc
;
445 Class
= Class
->pclsNext
;
452 IntGetClassForDesktop(IN OUT PCLS BaseClass
,
453 IN OUT PCLS
*ClassLink
,
459 ASSERT(Desktop
!= NULL
);
460 ASSERT(BaseClass
->pclsBase
== BaseClass
);
462 if (BaseClass
->rpdeskParent
== Desktop
)
464 /* it is most likely that a window is created on the same
465 desktop as the window class. */
470 if (BaseClass
->rpdeskParent
== NULL
)
472 ASSERT(BaseClass
->cWndReferenceCount
== 0);
473 ASSERT(BaseClass
->pclsClone
== NULL
);
475 /* Classes are also located in the shared heap when the class
476 was created before the thread attached to a desktop. As soon
477 as a window is created for such a class located on the shared
478 heap, the class is cloned into the desktop heap on which the
479 window is created. */
484 /* The user is asking for a class object on a different desktop,
486 Class
= BaseClass
->pclsClone
;
487 while (Class
!= NULL
)
489 if (Class
->rpdeskParent
== Desktop
)
491 ASSERT(Class
->pclsBase
== BaseClass
);
492 ASSERT(Class
->pclsClone
== NULL
);
496 Class
= Class
->pclsNext
;
502 /* The window is created on a different desktop, we need to
503 clone the class object to the desktop heap of the window! */
504 ClassSize
= sizeof(*BaseClass
) + (SIZE_T
)BaseClass
->cbclsExtra
;
506 Class
= DesktopHeapAlloc(Desktop
,
510 /* simply clone the class */
514 DPRINT("Clone Class 0x%x hM 0x%x\n %S\n",Class
, Class
->hModule
, Class
->lpszClientUnicodeMenuName
);
516 /* update some pointers and link the class */
517 Class
->rpdeskParent
= Desktop
;
518 Class
->cWndReferenceCount
= 0;
520 if (BaseClass
->rpdeskParent
== NULL
)
522 /* we don't really need the base class on the shared
523 heap anymore, delete it so the only class left is
524 the clone we just created, which now serves as the
526 ASSERT(BaseClass
->pclsClone
== NULL
);
527 ASSERT(Class
->pclsClone
== NULL
);
528 Class
->pclsBase
= Class
;
529 Class
->pclsNext
= BaseClass
->pclsNext
;
531 /* replace the base class */
532 (void)InterlockedExchangePointer((PVOID
*)ClassLink
,
535 /* destroy the obsolete copy on the shared heap */
536 BaseClass
->pclsBase
= NULL
;
537 BaseClass
->pclsClone
= NULL
;
538 IntDestroyClass(BaseClass
);
542 /* link in the clone */
543 Class
->pclsClone
= NULL
;
544 Class
->pclsBase
= BaseClass
;
545 Class
->pclsNext
= BaseClass
->pclsClone
;
546 (void)InterlockedExchangePointer(&BaseClass
->pclsClone
,
552 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
559 IntReferenceClass(IN OUT PCLS BaseClass
,
560 IN OUT PCLS
*ClassLink
,
564 ASSERT(BaseClass
->pclsBase
== BaseClass
);
566 Class
= IntGetClassForDesktop(BaseClass
,
571 Class
->cWndReferenceCount
++;
579 IntMakeCloneBaseClass(IN OUT PCLS Class
,
580 IN OUT PCLS
*BaseClassLink
,
581 IN OUT PCLS
*CloneLink
)
583 PCLS Clone
, BaseClass
;
585 ASSERT(Class
->pclsBase
!= Class
);
586 ASSERT(Class
->pclsBase
->pclsClone
!= NULL
);
587 ASSERT(Class
->rpdeskParent
!= NULL
);
588 ASSERT(Class
->cWndReferenceCount
!= 0);
589 ASSERT(Class
->pclsBase
->rpdeskParent
!= NULL
);
590 ASSERT(Class
->pclsBase
->cWndReferenceCount
== 0);
592 /* unlink the clone */
593 *CloneLink
= Class
->pclsNext
;
594 Class
->pclsClone
= Class
->pclsBase
->pclsClone
;
596 BaseClass
= Class
->pclsBase
;
598 /* update the class information to make it a base class */
599 Class
->pclsBase
= Class
;
600 Class
->pclsNext
= (*BaseClassLink
)->pclsNext
;
602 /* update all clones */
603 Clone
= Class
->pclsClone
;
604 while (Clone
!= NULL
)
606 ASSERT(Clone
->pclsClone
== NULL
);
607 Clone
->pclsBase
= Class
;
609 Clone
= Clone
->pclsNext
;
612 /* link in the new base class */
613 (void)InterlockedExchangePointer((PVOID
*)BaseClassLink
,
619 IntDereferenceClass(IN OUT PCLS Class
,
620 IN PDESKTOPINFO Desktop
,
623 PCLS
*PrevLink
, BaseClass
, CurrentClass
;
625 BaseClass
= Class
->pclsBase
;
627 if (--Class
->cWndReferenceCount
<= 0)
629 if (BaseClass
== Class
)
631 ASSERT(Class
->pclsBase
== Class
);
633 DPRINT("IntDereferenceClass 0x%x\n", Class
);
634 /* check if there are clones of the class on other desktops,
635 link the first clone in if possible. If there are no clones
636 then leave the class on the desktop heap. It will get moved
637 to the shared heap when the thread detaches. */
638 if (BaseClass
->pclsClone
!= NULL
)
640 if (BaseClass
->Global
)
641 PrevLink
= &pi
->pclsPublicList
;
643 PrevLink
= &pi
->pclsPrivateList
;
645 CurrentClass
= *PrevLink
;
646 while (CurrentClass
!= BaseClass
)
648 ASSERT(CurrentClass
!= NULL
);
650 PrevLink
= &CurrentClass
->pclsNext
;
651 CurrentClass
= CurrentClass
->pclsNext
;
654 ASSERT(*PrevLink
== BaseClass
);
656 /* make the first clone become the new base class */
657 IntMakeCloneBaseClass(BaseClass
->pclsClone
,
659 &BaseClass
->pclsClone
);
661 /* destroy the class, there's still another clone of the class
662 that now serves as a base class. Make sure we don't destruct
663 resources shared by all classes (Base = NULL)! */
664 BaseClass
->pclsBase
= NULL
;
665 BaseClass
->pclsClone
= NULL
;
666 IntDestroyClass(BaseClass
);
671 DPRINT("IntDereferenceClass1 0x%x\n", Class
);
673 /* locate the cloned class and unlink it */
674 PrevLink
= &BaseClass
->pclsClone
;
675 CurrentClass
= BaseClass
->pclsClone
;
676 while (CurrentClass
!= Class
)
678 ASSERT(CurrentClass
!= NULL
);
680 PrevLink
= &CurrentClass
->pclsNext
;
681 CurrentClass
= CurrentClass
->pclsNext
;
684 ASSERT(CurrentClass
== Class
);
686 (void)InterlockedExchangePointer((PVOID
*)PrevLink
,
689 ASSERT(Class
->pclsBase
== BaseClass
);
690 ASSERT(Class
->pclsClone
== NULL
);
692 /* the class was just a clone, we don't need it anymore */
693 IntDestroyClass(Class
);
699 IntMoveClassToSharedHeap(IN OUT PCLS Class
,
700 IN OUT PCLS
**ClassLinkPtr
)
705 ASSERT(Class
->pclsBase
== Class
);
706 ASSERT(Class
->rpdeskParent
!= NULL
);
707 ASSERT(Class
->cWndReferenceCount
== 0);
708 ASSERT(Class
->pclsClone
== NULL
);
710 ClassSize
= sizeof(*Class
) + (SIZE_T
)Class
->cbclsExtra
;
712 /* allocate the new base class on the shared heap */
713 NewClass
= UserHeapAlloc(ClassSize
);
714 if (NewClass
!= NULL
)
716 RtlCopyMemory(NewClass
,
720 NewClass
->rpdeskParent
= NULL
;
721 NewClass
->pclsBase
= NewClass
;
723 /* replace the class in the list */
724 (void)InterlockedExchangePointer((PVOID
*)*ClassLinkPtr
,
726 *ClassLinkPtr
= &NewClass
->pclsNext
;
728 /* free the obsolete class on the desktop heap */
729 Class
->pclsBase
= NULL
;
730 IntDestroyClass(Class
);
738 IntCheckDesktopClasses(IN PDESKTOP Desktop
,
739 IN OUT PCLS
*ClassList
,
740 IN BOOL FreeOnFailure
,
743 PCLS Class
, NextClass
, *Link
;
745 /* NOTE: We only need to check base classes! When classes are no longer needed
746 on a desktop, the clones will be freed automatically as soon as possible.
747 However, we need to move base classes to the shared heap, as soon as
748 the last desktop heap where a class is allocated on is about to be destroyed.
749 If we didn't move the class to the shared heap, the class would become
752 ASSERT(Desktop
!= NULL
);
756 while (Class
!= NULL
)
758 NextClass
= Class
->pclsNext
;
760 ASSERT(Class
->pclsBase
== Class
);
762 if (Class
->rpdeskParent
== Desktop
&&
763 Class
->cWndReferenceCount
== 0)
765 /* there shouldn't be any clones around anymore! */
766 ASSERT(Class
->pclsClone
== NULL
);
768 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
769 /* FIXME - We could move the class to another desktop heap if there's still desktops
770 mapped into the process... */
772 /* move the class to the shared heap */
773 if (IntMoveClassToSharedHeap(Class
,
776 ASSERT(*Link
== NextClass
);
780 ASSERT(NextClass
== Class
->pclsNext
);
784 /* unlink the base class */
785 (void)InterlockedExchangePointer((PVOID
*)Link
,
788 /* we can free the old base class now */
789 Class
->pclsBase
= NULL
;
790 IntDestroyClass(Class
);
794 Link
= &Class
->pclsNext
;
800 Link
= &Class
->pclsNext
;
807 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop
,
808 IN BOOL FreeOnFailure
)
813 pi
= GetW32ProcessInfo();
815 /* check all local classes */
816 IntCheckDesktopClasses(Desktop
,
817 &pi
->pclsPrivateList
,
821 /* check all global classes */
822 IntCheckDesktopClasses(Desktop
,
828 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop
);
829 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
837 IntCreateClass(IN CONST WNDCLASSEXW
* lpwcx
,
838 IN PUNICODE_STRING ClassName
,
839 IN PUNICODE_STRING MenuName
,
849 PWSTR pszMenuName
= NULL
;
850 NTSTATUS Status
= STATUS_SUCCESS
;
852 DPRINT("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
853 lpwcx
, ClassName
, MenuName
, dwFlags
, Desktop
, pi
);
855 if (!IntRegisterClassAtom(ClassName
,
858 DPRINT1("Failed to register class atom!\n");
862 ClassSize
= sizeof(*Class
) + lpwcx
->cbClsExtra
;
863 if (MenuName
->Length
!= 0)
865 pszMenuName
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
866 RtlUnicodeStringToAnsiSize(MenuName
));
867 if (pszMenuName
== NULL
)
873 Class
= DesktopHeapAlloc(Desktop
,
878 /* FIXME - the class was created before being connected
879 to a desktop. It is possible for the desktop window,
880 but should it be allowed for any other case? */
881 Class
= UserHeapAlloc(ClassSize
);
888 RtlZeroMemory(Class
, ClassSize
);
890 Class
->rpdeskParent
= Desktop
;
891 Class
->pclsBase
= Class
;
892 Class
->atomClassName
= Atom
;
894 Class
->CSF_flags
= dwFlags
;
896 if (LookupFnIdToiCls(Class
->fnid
, &iCls
))
898 gpsi
->atomSysClass
[iCls
] = Class
->atomClassName
;
903 PWSTR pszMenuNameBuffer
= pszMenuName
;
905 /* need to protect with SEH since accessing the WNDCLASSEX structure
906 and string buffers might raise an exception! We don't want to
908 // What?! If the user interface was written correctly this would not be an issue!
909 Class
->lpfnWndProc
= lpwcx
->lpfnWndProc
;
910 Class
->style
= lpwcx
->style
;
911 Class
->cbclsExtra
= lpwcx
->cbClsExtra
;
912 Class
->cbwndExtra
= lpwcx
->cbWndExtra
;
913 Class
->hModule
= lpwcx
->hInstance
;
914 Class
->hIcon
= lpwcx
->hIcon
; /* FIXME */
915 Class
->hIconSm
= lpwcx
->hIconSm
; /* FIXME */
916 Class
->hCursor
= lpwcx
->hCursor
; /* FIXME */
917 Class
->hbrBackground
= lpwcx
->hbrBackground
;
919 /* make a copy of the string */
920 if (pszMenuNameBuffer
!= NULL
)
922 Class
->MenuNameIsString
= TRUE
;
924 Class
->lpszClientUnicodeMenuName
= pszMenuNameBuffer
;
925 RtlCopyMemory(Class
->lpszClientUnicodeMenuName
,
928 Class
->lpszClientUnicodeMenuName
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
930 pszMenuNameBuffer
+= (MenuName
->Length
/ sizeof(WCHAR
)) + 1;
933 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
935 /* save an ansi copy of the string */
936 if (pszMenuNameBuffer
!= NULL
)
938 ANSI_STRING AnsiString
;
940 Class
->lpszClientAnsiMenuName
= (PSTR
)pszMenuNameBuffer
;
941 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
942 AnsiString
.Buffer
= Class
->lpszClientAnsiMenuName
;
943 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
946 if (!NT_SUCCESS(Status
))
948 DPRINT1("Failed to convert unicode menu name to ansi!\n");
950 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
955 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
957 /* Save kernel use menu name and ansi class name */
958 Class
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
; // Fixme!
959 //Class->lpszAnsiClassName = Fixme!
961 /* Server Side overrides class calling type (A/W)!
962 User32 whine test_builtinproc: "deftest"
963 built-in winproc - window A/W type automatically detected */
964 if (!(Class
->CSF_flags
& CSF_SERVERSIDEPROC
))
968 /* Due to the wine class "deftest" and most likely no FNID to reference
969 from, sort through the Server Side list and compare proc addresses
970 for match. This method will be used in related code.
972 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
973 { // Open Ansi or Unicode, just match, set and break.
974 if (GETPFNCLIENTW(i
) == Class
->lpfnWndProc
)
976 WndProc
= GETPFNSERVER(i
);
979 if (GETPFNCLIENTA(i
) == Class
->lpfnWndProc
)
981 WndProc
= GETPFNSERVER(i
);
986 { // If a hit, we are Server Side so set the right flags and proc.
987 Class
->CSF_flags
|= CSF_SERVERSIDEPROC
;
988 Class
->CSF_flags
&= ~CSF_ANSIPROC
;
989 Class
->lpfnWndProc
= WndProc
;
993 if (!(Class
->CSF_flags
& CSF_ANSIPROC
))
994 Class
->Unicode
= TRUE
;
996 if (Class
->style
& CS_GLOBALCLASS
)
997 Class
->Global
= TRUE
;
999 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1001 Status
= _SEH2_GetExceptionCode();
1005 if (!NT_SUCCESS(Status
))
1007 DPRINT1("Failed creating the class: 0x%x\n", Status
);
1009 SetLastNtError(Status
);
1011 if (pszMenuName
!= NULL
)
1012 UserHeapFree(pszMenuName
);
1014 DesktopHeapFree(Desktop
,
1018 IntDeregisterClassAtom(Atom
);
1024 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop
);
1026 if (pszMenuName
!= NULL
)
1027 UserHeapFree(pszMenuName
);
1029 IntDeregisterClassAtom(Atom
);
1031 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1038 IntFindClass(IN RTL_ATOM Atom
,
1039 IN HINSTANCE hInstance
,
1041 OUT PCLS
**Link OPTIONAL
)
1043 PCLS Class
, *PrevLink
= ClassList
;
1046 while (Class
!= NULL
)
1048 if (Class
->atomClassName
== Atom
&&
1049 (hInstance
== NULL
|| Class
->hModule
== hInstance
) &&
1050 !(Class
->CSF_flags
& CSF_WOWDEFERDESTROY
))
1052 ASSERT(Class
->pclsBase
== Class
);
1059 PrevLink
= &Class
->pclsNext
;
1060 Class
= Class
->pclsNext
;
1067 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName
,
1072 if (ClassName
->Length
!= 0)
1078 /* NOTE: Caller has to protect the call with SEH! */
1080 if (ClassName
->Length
!= 0)
1082 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1083 if (ClassName
->Length
/ sizeof(WCHAR
) >= sizeof(szBuf
) / sizeof(szBuf
[0]))
1085 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1089 /* We need to make a local copy of the class name! The caller could
1090 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1091 We're protected by SEH, but the ranges that might be accessed were
1093 RtlCopyMemory(szBuf
,
1096 szBuf
[ClassName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1100 AtomName
= ClassName
->Buffer
;
1102 /* lookup the atom */
1103 Status
= RtlLookupAtomInAtomTable(gAtomTable
,
1106 if (NT_SUCCESS(Status
))
1112 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1114 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1118 SetLastNtError(Status
);
1124 ASSERT(IS_ATOM(ClassName
->Buffer
));
1125 *Atom
= (RTL_ATOM
)((ULONG_PTR
)ClassName
->Buffer
);
1133 IntGetClassAtom(IN PUNICODE_STRING ClassName
,
1134 IN HINSTANCE hInstance OPTIONAL
,
1135 IN PPROCESSINFO pi OPTIONAL
,
1136 OUT PCLS
*BaseClass OPTIONAL
,
1137 OUT PCLS
**Link OPTIONAL
)
1139 RTL_ATOM Atom
= (RTL_ATOM
)0;
1141 ASSERT(BaseClass
!= NULL
);
1143 if (IntGetAtomFromStringOrAtom(ClassName
,
1145 Atom
!= (RTL_ATOM
)0)
1149 /* attempt to locate the class object */
1153 /* Step 1: try to find an exact match of locally registered classes */
1154 Class
= IntFindClass(Atom
,
1156 &pi
->pclsPrivateList
,
1159 { DPRINT("Step 1: 0x%x\n",Class
);
1163 /* Step 2: try to find any globally registered class. The hInstance
1164 is not relevant for global classes */
1165 Class
= IntFindClass(Atom
,
1167 &pi
->pclsPublicList
,
1170 { DPRINT("Step 2: 0x%x 0x%x\n",Class
, Class
->hModule
);
1174 /* Step 3: try to find any local class registered by user32 */
1175 Class
= IntFindClass(Atom
,
1177 &pi
->pclsPrivateList
,
1180 { DPRINT("Step 3: 0x%x\n",Class
);
1184 /* Step 4: try to find any global class registered by user32 */
1185 Class
= IntFindClass(Atom
,
1187 &pi
->pclsPublicList
,
1191 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
1193 }else{DPRINT("Step 4: 0x%x\n",Class
);}
1203 UserRegisterClass(IN CONST WNDCLASSEXW
* lpwcx
,
1204 IN PUNICODE_STRING ClassName
,
1205 IN PUNICODE_STRING MenuName
,
1213 RTL_ATOM Ret
= (RTL_ATOM
)0;
1215 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1217 pti
= GetW32ThreadInfo();
1221 // Need only to test for two conditions not four....... Fix more whine tests....
1222 if ( IntGetAtomFromStringOrAtom( ClassName
, &ClassAtom
) &&
1223 ClassAtom
!= (RTL_ATOM
)0 &&
1224 !(dwFlags
& CSF_SERVERSIDEPROC
) ) // Bypass Server Sides
1226 Class
= IntFindClass( ClassAtom
,
1228 &pi
->pclsPrivateList
,
1231 if (Class
!= NULL
&& !Class
->Global
)
1233 // local class already exists
1234 DPRINT1("Local Class 0x%p does already exist!\n", ClassAtom
);
1235 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1239 if (lpwcx
->style
& CS_GLOBALCLASS
)
1241 Class
= IntFindClass( ClassAtom
,
1243 &pi
->pclsPublicList
,
1246 if (Class
!= NULL
&& Class
->Global
)
1248 DPRINT1("Global Class 0x%p does already exist!\n", ClassAtom
);
1249 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
1255 Class
= IntCreateClass(lpwcx
,
1267 /* Register the class */
1269 List
= &pi
->pclsPublicList
;
1271 List
= &pi
->pclsPrivateList
;
1273 Class
->pclsNext
= *List
;
1274 (void)InterlockedExchangePointer((PVOID
*)List
,
1277 Ret
= Class
->atomClassName
;
1281 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1288 UserUnregisterClass(IN PUNICODE_STRING ClassName
,
1289 IN HINSTANCE hInstance
,
1290 OUT PCLSMENUNAME pClassMenuName
)
1297 pi
= GetW32ProcessInfo();
1299 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName
, hInstance
);
1301 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1302 ClassAtom
= IntGetClassAtom(ClassName
,
1307 if (ClassAtom
== (RTL_ATOM
)0)
1309 DPRINT1("UserUnregisterClass: No Class found.\n");
1313 ASSERT(Class
!= NULL
);
1315 if (Class
->cWndReferenceCount
!= 0 ||
1316 Class
->pclsClone
!= NULL
)
1318 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class
->cWndReferenceCount
, Class
->pclsClone
);
1319 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
1323 /* must be a base class! */
1324 ASSERT(Class
->pclsBase
== Class
);
1326 /* unlink the class */
1327 *Link
= Class
->pclsNext
;
1329 if (NT_SUCCESS(IntDeregisterClassAtom(Class
->atomClassName
)))
1331 DPRINT("Class 0x%x\n", Class
);
1332 DPRINT("UserUnregisterClass: Good Exit!\n");
1333 /* finally free the resources */
1334 IntDestroyClass(Class
);
1337 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1342 UserGetClassName(IN PCLS Class
,
1343 IN OUT PUNICODE_STRING ClassName
,
1346 NTSTATUS Status
= STATUS_SUCCESS
;
1347 WCHAR szStaticTemp
[32];
1348 PWSTR szTemp
= NULL
;
1349 ULONG BufLen
= sizeof(szStaticTemp
);
1352 /* Note: Accessing the buffer in ClassName may raise an exception! */
1358 PANSI_STRING AnsiClassName
= (PANSI_STRING
)ClassName
;
1359 UNICODE_STRING UnicodeClassName
;
1361 /* limit the size of the static buffer on the stack to the
1362 size of the buffer provided by the caller */
1363 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1365 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1368 /* find out how big the buffer needs to be */
1369 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1370 Class
->atomClassName
,
1375 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1377 if (BufLen
/ sizeof(WCHAR
) > AnsiClassName
->MaximumLength
)
1379 /* the buffer required exceeds the ansi buffer provided,
1380 pretend like we're using the ansi buffer and limit the
1381 size to the buffer size provided */
1382 BufLen
= AnsiClassName
->MaximumLength
* sizeof(WCHAR
);
1385 /* allocate a temporary buffer that can hold the unicode class name */
1386 szTemp
= ExAllocatePool(PagedPool
,
1390 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1394 /* query the class name */
1395 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1396 Class
->atomClassName
,
1403 szTemp
= szStaticTemp
;
1405 if (NT_SUCCESS(Status
))
1407 /* convert the atom name to ansi */
1409 RtlInitUnicodeString(&UnicodeClassName
,
1412 Status
= RtlUnicodeStringToAnsiString(AnsiClassName
,
1415 if (!NT_SUCCESS(Status
))
1417 SetLastNtError(Status
);
1422 Ret
= BufLen
/ sizeof(WCHAR
);
1426 BufLen
= ClassName
->MaximumLength
;
1428 /* query the atom name */
1429 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
1430 Class
->atomClassName
,
1436 if (!NT_SUCCESS(Status
))
1438 SetLastNtError(Status
);
1442 Ret
= BufLen
/ sizeof(WCHAR
);
1445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1447 SetLastNtError(_SEH2_GetExceptionCode());
1451 if (Ansi
&& szTemp
!= NULL
&& szTemp
!= szStaticTemp
)
1460 UserGetClassLongPtr(IN PCLS Class
,
1470 TRACE("GetClassLong(%d)\n", Index
);
1471 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1472 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1474 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1478 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1480 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1481 certain architectures, maybe using RtlCopyMemory is a
1482 better choice for those architectures! */
1484 TRACE("Result: %x\n", Ret
);
1490 case GCL_CBWNDEXTRA
:
1491 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1494 case GCL_CBCLSEXTRA
:
1495 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
1498 case GCLP_HBRBACKGROUND
:
1499 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1503 /* FIXME - get handle from pointer to CURSOR object */
1504 Ret
= (ULONG_PTR
)Class
->hCursor
;
1508 /* FIXME - get handle from pointer to ICON object */
1509 Ret
= (ULONG_PTR
)Class
->hIcon
;
1513 /* FIXME - get handle from pointer to ICON object */
1514 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1518 Ret
= (ULONG_PTR
)Class
->hModule
;
1522 /* NOTE: Returns pointer in kernel heap! */
1524 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
1526 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
1530 Ret
= (ULONG_PTR
)Class
->style
;
1534 Ret
= (ULONG_PTR
)IntGetClassWndProc(Class
, Ansi
);
1538 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1542 SetLastWin32Error(ERROR_INVALID_INDEX
);
1550 IntSetClassMenuName(IN PCLS Class
,
1551 IN PUNICODE_STRING MenuName
)
1555 /* change the base class first */
1556 Class
= Class
->pclsBase
;
1558 if (MenuName
->Length
!= 0)
1560 ANSI_STRING AnsiString
;
1563 AnsiString
.MaximumLength
= RtlUnicodeStringToAnsiSize(MenuName
);
1565 strBufW
= UserHeapAlloc(MenuName
->Length
+ sizeof(UNICODE_NULL
) +
1566 AnsiString
.MaximumLength
);
1567 if (strBufW
!= NULL
)
1573 /* copy the unicode string */
1574 RtlCopyMemory(strBufW
,
1577 strBufW
[MenuName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1579 /* create an ansi copy of the string */
1580 AnsiString
.Buffer
= (PSTR
)(strBufW
+ (MenuName
->Length
/ sizeof(WCHAR
)) + 1);
1581 Status
= RtlUnicodeStringToAnsiString(&AnsiString
,
1584 if (!NT_SUCCESS(Status
))
1586 SetLastNtError(Status
);
1592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1594 SetLastNtError(_SEH2_GetExceptionCode());
1600 /* update the base class */
1601 IntFreeClassMenuName(Class
);
1602 Class
->lpszClientUnicodeMenuName
= strBufW
;
1603 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1604 Class
->MenuNameIsString
= TRUE
;
1606 /* update the clones */
1607 Class
= Class
->pclsClone
;
1608 while (Class
!= NULL
)
1610 Class
->lpszClientUnicodeMenuName
= strBufW
;
1611 Class
->lpszClientAnsiMenuName
= AnsiString
.Buffer
;
1612 Class
->MenuNameIsString
= TRUE
;
1614 Class
= Class
->pclsNext
;
1619 DPRINT1("Failed to copy class menu name!\n");
1620 UserHeapFree(strBufW
);
1624 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1628 ASSERT(IS_INTRESOURCE(MenuName
->Buffer
));
1630 /* update the base class */
1631 IntFreeClassMenuName(Class
);
1632 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1633 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1634 Class
->MenuNameIsString
= FALSE
;
1636 /* update the clones */
1637 Class
= Class
->pclsClone
;
1638 while (Class
!= NULL
)
1640 Class
->lpszClientUnicodeMenuName
= MenuName
->Buffer
;
1641 Class
->lpszClientAnsiMenuName
= (PSTR
)MenuName
->Buffer
;
1642 Class
->MenuNameIsString
= FALSE
;
1644 Class
= Class
->pclsNext
;
1654 UserSetClassLongPtr(IN PCLS Class
,
1656 IN ULONG_PTR NewLong
,
1661 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1663 /* change the information in the base class first, then update the clones */
1664 Class
= Class
->pclsBase
;
1670 TRACE("SetClassLong(%d, %x)\n", Index
, NewLong
);
1672 if (Index
+ sizeof(ULONG_PTR
) < Index
||
1673 Index
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
1675 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1679 Data
= (PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
);
1681 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1682 certain architectures, maybe using RtlCopyMemory is a
1683 better choice for those architectures! */
1687 /* update the clones */
1688 Class
= Class
->pclsClone
;
1689 while (Class
!= NULL
)
1691 *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + Index
) = NewLong
;
1692 Class
= Class
->pclsNext
;
1700 case GCL_CBWNDEXTRA
:
1701 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
1702 Class
->cbwndExtra
= (INT
)NewLong
;
1704 /* update the clones */
1705 Class
= Class
->pclsClone
;
1706 while (Class
!= NULL
)
1708 Class
->cbwndExtra
= (INT
)NewLong
;
1709 Class
= Class
->pclsNext
;
1714 case GCL_CBCLSEXTRA
:
1715 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1718 case GCLP_HBRBACKGROUND
:
1719 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
1720 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1722 /* update the clones */
1723 Class
= Class
->pclsClone
;
1724 while (Class
!= NULL
)
1726 Class
->hbrBackground
= (HBRUSH
)NewLong
;
1727 Class
= Class
->pclsNext
;
1732 /* FIXME - get handle from pointer to CURSOR object */
1733 Ret
= (ULONG_PTR
)Class
->hCursor
;
1734 Class
->hCursor
= (HANDLE
)NewLong
;
1736 /* update the clones */
1737 Class
= Class
->pclsClone
;
1738 while (Class
!= NULL
)
1740 Class
->hCursor
= (HANDLE
)NewLong
;
1741 Class
= Class
->pclsNext
;
1746 /* FIXME - get handle from pointer to ICON object */
1747 Ret
= (ULONG_PTR
)Class
->hIcon
;
1748 Class
->hIcon
= (HANDLE
)NewLong
;
1750 /* update the clones */
1751 Class
= Class
->pclsClone
;
1752 while (Class
!= NULL
)
1754 Class
->hIcon
= (HANDLE
)NewLong
;
1755 Class
= Class
->pclsNext
;
1760 /* FIXME - get handle from pointer to ICON object */
1761 Ret
= (ULONG_PTR
)Class
->hIconSm
;
1762 Class
->hIconSm
= (HANDLE
)NewLong
;
1764 /* update the clones */
1765 Class
= Class
->pclsClone
;
1766 while (Class
!= NULL
)
1768 Class
->hIconSm
= (HANDLE
)NewLong
;
1769 Class
= Class
->pclsNext
;
1774 Ret
= (ULONG_PTR
)Class
->hModule
;
1775 Class
->hModule
= (HINSTANCE
)NewLong
;
1777 /* update the clones */
1778 Class
= Class
->pclsClone
;
1779 while (Class
!= NULL
)
1781 Class
->hModule
= (HINSTANCE
)NewLong
;
1782 Class
= Class
->pclsNext
;
1788 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1790 if (!IntSetClassMenuName(Class
,
1793 DPRINT1("Setting the class menu name failed!\n");
1796 /* FIXME - really return NULL? Wine does so... */
1801 Ret
= (ULONG_PTR
)Class
->style
;
1802 Class
->style
= (UINT
)NewLong
;
1804 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1805 move the class to the appropriate list? For now, we save
1806 the original value in Class->Global, so we can always
1807 locate the appropriate list */
1809 /* update the clones */
1810 Class
= Class
->pclsClone
;
1811 while (Class
!= NULL
)
1813 Class
->style
= (UINT
)NewLong
;
1814 Class
= Class
->pclsNext
;
1819 Ret
= (ULONG_PTR
)IntSetClassWndProc(Class
,
1826 PUNICODE_STRING Value
= (PUNICODE_STRING
)NewLong
;
1828 Ret
= (ULONG_PTR
)Class
->atomClassName
;
1829 if (!IntSetClassAtom(Class
,
1838 SetLastWin32Error(ERROR_INVALID_INDEX
);
1846 UserGetClassInfo(IN PCLS Class
,
1847 OUT PWNDCLASSEXW lpwcx
,
1849 HINSTANCE hInstance
)
1853 if (!Class
) return FALSE
;
1855 lpwcx
->style
= Class
->style
;
1857 // If fnId is set, clear the global bit. See wine class test check_style.
1859 lpwcx
->style
&= ~CS_GLOBALCLASS
;
1861 pi
= GetW32ProcessInfo();
1863 lpwcx
->lpfnWndProc
= IntGetClassWndProc(Class
, Ansi
);
1865 lpwcx
->cbClsExtra
= Class
->cbclsExtra
;
1866 lpwcx
->cbWndExtra
= Class
->cbwndExtra
;
1867 lpwcx
->hIcon
= Class
->hIcon
; /* FIXME - get handle from pointer */
1868 lpwcx
->hCursor
= Class
->hCursor
; /* FIXME - get handle from pointer */
1869 lpwcx
->hbrBackground
= Class
->hbrBackground
;
1871 /* Copy non-string to user first. */
1873 ((PWNDCLASSEXA
)lpwcx
)->lpszMenuName
= Class
->lpszClientAnsiMenuName
;
1875 lpwcx
->lpszMenuName
= Class
->lpszClientUnicodeMenuName
;
1877 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1878 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1879 lpszClientXxxMenuName should already be mapped to user space.
1881 /* Copy string ptr to user. */
1882 if ( Class
->lpszClientUnicodeMenuName
!= NULL
&&
1883 Class
->MenuNameIsString
)
1885 lpwcx
->lpszMenuName
= UserHeapAddressToUser(Ansi
?
1886 (PVOID
)Class
->lpszClientAnsiMenuName
:
1887 (PVOID
)Class
->lpszClientUnicodeMenuName
);
1890 if (hInstance
== hModClient
)
1891 lpwcx
->hInstance
= NULL
;
1893 lpwcx
->hInstance
= hInstance
;
1895 /* FIXME - return the string? Okay! This is performed in User32!*/
1896 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1898 lpwcx
->hIconSm
= Class
->hIconSm
; /* FIXME - get handle from pointer */
1908 UserRegisterSystemClasses(VOID
)
1911 UNICODE_STRING ClassName
, MenuName
;
1912 PPROCESSINFO ppi
= GetW32ProcessInfo();
1918 if (ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
)
1921 if ( hModClient
== NULL
)
1924 RtlZeroMemory(&ClassName
, sizeof(ClassName
));
1925 RtlZeroMemory(&MenuName
, sizeof(MenuName
));
1927 for (i
= 0; i
!= ARRAYSIZE(DefaultServerClasses
); i
++)
1929 if (!IS_ATOM(DefaultServerClasses
[i
].ClassName
))
1931 RtlInitUnicodeString(&ClassName
, DefaultServerClasses
[i
].ClassName
);
1935 ClassName
.Buffer
= DefaultServerClasses
[i
].ClassName
;
1936 ClassName
.Length
= 0;
1937 ClassName
.MaximumLength
= 0;
1940 wc
.cbSize
= sizeof(wc
);
1941 wc
.style
= DefaultServerClasses
[i
].Style
;
1943 Flags
|= CSF_SERVERSIDEPROC
;
1945 if (DefaultServerClasses
[i
].ProcW
)
1947 wc
.lpfnWndProc
= DefaultServerClasses
[i
].ProcW
;
1948 wc
.hInstance
= hModuleWin
;
1952 wc
.lpfnWndProc
= GETPFNSERVER(DefaultServerClasses
[i
].fiId
);
1953 wc
.hInstance
= hModClient
;
1957 wc
.cbWndExtra
= DefaultServerClasses
[i
].ExtraBytes
;
1959 wc
.hCursor
= DefaultServerClasses
[i
].hCursor
;
1960 wc
.hbrBackground
= DefaultServerClasses
[i
].hBrush
;
1961 wc
.lpszMenuName
= NULL
;
1962 wc
.lpszClassName
= ClassName
.Buffer
;
1965 Class
= IntCreateClass( &wc
,
1968 DefaultServerClasses
[i
].fiId
,
1974 Class
->pclsNext
= ppi
->pclsPublicList
;
1975 (void)InterlockedExchangePointer((PVOID
*)&ppi
->pclsPublicList
,
1978 ppi
->dwRegisteredClasses
|= ICLASS_TO_MASK(DefaultServerClasses
[i
].iCls
);
1982 WARN("!!! Registering system class failed!\n");
1986 if (Ret
) ppi
->W32PF_flags
|= W32PF_CLASSESREGISTERED
;
1990 /* SYSCALLS *****************************************************************/
1994 NtUserRegisterClassExWOW(
1996 PUNICODE_STRING ClassName
,
1997 PUNICODE_STRING ClsNVersion
,
1998 PCLSMENUNAME pClassMenuName
,
2004 * Registers a new class with the window manager
2006 * lpwcx = Win32 extended window class structure
2007 * bUnicodeClass = Whether to send ANSI or unicode strings
2008 * to window procedures
2010 * Atom identifying the new class
2013 WNDCLASSEXW CapturedClassInfo
= {0};
2014 UNICODE_STRING CapturedName
= {0}, CapturedMenuName
= {0};
2015 RTL_ATOM Ret
= (RTL_ATOM
)0;
2016 PPROCESSINFO ppi
= GetW32ProcessInfo();
2018 if (Flags
& ~(CSF_ANSIPROC
))
2020 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
2021 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2025 UserEnterExclusive();
2027 DPRINT("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName
);
2029 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2031 UserRegisterSystemClasses();
2036 /* Probe the parameters and basic parameter checks */
2037 if (ProbeForReadUint(&lpwcx
->cbSize
) != sizeof(WNDCLASSEXW
))
2039 DPRINT1("NtUserRegisterClassExWOW Wrong cbSize!\n");
2040 goto InvalidParameter
;
2044 sizeof(WNDCLASSEXW
),
2046 RtlCopyMemory(&CapturedClassInfo
,
2048 sizeof(WNDCLASSEXW
));
2050 CapturedName
= ProbeForReadUnicodeString(ClassName
);
2052 ProbeForRead(pClassMenuName
,
2053 sizeof(CLSMENUNAME
),
2056 CapturedMenuName
= ProbeForReadUnicodeString(pClassMenuName
->pusMenuName
);
2058 if ( CapturedName
.Length
& 1 ||
2059 CapturedMenuName
.Length
& 1 ||
2060 CapturedClassInfo
.cbClsExtra
< 0 ||
2061 CapturedClassInfo
.cbClsExtra
+
2062 CapturedName
.Length
+
2063 CapturedMenuName
.Length
+
2064 sizeof(CLS
) < CapturedClassInfo
.cbClsExtra
||
2065 CapturedClassInfo
.cbWndExtra
< 0 ||
2066 CapturedClassInfo
.hInstance
== NULL
)
2068 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2069 goto InvalidParameter
;
2072 if (CapturedName
.Length
!= 0)
2074 ProbeForRead(CapturedName
.Buffer
,
2075 CapturedName
.Length
,
2080 if (!IS_ATOM(CapturedName
.Buffer
))
2082 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2083 goto InvalidParameter
;
2087 if (CapturedMenuName
.Length
!= 0)
2089 ProbeForRead(CapturedMenuName
.Buffer
,
2090 CapturedMenuName
.Length
,
2093 else if (CapturedMenuName
.Buffer
!= NULL
&&
2094 !IS_INTRESOURCE(CapturedMenuName
.Buffer
))
2096 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2098 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2102 if (IsCallProcHandle(lpwcx
->lpfnWndProc
))
2103 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2104 // If this pops up we know what todo!
2105 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2108 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName
);
2110 /* Register the class */
2111 Ret
= UserRegisterClass(&CapturedClassInfo
,
2117 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2119 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2120 SetLastNtError(_SEH2_GetExceptionCode());
2126 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2135 NtUserGetClassLong(IN HWND hWnd
,
2139 PWINDOW_OBJECT Window
;
2142 if (Offset
!= GCLP_WNDPROC
)
2148 UserEnterExclusive();
2151 Window
= UserGetWindowObject(hWnd
);
2154 Ret
= UserGetClassLongPtr(Window
->Wnd
->pcls
,
2159 Offset
== GCLP_MENUNAME
&&
2160 Window
->Wnd
->pcls
->MenuNameIsString
)
2162 Ret
= (ULONG_PTR
)UserHeapAddressToUser((PVOID
)Ret
);
2174 NtUserSetClassLong(HWND hWnd
,
2176 ULONG_PTR dwNewLong
,
2180 PWINDOW_OBJECT Window
;
2183 UserEnterExclusive();
2185 pi
= GetW32ProcessInfo();
2187 Window
= UserGetWindowObject(hWnd
);
2190 if (Window
->ti
->ppi
!= pi
)
2192 SetLastWin32Error(ERROR_ACCESS_DENIED
);
2198 UNICODE_STRING Value
;
2200 /* probe the parameters */
2201 if (Offset
== GCW_ATOM
|| Offset
== GCLP_MENUNAME
)
2203 Value
= ProbeForReadUnicodeString((PUNICODE_STRING
)dwNewLong
);
2204 if (Value
.Length
& 1)
2206 goto InvalidParameter
;
2209 if (Value
.Length
!= 0)
2211 ProbeForRead(Value
.Buffer
,
2217 if (Offset
== GCW_ATOM
&& !IS_ATOM(Value
.Buffer
))
2219 goto InvalidParameter
;
2221 else if (Offset
== GCLP_MENUNAME
&& !IS_INTRESOURCE(Value
.Buffer
))
2224 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2229 dwNewLong
= (ULONG_PTR
)&Value
;
2232 Ret
= UserSetClassLongPtr(Window
->Wnd
->pcls
,
2237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2239 SetLastNtError(_SEH2_GetExceptionCode());
2258 * NOTE: Obsoleted in 32-bit windows
2264 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom
,
2265 IN HINSTANCE hInstance
,
2266 OUT PCLSMENUNAME pClassMenuName
)
2268 UNICODE_STRING CapturedClassName
;
2271 UserEnterExclusive();
2275 /* probe the paramters */
2276 CapturedClassName
= ProbeForReadUnicodeString(ClassNameOrAtom
);
2277 if (CapturedClassName
.Length
& 1)
2279 goto InvalidParameter
;
2282 if (CapturedClassName
.Length
!= 0)
2284 ProbeForRead(CapturedClassName
.Buffer
,
2285 CapturedClassName
.Length
,
2290 if (!IS_ATOM(CapturedClassName
.Buffer
))
2293 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2298 /* unregister the class */
2299 Ret
= UserUnregisterClass(&CapturedClassName
,
2301 NULL
); // Null for now~
2303 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2305 SetLastNtError(_SEH2_GetExceptionCode());
2313 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2316 HINSTANCE hInstance
,
2317 PUNICODE_STRING ClassName
,
2318 LPWNDCLASSEXW lpWndClassEx
,
2319 LPWSTR
*ppszMenuName
,
2322 UNICODE_STRING CapturedClassName
, SafeClassName
;
2323 WNDCLASSEXW Safewcexw
;
2325 RTL_ATOM ClassAtom
= 0;
2329 /* NOTE: need exclusive lock because getting the wndproc might require the
2330 creation of a call procedure handle */
2331 UserEnterExclusive();
2333 ppi
= GetW32ProcessInfo();
2335 if ( !(ppi
->W32PF_flags
& W32PF_CLASSESREGISTERED
))
2337 UserRegisterSystemClasses();
2342 /* probe the paramters */
2343 CapturedClassName
= ProbeForReadUnicodeString(ClassName
);
2345 if (CapturedClassName
.Length
== 0)
2346 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance
, CapturedClassName
.Buffer
, lpWndClassEx
, Ansi
);
2348 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance
, &CapturedClassName
, lpWndClassEx
, Ansi
);
2350 if (CapturedClassName
.Length
& 1)
2352 goto InvalidParameter
;
2355 if (CapturedClassName
.Length
!= 0)
2357 ProbeForRead( CapturedClassName
.Buffer
,
2358 CapturedClassName
.Length
,
2361 RtlInitUnicodeString( &SafeClassName
, CapturedClassName
.Buffer
);
2363 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2364 SafeClassName
.MaximumLength
,
2366 RtlCopyMemory( SafeClassName
.Buffer
,
2367 CapturedClassName
.Buffer
,
2368 SafeClassName
.MaximumLength
);
2372 if (!IS_ATOM(CapturedClassName
.Buffer
))
2374 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2375 goto InvalidParameter
;
2378 SafeClassName
.Buffer
= CapturedClassName
.Buffer
;
2379 SafeClassName
.Length
= 0;
2380 SafeClassName
.MaximumLength
= 0;
2383 if (ProbeForReadUint(&lpWndClassEx
->cbSize
) != sizeof(WNDCLASSEXW
))
2386 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2391 ProbeForWrite( lpWndClassEx
, sizeof(WNDCLASSEXW
), sizeof(ULONG
));
2393 RtlCopyMemory( &Safewcexw
, lpWndClassEx
, sizeof(WNDCLASSEXW
));
2395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2397 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2402 // If null instance use client.
2403 if (!hInstance
) hInstance
= hModClient
;
2407 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName
, hInstance
);
2408 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2413 if (ClassAtom
!= (RTL_ATOM
)0)
2415 if (hInstance
== NULL
) hInstance
= hModClient
;
2417 Ret
= UserGetClassInfo( Class
,
2424 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2432 /* Emulate Function. */
2433 if (ppszMenuName
) *ppszMenuName
= (LPWSTR
)Safewcexw
.lpszMenuName
;
2435 RtlCopyMemory(lpWndClassEx
, &Safewcexw
, sizeof(WNDCLASSEXW
));
2438 /* We must return the atom of the class here instead of just TRUE. */
2439 /* Undocumented behavior! Return the class atom as a BOOL! */
2440 Ret
= (BOOL
)ClassAtom
;
2443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2445 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2450 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2457 NtUserGetClassName (IN HWND hWnd
,
2458 OUT PUNICODE_STRING ClassName
,
2461 PWINDOW_OBJECT Window
;
2462 UNICODE_STRING CapturedClassName
;
2467 Window
= UserGetWindowObject(hWnd
);
2472 ProbeForWriteUnicodeString(ClassName
);
2473 CapturedClassName
= *ClassName
;
2475 /* get the class name */
2476 Ret
= UserGetClassName(Window
->Wnd
->pcls
,
2482 /* update the Length field */
2483 ClassName
->Length
= CapturedClassName
.Length
;
2486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2488 SetLastNtError(_SEH2_GetExceptionCode());
2498 /* Return Pointer to Class structure. */
2500 NtUserGetWOWClass(HINSTANCE hInstance
,
2501 PUNICODE_STRING ClassName
)
2503 UNICODE_STRING SafeClassName
;
2506 RTL_ATOM ClassAtom
= 0;
2509 UserEnterExclusive();
2511 pi
= GetW32ProcessInfo();
2515 if (ClassName
->Length
!= 0)
2517 ProbeForRead( ClassName
->Buffer
,
2521 RtlInitUnicodeString( &SafeClassName
, ClassName
->Buffer
);
2523 SafeClassName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
2524 SafeClassName
.MaximumLength
,
2526 RtlCopyMemory( SafeClassName
.Buffer
,
2528 SafeClassName
.MaximumLength
);
2532 if (!IS_ATOM(ClassName
->Buffer
))
2534 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2539 SafeClassName
.Buffer
= ClassName
->Buffer
;
2540 SafeClassName
.Length
= 0;
2541 SafeClassName
.MaximumLength
= 0;
2545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2547 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2554 ClassAtom
= IntGetClassAtom( &SafeClassName
,
2561 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
2565 if (SafeClassName
.Length
) ExFreePoolWithTag(SafeClassName
.Buffer
, TAG_STRING
);
2568 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.