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
,
212 Length
+= sizeof(WCHAR
);
213 Name
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_STRING
);
214 Status
= RtlQueryAtomInAtomTable(WinStaObject
->AtomTable
,
215 WindowObject
->Class
->Atom
, NULL
, NULL
,
217 if (!NT_SUCCESS(Status
))
219 DPRINT("IntGetClassName: RtlQueryAtomInAtomTable failed\n");
222 Length
/= sizeof(WCHAR
);
223 if (Length
> nMaxCount
)
227 wcsncpy(lpClassName
, Name
, Length
);
228 /* FIXME: Check buffer size before doing this! */
229 *(lpClassName
+ Length
) = 0;
241 PWINDOW_OBJECT Window
;
242 DECLARE_RETURN(DWORD
);
245 DPRINT("Enter NtUserGetClassName\n");
247 if (!(Window
= UserGetWindowObject(hWnd
)))
252 RETURN( IntGetClassName(Window
, lpClassName
, nMaxCount
));
255 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_
);
261 NtUserGetWOWClass(DWORD Unknown0
,
268 PWNDCLASS_OBJECT FASTCALL
270 CONST WNDCLASSEXW
*lpwcx
,
273 PUNICODE_STRING MenuName
,
276 PWNDCLASS_OBJECT ClassObject
;
280 Global
= (Flags
& REGISTERCLASS_SYSTEM
) || (lpwcx
->style
& CS_GLOBALCLASS
) ? TRUE
: FALSE
;
282 /* Check for double registration of the class. */
283 if (PsGetWin32Process() != NULL
)
285 if (ClassReferenceClassByAtom(&ClassObject
, Atom
, lpwcx
->hInstance
))
288 * NOTE: We may also get a global class from
289 * ClassReferenceClassByAtom. This simple check
290 * prevents that we fail valid request.
292 if (ClassObject
->hInstance
== lpwcx
->hInstance
)
294 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS
);
295 ObmDereferenceObject(ClassObject
);
301 objectSize
= sizeof(WNDCLASS_OBJECT
) + lpwcx
->cbClsExtra
;
302 ClassObject
= ObmCreateObject(&gHandleTable
, NULL
, otClass
, objectSize
);
303 if (ClassObject
== 0)
305 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
309 ClassObject
->cbSize
= lpwcx
->cbSize
;
310 ClassObject
->style
= lpwcx
->style
;
311 ClassObject
->cbClsExtra
= lpwcx
->cbClsExtra
;
312 ClassObject
->cbWndExtra
= lpwcx
->cbWndExtra
;
313 ClassObject
->hInstance
= lpwcx
->hInstance
;
314 ClassObject
->hIcon
= lpwcx
->hIcon
;
315 ClassObject
->hCursor
= lpwcx
->hCursor
;
316 ClassObject
->hbrBackground
= lpwcx
->hbrBackground
;
317 ClassObject
->Unicode
= !(Flags
& REGISTERCLASS_ANSI
);
318 ClassObject
->Global
= Global
;
319 ClassObject
->hIconSm
= lpwcx
->hIconSm
;
320 ClassObject
->Atom
= Atom
;
323 if (Flags
& REGISTERCLASS_ANSI
)
325 ClassObject
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
326 ClassObject
->lpfnWndProcW
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,FALSE
);
330 ClassObject
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
331 ClassObject
->lpfnWndProcA
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,TRUE
);
336 if (Flags
& REGISTERCLASS_ANSI
)
338 ClassObject
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
339 ClassObject
->lpfnWndProcW
= wpExtra
;
343 ClassObject
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
344 ClassObject
->lpfnWndProcA
= wpExtra
;
347 if (MenuName
->Length
== 0)
349 ClassObject
->lpszMenuName
.Length
=
350 ClassObject
->lpszMenuName
.MaximumLength
= 0;
351 ClassObject
->lpszMenuName
.Buffer
= MenuName
->Buffer
;
355 ClassObject
->lpszMenuName
.Length
=
356 ClassObject
->lpszMenuName
.MaximumLength
= MenuName
->MaximumLength
;
357 ClassObject
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ClassObject
->lpszMenuName
.MaximumLength
, TAG_STRING
);
358 RtlCopyUnicodeString(&ClassObject
->lpszMenuName
, MenuName
);
360 /* Extra class data */
361 if (ClassObject
->cbClsExtra
!= 0)
363 ClassObject
->ExtraData
= (PCHAR
)(ClassObject
+ 1);
364 RtlZeroMemory(ClassObject
->ExtraData
, (ULONG
)ClassObject
->cbClsExtra
);
368 ClassObject
->ExtraData
= NULL
;
371 InitializeListHead(&ClassObject
->ClassWindowsListHead
);
377 NtUserRegisterClassExWOW(
378 CONST WNDCLASSEXW
* lpwcx
,
379 PUNICODE_STRING ClassName
,
380 PUNICODE_STRING ClassNameCopy
,
381 PUNICODE_STRING MenuName
,
382 WNDPROC wpExtra
, /* FIXME: Windows uses this parameter for something different. */
388 * Registers a new class with the window manager
390 * lpwcx = Win32 extended window class structure
391 * bUnicodeClass = Whether to send ANSI or unicode strings
392 * to window procedures
393 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
395 * Atom identifying the new class
398 WNDCLASSEXW SafeClass
;
399 PWINSTATION_OBJECT WinStaObject
;
400 PWNDCLASS_OBJECT ClassObject
;
403 DECLARE_RETURN(RTL_ATOM
);
405 DPRINT("Enter NtUserRegisterClassExWOW\n");
406 UserEnterExclusive();
410 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
411 RETURN( (RTL_ATOM
)0);
414 if (Flags
& ~REGISTERCLASS_ALL
)
416 SetLastWin32Error(ERROR_INVALID_FLAGS
);
417 RETURN( (RTL_ATOM
)0);
420 Status
= MmCopyFromCaller(&SafeClass
, lpwcx
, sizeof(WNDCLASSEXW
));
421 if (!NT_SUCCESS(Status
))
423 SetLastNtError(Status
);
424 RETURN( (RTL_ATOM
)0);
427 /* Deny negative sizes */
428 if (lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0)
430 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
431 RETURN( (RTL_ATOM
)0);
434 WinStaObject
= PsGetWin32Thread()->Desktop
->WindowStation
;
436 if (ClassName
->Length
> 0)
438 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName
->Buffer
);
439 /* FIXME - Safely copy/verify the buffer first!!! */
440 Status
= RtlAddAtomToAtomTable(WinStaObject
->AtomTable
,
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("Failed adding class name (%S) to atom table\n",
447 SetLastNtError(Status
);
453 Atom
= (RTL_ATOM
)(ULONG
)ClassName
->Buffer
;
455 ClassObject
= IntCreateClass(&SafeClass
, Flags
, wpExtra
, MenuName
, Atom
);
456 if (ClassObject
== NULL
)
458 if (ClassName
->Length
)
460 RtlDeleteAtomFromAtomTable(WinStaObject
->AtomTable
, Atom
);
462 DPRINT("Failed creating window class object\n");
466 InsertTailList(&PsGetWin32Process()->ClassListHead
, &ClassObject
->ListEntry
);
471 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_
);
477 IntGetClassLong(struct _WINDOW_OBJECT
*Window
, ULONG Offset
, BOOL Ansi
)
481 if ((int)Offset
>= 0)
483 DPRINT("GetClassLong(%x, %d)\n", Window
->hSelf
, Offset
);
484 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
486 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
489 Ret
= *((LONG
*)(Window
->Class
->ExtraData
+ Offset
));
490 DPRINT("Result: %x\n", Ret
);
497 Ret
= Window
->Class
->cbWndExtra
;
500 Ret
= Window
->Class
->cbClsExtra
;
502 case GCL_HBRBACKGROUND
:
503 Ret
= (ULONG
)Window
->Class
->hbrBackground
;
506 Ret
= (ULONG
)Window
->Class
->hCursor
;
509 Ret
= (ULONG
)Window
->Class
->hIcon
;
512 Ret
= (ULONG
)Window
->Class
->hIconSm
;
515 Ret
= (ULONG
)Window
->Class
->hInstance
;
518 Ret
= (ULONG
)Window
->Class
->lpszMenuName
.Buffer
;
521 Ret
= Window
->Class
->style
;
526 Ret
= (ULONG
)Window
->Class
->lpfnWndProcA
;
530 Ret
= (ULONG
)Window
->Class
->lpfnWndProcW
;
534 Ret
= Window
->Class
->Atom
;
544 NtUserGetClassLong(HWND hWnd
, DWORD Offset
, BOOL Ansi
)
546 PWINDOW_OBJECT Window
;
547 DECLARE_RETURN(DWORD
);
549 DPRINT("Enter NtUserGetClassLong\n");
550 UserEnterExclusive();
552 if (!(Window
= UserGetWindowObject(hWnd
)))
557 RETURN(IntGetClassLong(Window
, Offset
, Ansi
));
560 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_
);
566 co_IntSetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, LONG dwNewLong
, BOOL Ansi
)
568 ASSERT_REFS_CO(Window
);
570 if ((int)Offset
>= 0)
572 DPRINT("SetClassLong(%x, %d, %x)\n", Window
->hSelf
, Offset
, dwNewLong
);
573 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
575 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
578 *((LONG
*)(Window
->Class
->ExtraData
+ Offset
)) = dwNewLong
;
585 Window
->Class
->cbWndExtra
= dwNewLong
;
588 Window
->Class
->cbClsExtra
= dwNewLong
;
590 case GCL_HBRBACKGROUND
:
591 Window
->Class
->hbrBackground
= (HBRUSH
)dwNewLong
;
594 Window
->Class
->hCursor
= (HCURSOR
)dwNewLong
;
597 Window
->Class
->hIcon
= (HICON
)dwNewLong
;
599 if (!IntGetOwner(Window
) && !IntGetParent(Window
))
601 co_IntShellHookNotify(HSHELL_REDRAW
, (LPARAM
) Window
->hSelf
);
605 Window
->Class
->hIconSm
= (HICON
)dwNewLong
;
608 Window
->Class
->hInstance
= (HINSTANCE
)dwNewLong
;
611 if (Window
->Class
->lpszMenuName
.MaximumLength
)
612 RtlFreeUnicodeString(&Window
->Class
->lpszMenuName
);
613 if (!IS_INTRESOURCE(dwNewLong
))
615 Window
->Class
->lpszMenuName
.Length
=
616 Window
->Class
->lpszMenuName
.MaximumLength
= ((PUNICODE_STRING
)dwNewLong
)->MaximumLength
;
617 Window
->Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Window
->Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
618 RtlCopyUnicodeString(&Window
->Class
->lpszMenuName
, (PUNICODE_STRING
)dwNewLong
);
622 Window
->Class
->lpszMenuName
.Length
=
623 Window
->Class
->lpszMenuName
.MaximumLength
= 0;
624 Window
->Class
->lpszMenuName
.Buffer
= (LPWSTR
)dwNewLong
;
628 Window
->Class
->style
= dwNewLong
;
633 Window
->Class
->lpfnWndProcA
= (WNDPROC
)dwNewLong
;
634 Window
->Class
->lpfnWndProcW
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,FALSE
);
635 Window
->Class
->Unicode
= FALSE
;
639 Window
->Class
->lpfnWndProcW
= (WNDPROC
)dwNewLong
;
640 Window
->Class
->lpfnWndProcA
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,TRUE
);
641 Window
->Class
->Unicode
= TRUE
;
648 NtUserSetClassLong(HWND hWnd
,
653 PWINDOW_OBJECT Window
;
655 DECLARE_RETURN(DWORD
);
657 DPRINT("Enter NtUserSetClassLong\n");
658 UserEnterExclusive();
660 if (!(Window
= UserGetWindowObject(hWnd
)))
665 UserRefObjectCo(Window
);
667 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
668 co_IntSetClassLong(Window
, Offset
, dwNewLong
, Ansi
);
670 UserDerefObjectCo(Window
);
675 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_
);
681 NtUserSetClassWord(DWORD Unknown0
,
690 NtUserUnregisterClass(
691 LPCWSTR ClassNameOrAtom
,
695 PWNDCLASS_OBJECT Class
;
696 PWINSTATION_OBJECT WinSta
;
697 DECLARE_RETURN(BOOL
);
699 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom
);
700 UserEnterExclusive();
702 if (!ClassNameOrAtom
|| !PsGetWin32Thread()->Desktop
)
704 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
708 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
710 if (!ClassReferenceClassByNameOrAtom(&Class
, ClassNameOrAtom
, hInstance
))
712 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
716 if (Class
->hInstance
&& Class
->hInstance
!= hInstance
)
718 ClassDereferenceObject(Class
);
719 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
723 if (!IsListEmpty(&Class
->ClassWindowsListHead
))
725 /* Dereference the ClassReferenceClassByNameOrAtom() call */
726 ObmDereferenceObject(Class
);
727 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
731 /* Dereference the ClassReferenceClassByNameOrAtom() call */
732 ClassDereferenceObject(Class
);
734 RemoveEntryList(&Class
->ListEntry
);
736 RtlDeleteAtomFromAtomTable(WinSta
->AtomTable
, Class
->Atom
);
738 /* Free the object */
739 ClassDereferenceObject(Class
);
744 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_
);