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
);
52 ClassDerefObject(PWNDCLASS_OBJECT Class
)
54 ASSERT(Class
->refs
>= 1);
60 ClassRefObject(PWNDCLASS_OBJECT Class
)
62 ASSERT(Class
->refs
>= 0);
67 VOID FASTCALL
DestroyClass(PWNDCLASS_OBJECT Class
)
69 ASSERT(Class
->refs
== 0);
71 RemoveEntryList(&Class
->ListEntry
);
72 RtlDeleteAtomFromAtomTable(gAtomTable
, Class
->Atom
);
77 /* clean all process classes. all process windows must cleaned first!! */
78 void FASTCALL
DestroyProcessClasses(PW32PROCESS Process
)
80 PWNDCLASS_OBJECT Class
;
82 while (!IsListEmpty(&Process
->ClassList
))
84 Class
= CONTAINING_RECORD(RemoveHeadList(&Process
->ClassList
), WNDCLASS_OBJECT
, ListEntry
);
92 PWNDCLASS_OBJECT FASTCALL
93 ClassGetClassByAtom(RTL_ATOM Atom
, HINSTANCE hInstance
)
95 PWNDCLASS_OBJECT Class
;
96 PW32PROCESS Process
= PsGetWin32Process();
98 LIST_FOR_EACH(Class
, &Process
->ClassList
, WNDCLASS_OBJECT
, ListEntry
)
100 if (Class
->Atom
!= Atom
) continue;
102 if (!hInstance
|| Class
->Global
|| Class
->hInstance
== hInstance
) return Class
;
109 PWNDCLASS_OBJECT FASTCALL
110 ClassGetClassByName(LPCWSTR ClassName
, HINSTANCE hInstance
)
115 if (!ClassName
|| !PsGetWin32Thread()->Desktop
)
118 Status
= RtlLookupAtomInAtomTable(
123 if (!NT_SUCCESS(Status
))
125 DPRINT1("Failed to lookup class atom!\n");
129 return ClassGetClassByAtom(Atom
, hInstance
);
133 PWNDCLASS_OBJECT FASTCALL
134 ClassGetClassByNameOrAtom(LPCWSTR ClassNameOrAtom
, HINSTANCE hInstance
)
136 if (!ClassNameOrAtom
) return NULL
;
138 if (IS_ATOM(ClassNameOrAtom
))
139 return ClassGetClassByAtom((RTL_ATOM
)((ULONG_PTR
)ClassNameOrAtom
), hInstance
);
141 return ClassGetClassByName(ClassNameOrAtom
, hInstance
);
148 CONST WNDCLASSEXW
*lpwcx
,
151 PUNICODE_STRING MenuName
,
154 PWNDCLASS_OBJECT Class
;
160 ASSERT(lpwcx
->hInstance
);
162 Global
= (Flags
& REGISTERCLASS_SYSTEM
) || (lpwcx
->style
& CS_GLOBALCLASS
);
164 /* Check for double registration of the class. */
165 Class
= ClassGetClassByAtom(Atom
, lpwcx
->hInstance
);
166 if (Class
&& Global
== Class
->Global
)
168 /* can max have one class of each type (global/local) */
169 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
173 objectSize
= sizeof(WNDCLASS_OBJECT
) + lpwcx
->cbClsExtra
;
175 //FIXME: allocate in session heap (or possibly desktop heap)
176 Class
= ExAllocatePool(PagedPool
, objectSize
);
179 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
182 RtlZeroMemory(Class
, objectSize
);
184 Class
->cbSize
= lpwcx
->cbSize
;
185 Class
->style
= lpwcx
->style
;
186 Class
->cbClsExtra
= lpwcx
->cbClsExtra
;
187 Class
->cbWndExtra
= lpwcx
->cbWndExtra
;
188 Class
->hInstance
= lpwcx
->hInstance
;
189 Class
->hIcon
= lpwcx
->hIcon
;
190 Class
->hCursor
= lpwcx
->hCursor
;
191 Class
->hbrBackground
= lpwcx
->hbrBackground
;
192 Class
->Unicode
= !(Flags
& REGISTERCLASS_ANSI
);
193 Class
->Global
= Global
;
194 Class
->hIconSm
= lpwcx
->hIconSm
;
199 if (Flags
& REGISTERCLASS_ANSI
)
201 Class
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
202 Class
->lpfnWndProcW
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,FALSE
);
206 Class
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
207 Class
->lpfnWndProcA
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,TRUE
);
212 if (Flags
& REGISTERCLASS_ANSI
)
214 Class
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
215 Class
->lpfnWndProcW
= wpExtra
;
219 Class
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
220 Class
->lpfnWndProcA
= wpExtra
;
224 if (MenuName
->Length
== 0)
226 Class
->lpszMenuName
.Length
=
227 Class
->lpszMenuName
.MaximumLength
= 0;
228 Class
->lpszMenuName
.Buffer
= MenuName
->Buffer
;
232 Class
->lpszMenuName
.Length
=
233 Class
->lpszMenuName
.MaximumLength
= MenuName
->MaximumLength
;
234 Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
235 RtlCopyUnicodeString(&Class
->lpszMenuName
, MenuName
);
238 /* Extra class data */
239 if (Class
->cbClsExtra
)
240 Class
->ExtraData
= (PCHAR
)(Class
+ 1);
244 /* global classes go last (incl. system classes) */
245 InsertTailList(&PsGetWin32Process()->ClassList
, &Class
->ListEntry
);
249 /* local classes have priority so we put them first */
250 InsertHeadList(&PsGetWin32Process()->ClassList
, &Class
->ListEntry
);
258 IntGetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, BOOL Ansi
)
262 if ((int)Offset
>= 0)
264 DPRINT("GetClassLong(%x, %d)\n", Window
->hSelf
, Offset
);
265 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
267 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
270 Ret
= *((LONG
*)(Window
->Class
->ExtraData
+ Offset
));
271 DPRINT("Result: %x\n", Ret
);
278 Ret
= Window
->Class
->cbWndExtra
;
281 Ret
= Window
->Class
->cbClsExtra
;
283 case GCL_HBRBACKGROUND
:
284 Ret
= (ULONG
)Window
->Class
->hbrBackground
;
287 Ret
= (ULONG
)Window
->Class
->hCursor
;
290 Ret
= (ULONG
)Window
->Class
->hIcon
;
293 Ret
= (ULONG
)Window
->Class
->hIconSm
;
296 Ret
= (ULONG
)Window
->Class
->hInstance
;
299 Ret
= (ULONG
)Window
->Class
->lpszMenuName
.Buffer
;
302 Ret
= Window
->Class
->style
;
307 Ret
= (ULONG
)Window
->Class
->lpfnWndProcA
;
311 Ret
= (ULONG
)Window
->Class
->lpfnWndProcW
;
315 Ret
= Window
->Class
->Atom
;
326 co_IntSetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, LONG dwNewLong
, BOOL Ansi
)
328 ASSERT_REFS_CO(Window
);
330 if ((int)Offset
>= 0)
332 DPRINT("SetClassLong(%x, %d, %x)\n", Window
->hSelf
, Offset
, dwNewLong
);
333 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
335 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
338 *((LONG
*)(Window
->Class
->ExtraData
+ Offset
)) = dwNewLong
;
345 Window
->Class
->cbWndExtra
= dwNewLong
;
348 Window
->Class
->cbClsExtra
= dwNewLong
;
350 case GCL_HBRBACKGROUND
:
351 Window
->Class
->hbrBackground
= (HBRUSH
)dwNewLong
;
354 Window
->Class
->hCursor
= (HCURSOR
)dwNewLong
;
357 Window
->Class
->hIcon
= (HICON
)dwNewLong
;
359 if (!IntGetOwner(Window
) && !IntGetParent(Window
))
361 co_IntShellHookNotify(HSHELL_REDRAW
, (LPARAM
) Window
->hSelf
);
365 Window
->Class
->hIconSm
= (HICON
)dwNewLong
;
368 Window
->Class
->hInstance
= (HINSTANCE
)dwNewLong
;
371 if (Window
->Class
->lpszMenuName
.MaximumLength
)
372 RtlFreeUnicodeString(&Window
->Class
->lpszMenuName
);
373 if (!IS_INTRESOURCE(dwNewLong
))
375 Window
->Class
->lpszMenuName
.Length
=
376 Window
->Class
->lpszMenuName
.MaximumLength
= ((PUNICODE_STRING
)dwNewLong
)->MaximumLength
;
377 Window
->Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Window
->Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
378 RtlCopyUnicodeString(&Window
->Class
->lpszMenuName
, (PUNICODE_STRING
)dwNewLong
);
382 Window
->Class
->lpszMenuName
.Length
=
383 Window
->Class
->lpszMenuName
.MaximumLength
= 0;
384 Window
->Class
->lpszMenuName
.Buffer
= (LPWSTR
)dwNewLong
;
388 Window
->Class
->style
= dwNewLong
;
393 Window
->Class
->lpfnWndProcA
= (WNDPROC
)dwNewLong
;
394 Window
->Class
->lpfnWndProcW
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,FALSE
);
395 Window
->Class
->Unicode
= FALSE
;
399 Window
->Class
->lpfnWndProcW
= (WNDPROC
)dwNewLong
;
400 Window
->Class
->lpfnWndProcA
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,TRUE
);
401 Window
->Class
->Unicode
= TRUE
;
406 /* SYSCALLS *****************************************************************/
410 NtUserRegisterClassExWOW(
411 CONST WNDCLASSEXW
* lpwcx
,
412 PUNICODE_STRING ClassName
,
413 PUNICODE_STRING ClassNameCopy
,//huhuhuhu???
414 PUNICODE_STRING MenuName
,
421 * Registers a new class with the window manager
423 * lpwcx = Win32 extended window class structure
424 * bUnicodeClass = Whether to send ANSI or unicode strings
425 * to window procedures
426 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
428 * Atom identifying the new class
431 WNDCLASSEXW SafeClass
;
434 DECLARE_RETURN(RTL_ATOM
);
436 DPRINT("Enter NtUserRegisterClassExWOW\n");
437 UserEnterExclusive();
441 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
442 RETURN( (RTL_ATOM
)0);
445 if (Flags
& ~REGISTERCLASS_ALL
)
447 SetLastWin32Error(ERROR_INVALID_FLAGS
);
448 RETURN( (RTL_ATOM
)0);
451 Status
= MmCopyFromCaller(&SafeClass
, lpwcx
, sizeof(WNDCLASSEXW
));
452 if (!NT_SUCCESS(Status
))
454 SetLastNtError(Status
);
455 RETURN( (RTL_ATOM
)0);
458 /* Deny negative sizes */
459 if (lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0)
461 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
462 RETURN( (RTL_ATOM
)0);
465 if (!lpwcx
->hInstance
)
467 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
468 RETURN( (RTL_ATOM
)0);
471 //FIXME: make ClassName ptr the atom, not buffer
472 if (ClassName
->Length
> 0)
474 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName
->Buffer
);
475 /* FIXME - Safely copy/verify the buffer first!!! */
476 Status
= RtlAddAtomToAtomTable(gAtomTable
,
479 if (!NT_SUCCESS(Status
))
481 DPRINT1("Failed adding class name (%S) to atom table\n",
483 SetLastNtError(Status
);
489 Atom
= (RTL_ATOM
)(ULONG
)ClassName
->Buffer
;
494 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
498 if (!IntRegisterClass(&SafeClass
, Flags
, wpExtra
, MenuName
, Atom
))
500 if (ClassName
->Length
)
502 RtlDeleteAtomFromAtomTable(gAtomTable
, Atom
);
504 DPRINT("Failed creating window class object\n");
511 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_
);
519 NtUserGetClassLong(HWND hWnd
, DWORD Offset
, BOOL Ansi
)
521 PWINDOW_OBJECT Window
;
522 DECLARE_RETURN(DWORD
);
524 DPRINT("Enter NtUserGetClassLong\n");
525 UserEnterExclusive();
527 if (!(Window
= UserGetWindowObject(hWnd
)))
532 RETURN(IntGetClassLong(Window
, Offset
, Ansi
));
535 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_
);
543 NtUserSetClassLong(HWND hWnd
,
548 PWINDOW_OBJECT Window
;
550 USER_REFERENCE_ENTRY Ref
;
551 DECLARE_RETURN(DWORD
);
553 DPRINT("Enter NtUserSetClassLong\n");
554 UserEnterExclusive();
556 if (!(Window
= UserGetWindowObject(hWnd
)))
561 UserRefObjectCo(Window
, &Ref
);
563 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
564 co_IntSetClassLong(Window
, Offset
, dwNewLong
, Ansi
);
566 UserDerefObjectCo(Window
);
571 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_
);
577 NtUserSetClassWord(DWORD Unknown0
,
586 NtUserUnregisterClass(
587 LPCWSTR ClassNameOrAtom
,
588 HINSTANCE hInstance
, /* can be 0 */
591 PWNDCLASS_OBJECT Class
;
592 DECLARE_RETURN(BOOL
);
594 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom
);
595 UserEnterExclusive();
597 if (!ClassNameOrAtom
)
599 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
603 if (!(Class
= ClassGetClassByNameOrAtom(ClassNameOrAtom
, hInstance
)))
605 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
611 /* NOTE: the class will not be freed when its refs become 0 ie. no more
612 * windows are using it. I dunno why that is but its how Windows does it (and Wine).
613 * The class will hang around until the process exit. -Gunnar
615 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
624 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_
);
629 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
634 LPWNDCLASSEXW lpWndClassEx
,
638 PWNDCLASS_OBJECT Class
;
640 DECLARE_RETURN(DWORD
);
642 if (IS_ATOM(lpClassName
))
643 DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName
, hInstance
);
645 DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName
, hInstance
);
647 UserEnterExclusive();
651 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
655 if (!(Class
= ClassGetClassByNameOrAtom(lpClassName
, hInstance
)))
657 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
661 lpWndClassEx
->cbSize
= sizeof(WNDCLASSEXW
);
662 lpWndClassEx
->style
= Class
->style
;
664 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcA
;
666 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcW
;
667 lpWndClassEx
->cbClsExtra
= Class
->cbClsExtra
;
668 lpWndClassEx
->cbWndExtra
= Class
->cbWndExtra
;
669 /* This is not typo, we're really not going to use Class->hInstance here. */
670 /* Well, i think its wrong so i changed it -Gunnar */
671 lpWndClassEx
->hInstance
= Class
->hInstance
;
672 lpWndClassEx
->hIcon
= Class
->hIcon
;
673 lpWndClassEx
->hCursor
= Class
->hCursor
;
674 lpWndClassEx
->hbrBackground
= Class
->hbrBackground
;
675 if (Class
->lpszMenuName
.MaximumLength
)
676 RtlCopyUnicodeString((PUNICODE_STRING
)lpWndClassEx
->lpszMenuName
, &Class
->lpszMenuName
);
678 lpWndClassEx
->lpszMenuName
= Class
->lpszMenuName
.Buffer
;
679 lpWndClassEx
->lpszClassName
= lpClassName
;
680 lpWndClassEx
->hIconSm
= Class
->hIconSm
;
686 DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_
);
697 ULONG nMaxCount
/* in TCHARS */
700 PWINDOW_OBJECT Window
;
701 DECLARE_RETURN(DWORD
);
705 DPRINT("Enter NtUserGetClassName\n");
707 if (!(Window
= UserGetWindowObject(hWnd
)))
712 nMaxCount
*= sizeof(WCHAR
);
714 //FIXME: wrap in SEH to protect lpClassName access
715 Status
= RtlQueryAtomInAtomTable(gAtomTable
,
716 Window
->Class
->Atom
, NULL
, NULL
,
717 lpClassName
, &nMaxCount
);
718 if (!NT_SUCCESS(Status
))
720 SetLastNtError(Status
);
724 RETURN(nMaxCount
/ sizeof(WCHAR
));
727 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_
);
733 NtUserGetWOWClass(DWORD Unknown0
,