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 ClassReferenceClassByAtom(
52 PWNDCLASS_OBJECT
* Class
,
56 PWNDCLASS_OBJECT Current
, BestMatch
= NULL
;
57 PLIST_ENTRY CurrentEntry
;
58 PW32PROCESS Process
= PsGetWin32Process();
60 CurrentEntry
= Process
->ClassListHead
.Flink
;
61 while (CurrentEntry
!= &Process
->ClassListHead
)
63 Current
= CONTAINING_RECORD(CurrentEntry
, WNDCLASS_OBJECT
, ListEntry
);
65 if (Current
->Atom
== Atom
&& (hInstance
== NULL
|| Current
->hInstance
== hInstance
))
68 ObmReferenceObject(Current
);
72 if (Current
->Atom
== Atom
&& Current
->Global
)
75 CurrentEntry
= CurrentEntry
->Flink
;
78 if (BestMatch
!= NULL
)
81 ObmReferenceObject(BestMatch
);
89 ClassReferenceClassByName(
90 PWNDCLASS_OBJECT
*Class
,
94 PWINSTATION_OBJECT WinStaObject
;
99 if (!ClassName
|| !PsGetWin32Thread()->Desktop
)
102 WinStaObject
= PsGetWin32Thread()->Desktop
->WindowStation
;
104 Status
= RtlLookupAtomInAtomTable(
105 WinStaObject
->AtomTable
,
109 if (!NT_SUCCESS(Status
))
111 DPRINT1("Failed to lookup class atom!\n");
115 Found
= ClassReferenceClassByAtom(Class
, ClassAtom
, hInstance
);
121 ClassReferenceClassByNameOrAtom(
122 PWNDCLASS_OBJECT
*Class
,
123 LPCWSTR ClassNameOrAtom
,
128 if (IS_ATOM(ClassNameOrAtom
))
129 Found
= ClassReferenceClassByAtom(Class
, (RTL_ATOM
)((ULONG_PTR
)ClassNameOrAtom
), hInstance
);
131 Found
= ClassReferenceClassByName(Class
, ClassNameOrAtom
, hInstance
);
140 LPWNDCLASSEXW lpWndClassEx
,
144 PWNDCLASS_OBJECT Class
;
146 DECLARE_RETURN(DWORD
);
148 if (IS_ATOM(lpClassName
))
149 DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName
, hInstance
);
151 DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName
, hInstance
);
153 UserEnterExclusive();
155 if (!ClassReferenceClassByNameOrAtom(&Class
, lpClassName
, hInstance
))
157 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
161 lpWndClassEx
->cbSize
= sizeof(WNDCLASSEXW
);
162 lpWndClassEx
->style
= Class
->style
;
164 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcA
;
166 lpWndClassEx
->lpfnWndProc
= Class
->lpfnWndProcW
;
167 lpWndClassEx
->cbClsExtra
= Class
->cbClsExtra
;
168 lpWndClassEx
->cbWndExtra
= Class
->cbWndExtra
;
169 /* This is not typo, we're really not going to use Class->hInstance here. */
170 lpWndClassEx
->hInstance
= hInstance
;
171 lpWndClassEx
->hIcon
= Class
->hIcon
;
172 lpWndClassEx
->hCursor
= Class
->hCursor
;
173 lpWndClassEx
->hbrBackground
= Class
->hbrBackground
;
174 if (Class
->lpszMenuName
.MaximumLength
)
175 RtlCopyUnicodeString((PUNICODE_STRING
)lpWndClassEx
->lpszMenuName
, &Class
->lpszMenuName
);
177 lpWndClassEx
->lpszMenuName
= Class
->lpszMenuName
.Buffer
;
178 lpWndClassEx
->lpszClassName
= lpClassName
;
179 lpWndClassEx
->hIconSm
= Class
->hIconSm
;
182 ObmDereferenceObject(Class
);
187 DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_
);
193 IntGetClassName(struct _WINDOW_OBJECT
*WindowObject
, LPWSTR lpClassName
,
198 PWINSTATION_OBJECT WinStaObject
;
201 if(!PsGetWin32Thread()->Desktop
)
206 WinStaObject
= PsGetWin32Thread()->Desktop
->WindowStation
;
209 Status
= RtlQueryAtomInAtomTable(WinStaObject
->AtomTable
,
210 WindowObject
->Class
->Atom
, NULL
, NULL
, NULL
, &Length
);
211 Name
= ExAllocatePoolWithTag(PagedPool
, Length
+ sizeof(UNICODE_NULL
), TAG_STRING
);
212 Status
= RtlQueryAtomInAtomTable(WinStaObject
->AtomTable
,
213 WindowObject
->Class
->Atom
, NULL
, NULL
, Name
, &Length
);
214 if (!NT_SUCCESS(Status
))
216 DPRINT("IntGetClassName: RtlQueryAtomInAtomTable failed\n");
219 Length
/= sizeof(WCHAR
);
220 if (Length
> nMaxCount
)
224 wcsncpy(lpClassName
, Name
, Length
);
225 /* FIXME: Check buffer size before doing this! */
226 *(lpClassName
+ Length
) = 0;
238 PWINDOW_OBJECT Window
;
239 DECLARE_RETURN(DWORD
);
242 DPRINT("Enter NtUserGetClassName\n");
244 if (!(Window
= UserGetWindowObject(hWnd
)))
249 RETURN( IntGetClassName(Window
, lpClassName
, nMaxCount
));
252 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_
);
258 NtUserGetWOWClass(DWORD Unknown0
,
265 PWNDCLASS_OBJECT FASTCALL
267 CONST WNDCLASSEXW
*lpwcx
,
270 PUNICODE_STRING MenuName
,
273 PWNDCLASS_OBJECT ClassObject
;
277 Global
= (Flags
& REGISTERCLASS_SYSTEM
) || (lpwcx
->style
& CS_GLOBALCLASS
) ? TRUE
: FALSE
;
279 /* Check for double registration of the class. */
280 if (PsGetWin32Process() != NULL
)
282 if (ClassReferenceClassByAtom(&ClassObject
, Atom
, lpwcx
->hInstance
))
285 * NOTE: We may also get a global class from
286 * ClassReferenceClassByAtom. This simple check
287 * prevents that we fail valid request.
289 if (ClassObject
->hInstance
== lpwcx
->hInstance
)
291 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
292 ObmDereferenceObject(ClassObject
);
298 objectSize
= sizeof(WNDCLASS_OBJECT
) + lpwcx
->cbClsExtra
;
299 ClassObject
= ObmCreateObject(&gHandleTable
, NULL
, otClass
, objectSize
);
300 if (ClassObject
== 0)
302 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
306 ClassObject
->cbSize
= lpwcx
->cbSize
;
307 ClassObject
->style
= lpwcx
->style
;
308 ClassObject
->cbClsExtra
= lpwcx
->cbClsExtra
;
309 ClassObject
->cbWndExtra
= lpwcx
->cbWndExtra
;
310 ClassObject
->hInstance
= lpwcx
->hInstance
;
311 ClassObject
->hIcon
= lpwcx
->hIcon
;
312 ClassObject
->hCursor
= lpwcx
->hCursor
;
313 ClassObject
->hbrBackground
= lpwcx
->hbrBackground
;
314 ClassObject
->Unicode
= !(Flags
& REGISTERCLASS_ANSI
);
315 ClassObject
->Global
= Global
;
316 ClassObject
->hIconSm
= lpwcx
->hIconSm
;
317 ClassObject
->Atom
= Atom
;
320 if (Flags
& REGISTERCLASS_ANSI
)
322 ClassObject
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
323 ClassObject
->lpfnWndProcW
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,FALSE
);
327 ClassObject
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
328 ClassObject
->lpfnWndProcA
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,TRUE
);
333 if (Flags
& REGISTERCLASS_ANSI
)
335 ClassObject
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
336 ClassObject
->lpfnWndProcW
= wpExtra
;
340 ClassObject
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
341 ClassObject
->lpfnWndProcA
= wpExtra
;
344 if (MenuName
->Length
== 0)
346 ClassObject
->lpszMenuName
.Length
=
347 ClassObject
->lpszMenuName
.MaximumLength
= 0;
348 ClassObject
->lpszMenuName
.Buffer
= MenuName
->Buffer
;
352 ClassObject
->lpszMenuName
.Length
=
353 ClassObject
->lpszMenuName
.MaximumLength
= MenuName
->MaximumLength
;
354 ClassObject
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ClassObject
->lpszMenuName
.MaximumLength
, TAG_STRING
);
355 RtlCopyUnicodeString(&ClassObject
->lpszMenuName
, MenuName
);
357 /* Extra class data */
358 if (ClassObject
->cbClsExtra
!= 0)
360 ClassObject
->ExtraData
= (PCHAR
)(ClassObject
+ 1);
361 RtlZeroMemory(ClassObject
->ExtraData
, (ULONG
)ClassObject
->cbClsExtra
);
365 ClassObject
->ExtraData
= NULL
;
368 InitializeListHead(&ClassObject
->ClassWindowsListHead
);
374 NtUserRegisterClassExWOW(
375 CONST WNDCLASSEXW
* lpwcx
,
376 PUNICODE_STRING ClassName
,
377 PUNICODE_STRING ClassNameCopy
,
378 PUNICODE_STRING MenuName
,
379 WNDPROC wpExtra
, /* FIXME: Windows uses this parameter for something different. */
385 * Registers a new class with the window manager
387 * lpwcx = Win32 extended window class structure
388 * bUnicodeClass = Whether to send ANSI or unicode strings
389 * to window procedures
390 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
392 * Atom identifying the new class
395 WNDCLASSEXW SafeClass
;
396 PWINSTATION_OBJECT WinStaObject
;
397 PWNDCLASS_OBJECT ClassObject
;
400 DECLARE_RETURN(RTL_ATOM
);
402 DPRINT("Enter NtUserRegisterClassExWOW\n");
403 UserEnterExclusive();
407 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
408 RETURN( (RTL_ATOM
)0);
411 if (Flags
& ~REGISTERCLASS_ALL
)
413 SetLastWin32Error(ERROR_INVALID_FLAGS
);
414 RETURN( (RTL_ATOM
)0);
417 Status
= MmCopyFromCaller(&SafeClass
, lpwcx
, sizeof(WNDCLASSEXW
));
418 if (!NT_SUCCESS(Status
))
420 SetLastNtError(Status
);
421 RETURN( (RTL_ATOM
)0);
424 /* Deny negative sizes */
425 if (lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0)
427 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
428 RETURN( (RTL_ATOM
)0);
431 WinStaObject
= PsGetWin32Thread()->Desktop
->WindowStation
;
433 if (ClassName
->Length
> 0)
435 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName
->Buffer
);
436 /* FIXME - Safely copy/verify the buffer first!!! */
437 Status
= RtlAddAtomToAtomTable(WinStaObject
->AtomTable
,
440 if (!NT_SUCCESS(Status
))
442 DPRINT1("Failed adding class name (%S) to atom table\n",
444 SetLastNtError(Status
);
450 Atom
= (RTL_ATOM
)(ULONG
)ClassName
->Buffer
;
452 ClassObject
= IntCreateClass(&SafeClass
, Flags
, wpExtra
, MenuName
, Atom
);
453 if (ClassObject
== NULL
)
455 if (ClassName
->Length
)
457 RtlDeleteAtomFromAtomTable(WinStaObject
->AtomTable
, Atom
);
459 DPRINT("Failed creating window class object\n");
463 InsertTailList(&PsGetWin32Process()->ClassListHead
, &ClassObject
->ListEntry
);
468 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_
);
474 IntGetClassLong(struct _WINDOW_OBJECT
*Window
, ULONG Offset
, BOOL Ansi
)
478 if ((int)Offset
>= 0)
480 DPRINT("GetClassLong(%x, %d)\n", Window
->hSelf
, Offset
);
481 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
483 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
486 Ret
= *((LONG
*)(Window
->Class
->ExtraData
+ Offset
));
487 DPRINT("Result: %x\n", Ret
);
494 Ret
= Window
->Class
->cbWndExtra
;
497 Ret
= Window
->Class
->cbClsExtra
;
499 case GCL_HBRBACKGROUND
:
500 Ret
= (ULONG
)Window
->Class
->hbrBackground
;
503 Ret
= (ULONG
)Window
->Class
->hCursor
;
506 Ret
= (ULONG
)Window
->Class
->hIcon
;
509 Ret
= (ULONG
)Window
->Class
->hIconSm
;
512 Ret
= (ULONG
)Window
->Class
->hInstance
;
515 Ret
= (ULONG
)Window
->Class
->lpszMenuName
.Buffer
;
518 Ret
= Window
->Class
->style
;
523 Ret
= (ULONG
)Window
->Class
->lpfnWndProcA
;
527 Ret
= (ULONG
)Window
->Class
->lpfnWndProcW
;
531 Ret
= Window
->Class
->Atom
;
541 NtUserGetClassLong(HWND hWnd
, DWORD Offset
, BOOL Ansi
)
543 PWINDOW_OBJECT Window
;
544 DECLARE_RETURN(DWORD
);
546 DPRINT("Enter NtUserGetClassLong\n");
547 UserEnterExclusive();
549 if (!(Window
= UserGetWindowObject(hWnd
)))
554 RETURN(IntGetClassLong(Window
, Offset
, Ansi
));
557 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_
);
563 co_IntSetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, LONG dwNewLong
, BOOL Ansi
)
565 ASSERT_REFS_CO(Window
);
567 if ((int)Offset
>= 0)
569 DPRINT("SetClassLong(%x, %d, %x)\n", Window
->hSelf
, Offset
, dwNewLong
);
570 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
572 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
575 *((LONG
*)(Window
->Class
->ExtraData
+ Offset
)) = dwNewLong
;
582 Window
->Class
->cbWndExtra
= dwNewLong
;
585 Window
->Class
->cbClsExtra
= dwNewLong
;
587 case GCL_HBRBACKGROUND
:
588 Window
->Class
->hbrBackground
= (HBRUSH
)dwNewLong
;
591 Window
->Class
->hCursor
= (HCURSOR
)dwNewLong
;
594 Window
->Class
->hIcon
= (HICON
)dwNewLong
;
596 if (!IntGetOwner(Window
) && !IntGetParent(Window
))
598 co_IntShellHookNotify(HSHELL_REDRAW
, (LPARAM
) Window
->hSelf
);
602 Window
->Class
->hIconSm
= (HICON
)dwNewLong
;
605 Window
->Class
->hInstance
= (HINSTANCE
)dwNewLong
;
608 if (Window
->Class
->lpszMenuName
.MaximumLength
)
609 RtlFreeUnicodeString(&Window
->Class
->lpszMenuName
);
610 if (!IS_INTRESOURCE(dwNewLong
))
612 Window
->Class
->lpszMenuName
.Length
=
613 Window
->Class
->lpszMenuName
.MaximumLength
= ((PUNICODE_STRING
)dwNewLong
)->MaximumLength
;
614 Window
->Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Window
->Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
615 RtlCopyUnicodeString(&Window
->Class
->lpszMenuName
, (PUNICODE_STRING
)dwNewLong
);
619 Window
->Class
->lpszMenuName
.Length
=
620 Window
->Class
->lpszMenuName
.MaximumLength
= 0;
621 Window
->Class
->lpszMenuName
.Buffer
= (LPWSTR
)dwNewLong
;
625 Window
->Class
->style
= dwNewLong
;
630 Window
->Class
->lpfnWndProcA
= (WNDPROC
)dwNewLong
;
631 Window
->Class
->lpfnWndProcW
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,FALSE
);
632 Window
->Class
->Unicode
= FALSE
;
636 Window
->Class
->lpfnWndProcW
= (WNDPROC
)dwNewLong
;
637 Window
->Class
->lpfnWndProcA
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,TRUE
);
638 Window
->Class
->Unicode
= TRUE
;
645 NtUserSetClassLong(HWND hWnd
,
650 PWINDOW_OBJECT Window
;
652 DECLARE_RETURN(DWORD
);
654 DPRINT("Enter NtUserSetClassLong\n");
655 UserEnterExclusive();
657 if (!(Window
= UserGetWindowObject(hWnd
)))
662 UserRefObjectCo(Window
);
664 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
665 co_IntSetClassLong(Window
, Offset
, dwNewLong
, Ansi
);
667 UserDerefObjectCo(Window
);
672 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_
);
678 NtUserSetClassWord(DWORD Unknown0
,
687 NtUserUnregisterClass(
688 LPCWSTR ClassNameOrAtom
,
692 PWNDCLASS_OBJECT Class
;
693 PWINSTATION_OBJECT WinSta
;
694 DECLARE_RETURN(BOOL
);
696 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom
);
697 UserEnterExclusive();
699 if (!ClassNameOrAtom
|| !PsGetWin32Thread()->Desktop
)
701 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
705 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
707 if (!ClassReferenceClassByNameOrAtom(&Class
, ClassNameOrAtom
, hInstance
))
709 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
713 if (Class
->hInstance
&& Class
->hInstance
!= hInstance
)
715 ClassDereferenceObject(Class
);
716 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
720 if (!IsListEmpty(&Class
->ClassWindowsListHead
))
722 /* Dereference the ClassReferenceClassByNameOrAtom() call */
723 ObmDereferenceObject(Class
);
724 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
728 /* Dereference the ClassReferenceClassByNameOrAtom() call */
729 ClassDereferenceObject(Class
);
731 RemoveEntryList(&Class
->ListEntry
);
733 RtlDeleteAtomFromAtomTable(WinSta
->AtomTable
, Class
->Atom
);
735 /* Free the object */
736 ClassDereferenceObject(Class
);
741 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_
);