2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
36 /* FUNCTIONS *****************************************************************/
41 return(STATUS_SUCCESS
);
45 CleanupClassImpl(VOID
)
47 return(STATUS_SUCCESS
);
51 /* return TRUE if class became destroyed */
53 ClassDerefObject(PWNDCLASS_OBJECT Class
)
55 ASSERT(Class
->refs
>= 1);
61 ClassRefObject(PWNDCLASS_OBJECT Class
)
63 ASSERT(Class
->refs
>= 0);
68 VOID FASTCALL
DestroyClass(PWNDCLASS_OBJECT Class
)
70 PWINSTATION_OBJECT WinSta
;
71 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
73 ASSERT(Class
->refs
== 0);
74 RemoveEntryList(&Class
->ListEntry
);
76 RtlDeleteAtomFromAtomTable(WinSta
->AtomTable
, Class
->Atom
);
81 /* clean all process classes. all process windows must cleaned first!! */
82 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
84 PWNDCLASS_OBJECT Class
;
86 while (!IsListEmpty(&Process
->ClassList
))
88 Class
= CONTAINING_RECORD(RemoveHeadList(&Process
->ClassList
), WNDCLASS_OBJECT
, ListEntry
);
96 PWNDCLASS_OBJECT FASTCALL
97 ClassGetClassByAtom(RTL_ATOM Atom
, HINSTANCE hInstance
)
99 PWNDCLASS_OBJECT Class
;
100 PW32PROCESS Process
= PsGetWin32Process();
102 LIST_FOR_EACH(Class
, &Process
->ClassList
, WNDCLASS_OBJECT
, ListEntry
)
104 if (Class
->Atom
!= Atom
) continue;
106 if (!hInstance
|| Class
->Global
|| Class
->hInstance
== hInstance
) return Class
;
113 PWNDCLASS_OBJECT FASTCALL
114 ClassGetClassByName(LPCWSTR ClassName
, HINSTANCE hInstance
)
116 PWINSTATION_OBJECT WinSta
;
120 if (!ClassName
|| !PsGetWin32Thread()->Desktop
)
123 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
125 Status
= RtlLookupAtomInAtomTable(
130 if (!NT_SUCCESS(Status
))
132 DPRINT1("Failed to lookup class atom!\n");
136 return ClassGetClassByAtom(Atom
, hInstance
);
140 PWNDCLASS_OBJECT FASTCALL
141 ClassGetClassByNameOrAtom(LPCWSTR ClassNameOrAtom
, HINSTANCE hInstance
)
143 if (!ClassNameOrAtom
) return NULL
;
145 if (IS_ATOM(ClassNameOrAtom
))
146 return ClassGetClassByAtom((RTL_ATOM
)((ULONG_PTR
)ClassNameOrAtom
), hInstance
);
148 return ClassGetClassByName(ClassNameOrAtom
, hInstance
);
155 CONST WNDCLASSEXW
*lpwcx
,
158 PUNICODE_STRING MenuName
,
161 PWNDCLASS_OBJECT Class
;
167 ASSERT(lpwcx
->hInstance
);
169 Global
= (Flags
& REGISTERCLASS_SYSTEM
) || (lpwcx
->style
& CS_GLOBALCLASS
);
171 /* Check for double registration of the class. */
172 Class
= ClassGetClassByAtom(Atom
, lpwcx
->hInstance
);
173 if (Class
&& Global
== Class
->Global
)
175 /* can max have one class of each type (global/local) */
176 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
180 objectSize
= sizeof(WNDCLASS_OBJECT
) + lpwcx
->cbClsExtra
;
182 //FIXME: allocate in session heap (or possibly desktop heap)
183 Class
= ExAllocatePool(PagedPool
, objectSize
);
186 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
189 RtlZeroMemory(Class
, objectSize
);
191 Class
->cbSize
= lpwcx
->cbSize
;
192 Class
->style
= lpwcx
->style
;
193 Class
->cbClsExtra
= lpwcx
->cbClsExtra
;
194 Class
->cbWndExtra
= lpwcx
->cbWndExtra
;
195 Class
->hInstance
= lpwcx
->hInstance
;
196 Class
->hIcon
= lpwcx
->hIcon
;
197 Class
->hCursor
= lpwcx
->hCursor
;
198 Class
->hbrBackground
= lpwcx
->hbrBackground
;
199 Class
->Unicode
= !(Flags
& REGISTERCLASS_ANSI
);
200 Class
->Global
= Global
;
201 Class
->hIconSm
= lpwcx
->hIconSm
;
206 if (Flags
& REGISTERCLASS_ANSI
)
208 Class
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
209 Class
->lpfnWndProcW
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,FALSE
);
213 Class
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
214 Class
->lpfnWndProcA
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,TRUE
);
219 if (Flags
& REGISTERCLASS_ANSI
)
221 Class
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
222 Class
->lpfnWndProcW
= wpExtra
;
226 Class
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
227 Class
->lpfnWndProcA
= wpExtra
;
231 if (MenuName
->Length
== 0)
233 Class
->lpszMenuName
.Length
=
234 Class
->lpszMenuName
.MaximumLength
= 0;
235 Class
->lpszMenuName
.Buffer
= MenuName
->Buffer
;
239 Class
->lpszMenuName
.Length
=
240 Class
->lpszMenuName
.MaximumLength
= MenuName
->MaximumLength
;
241 Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
242 RtlCopyUnicodeString(&Class
->lpszMenuName
, MenuName
);
245 /* Extra class data */
246 if (Class
->cbClsExtra
)
247 Class
->ExtraData
= (PCHAR
)(Class
+ 1);
251 /* global classes go last (incl. system classes) */
252 InsertTailList(&PsGetWin32Process()->ClassList
, &Class
->ListEntry
);
256 /* local classes have priority so we put them first */
257 InsertHeadList(&PsGetWin32Process()->ClassList
, &Class
->ListEntry
);
265 IntGetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, BOOL Ansi
)
269 if ((int)Offset
>= 0)
271 DPRINT("GetClassLong(%x, %d)\n", Window
->hSelf
, Offset
);
272 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
274 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
277 Ret
= *((LONG
*)(Window
->Class
->ExtraData
+ Offset
));
278 DPRINT("Result: %x\n", Ret
);
285 Ret
= Window
->Class
->cbWndExtra
;
288 Ret
= Window
->Class
->cbClsExtra
;
290 case GCL_HBRBACKGROUND
:
291 Ret
= (ULONG
)Window
->Class
->hbrBackground
;
294 Ret
= (ULONG
)Window
->Class
->hCursor
;
297 Ret
= (ULONG
)Window
->Class
->hIcon
;
300 Ret
= (ULONG
)Window
->Class
->hIconSm
;
303 Ret
= (ULONG
)Window
->Class
->hInstance
;
306 Ret
= (ULONG
)Window
->Class
->lpszMenuName
.Buffer
;
309 Ret
= Window
->Class
->style
;
314 Ret
= (ULONG
)Window
->Class
->lpfnWndProcA
;
318 Ret
= (ULONG
)Window
->Class
->lpfnWndProcW
;
322 Ret
= Window
->Class
->Atom
;
333 co_IntSetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, LONG dwNewLong
, BOOL Ansi
)
335 ASSERT_REFS_CO(Window
);
337 if ((int)Offset
>= 0)
339 DPRINT("SetClassLong(%x, %d, %x)\n", Window
->hSelf
, Offset
, dwNewLong
);
340 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
342 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
345 *((LONG
*)(Window
->Class
->ExtraData
+ Offset
)) = dwNewLong
;
352 Window
->Class
->cbWndExtra
= dwNewLong
;
355 Window
->Class
->cbClsExtra
= dwNewLong
;
357 case GCL_HBRBACKGROUND
:
358 Window
->Class
->hbrBackground
= (HBRUSH
)dwNewLong
;
361 Window
->Class
->hCursor
= (HCURSOR
)dwNewLong
;
364 Window
->Class
->hIcon
= (HICON
)dwNewLong
;
366 if (!IntGetOwner(Window
) && !IntGetParent(Window
))
368 co_IntShellHookNotify(HSHELL_REDRAW
, (LPARAM
) Window
->hSelf
);
372 Window
->Class
->hIconSm
= (HICON
)dwNewLong
;
375 Window
->Class
->hInstance
= (HINSTANCE
)dwNewLong
;
378 if (Window
->Class
->lpszMenuName
.MaximumLength
)
379 RtlFreeUnicodeString(&Window
->Class
->lpszMenuName
);
380 if (!IS_INTRESOURCE(dwNewLong
))
382 Window
->Class
->lpszMenuName
.Length
=
383 Window
->Class
->lpszMenuName
.MaximumLength
= ((PUNICODE_STRING
)dwNewLong
)->MaximumLength
;
384 Window
->Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Window
->Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
385 RtlCopyUnicodeString(&Window
->Class
->lpszMenuName
, (PUNICODE_STRING
)dwNewLong
);
389 Window
->Class
->lpszMenuName
.Length
=
390 Window
->Class
->lpszMenuName
.MaximumLength
= 0;
391 Window
->Class
->lpszMenuName
.Buffer
= (LPWSTR
)dwNewLong
;
395 Window
->Class
->style
= dwNewLong
;
400 Window
->Class
->lpfnWndProcA
= (WNDPROC
)dwNewLong
;
401 Window
->Class
->lpfnWndProcW
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,FALSE
);
402 Window
->Class
->Unicode
= FALSE
;
406 Window
->Class
->lpfnWndProcW
= (WNDPROC
)dwNewLong
;
407 Window
->Class
->lpfnWndProcA
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,TRUE
);
408 Window
->Class
->Unicode
= TRUE
;
413 /* SYSCALLS *****************************************************************/
417 NtUserRegisterClassExWOW(
418 CONST WNDCLASSEXW
* lpwcx
,
419 PUNICODE_STRING ClassName
,
420 PUNICODE_STRING ClassNameCopy
,//huhuhuhu???
421 PUNICODE_STRING MenuName
,
428 * Registers a new class with the window manager
430 * lpwcx = Win32 extended window class structure
431 * bUnicodeClass = Whether to send ANSI or unicode strings
432 * to window procedures
433 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
435 * Atom identifying the new class
438 WNDCLASSEXW SafeClass
;
439 PWINSTATION_OBJECT WinSta
;
442 DECLARE_RETURN(RTL_ATOM
);
444 DPRINT("Enter NtUserRegisterClassExWOW\n");
445 UserEnterExclusive();
449 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
450 RETURN( (RTL_ATOM
)0);
453 if (Flags
& ~REGISTERCLASS_ALL
)
455 SetLastWin32Error(ERROR_INVALID_FLAGS
);
456 RETURN( (RTL_ATOM
)0);
459 Status
= MmCopyFromCaller(&SafeClass
, lpwcx
, sizeof(WNDCLASSEXW
));
460 if (!NT_SUCCESS(Status
))
462 SetLastNtError(Status
);
463 RETURN( (RTL_ATOM
)0);
466 /* Deny negative sizes */
467 if (lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0)
469 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
470 RETURN( (RTL_ATOM
)0);
473 if (!lpwcx
->hInstance
)
475 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
476 RETURN( (RTL_ATOM
)0);
479 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
481 //FIXME: make ClassName ptr the atom, not buffer
482 if (ClassName
->Length
> 0)
484 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName
->Buffer
);
485 /* FIXME - Safely copy/verify the buffer first!!! */
486 Status
= RtlAddAtomToAtomTable(WinSta
->AtomTable
,
489 if (!NT_SUCCESS(Status
))
491 DPRINT1("Failed adding class name (%S) to atom table\n",
493 SetLastNtError(Status
);
499 Atom
= (RTL_ATOM
)(ULONG
)ClassName
->Buffer
;
504 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
508 if (!IntRegisterClass(&SafeClass
, Flags
, wpExtra
, MenuName
, Atom
))
510 if (ClassName
->Length
)
512 RtlDeleteAtomFromAtomTable(WinSta
->AtomTable
, Atom
);
514 DPRINT("Failed creating window class object\n");
521 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_
);
529 NtUserGetClassLong(HWND hWnd
, DWORD Offset
, BOOL Ansi
)
531 PWINDOW_OBJECT Window
;
532 DECLARE_RETURN(DWORD
);
534 DPRINT("Enter NtUserGetClassLong\n");
535 UserEnterExclusive();
537 if (!(Window
= UserGetWindowObject(hWnd
)))
542 RETURN(IntGetClassLong(Window
, Offset
, Ansi
));
545 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_
);
553 NtUserSetClassLong(HWND hWnd
,
558 PWINDOW_OBJECT Window
;
560 DECLARE_RETURN(DWORD
);
562 DPRINT("Enter NtUserSetClassLong\n");
563 UserEnterExclusive();
565 if (!(Window
= UserGetWindowObject(hWnd
)))
570 UserRefObjectCo(Window
);
572 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
573 co_IntSetClassLong(Window
, Offset
, dwNewLong
, Ansi
);
575 UserDerefObjectCo(Window
);
580 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_
);
586 NtUserSetClassWord(DWORD Unknown0
,
595 NtUserUnregisterClass(
596 LPCWSTR ClassNameOrAtom
,
597 HINSTANCE hInstance
, /* can be 0 */
600 PWNDCLASS_OBJECT Class
;
601 DECLARE_RETURN(BOOL
);
603 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom
);
604 UserEnterExclusive();
606 if (!ClassNameOrAtom
)
608 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
612 if (!(Class
= ClassGetClassByNameOrAtom(ClassNameOrAtom
, hInstance
)))
614 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
618 /* this was probably ment to prevent sysclass dereg
619 Seems wrong. Any class can have NULL hInst, not only sysclasses
622 // if (Class->hInstance && Class->hInstance != hInstance)
624 // SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
630 /* NOTE: the class will not be freed when its refs become 0 ie. no more
631 * windows are using it. I dunno why that is but its how Windows does it (and Wine).
632 * The class will hang around until the process exit. -Gunnar
634 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
643 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_
);
648 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
653 LPWNDCLASSEXW lpWndClassEx
,
657 PWNDCLASS_OBJECT Class
;
659 DECLARE_RETURN(DWORD
);
661 if (IS_ATOM(lpClassName
))
662 DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName
, hInstance
);
664 DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName
, hInstance
);
666 UserEnterExclusive();
670 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
674 if (!(Class
= ClassGetClassByNameOrAtom(lpClassName
, hInstance
)))
676 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
680 lpWndClassEx
->cbSize
= sizeof(WNDCLASSEXW
);
681 lpWndClassEx
->style
= Class
->style
;
683 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcA
;
685 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcW
;
686 lpWndClassEx
->cbClsExtra
= Class
->cbClsExtra
;
687 lpWndClassEx
->cbWndExtra
= Class
->cbWndExtra
;
688 /* This is not typo, we're really not going to use Class->hInstance here. */
689 /* Well, i think its wrong so i changed it -Gunnar */
690 lpWndClassEx
->hInstance
= Class
->hInstance
;
691 lpWndClassEx
->hIcon
= Class
->hIcon
;
692 lpWndClassEx
->hCursor
= Class
->hCursor
;
693 lpWndClassEx
->hbrBackground
= Class
->hbrBackground
;
694 if (Class
->lpszMenuName
.MaximumLength
)
695 RtlCopyUnicodeString((PUNICODE_STRING
)lpWndClassEx
->lpszMenuName
, &Class
->lpszMenuName
);
697 lpWndClassEx
->lpszMenuName
= Class
->lpszMenuName
.Buffer
;
698 lpWndClassEx
->lpszClassName
= lpClassName
;
699 lpWndClassEx
->hIconSm
= Class
->hIconSm
;
705 DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_
);
716 ULONG nMaxCount
/* in TCHARS */
719 PWINDOW_OBJECT Window
;
720 DECLARE_RETURN(DWORD
);
721 PWINSTATION_OBJECT WinSta
;
725 DPRINT("Enter NtUserGetClassName\n");
727 if (!(Window
= UserGetWindowObject(hWnd
)))
732 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
734 nMaxCount
*= sizeof(WCHAR
);
736 //FIXME: wrap in SEH to protect lpClassName access
737 Status
= RtlQueryAtomInAtomTable(WinSta
->AtomTable
,
738 Window
->Class
->Atom
, NULL
, NULL
,
739 lpClassName
, &nMaxCount
);
740 if (!NT_SUCCESS(Status
))
742 SetLastNtError(Status
);
746 RETURN(nMaxCount
/ sizeof(WCHAR
));
749 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_
);
755 NtUserGetWOWClass(DWORD Unknown0
,