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 WindowObject
;
240 DECLARE_RETURN(DWORD
);
244 WindowObject
= IntGetWindowObject(hWnd
);
245 if (WindowObject
== NULL
)
247 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
250 Length
= IntGetClassName(WindowObject
, lpClassName
, nMaxCount
);
251 IntReleaseWindowObject(WindowObject
);
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(NULL
, 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
;
321 if (wpExtra
== NULL
) {
322 if (Flags
& REGISTERCLASS_ANSI
)
324 ClassObject
->lpfnWndProcA
= lpwcx
->lpfnWndProc
;
325 ClassObject
->lpfnWndProcW
= (WNDPROC
)IntAddWndProcHandle(lpwcx
->lpfnWndProc
,FALSE
);
329 ClassObject
->lpfnWndProcW
= lpwcx
->lpfnWndProc
;
330 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
;
538 NtUserGetClassLong(HWND hWnd
, DWORD Offset
, BOOL Ansi
)
540 PWINDOW_OBJECT Window
;
542 DECLARE_RETURN(DWORD
);
544 DPRINT("Enter NtUserGetClassLong\n");
545 UserEnterExclusive();
547 Window
= IntGetWindowObject(hWnd
);
550 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
553 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
554 IntReleaseWindowObject(Window
);
558 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_
);
564 co_IntSetClassLong(PWINDOW_OBJECT Window
, ULONG Offset
, LONG dwNewLong
, BOOL Ansi
)
566 PWINDOW_OBJECT Parent
, Owner
;
568 if ((int)Offset
>= 0)
570 DPRINT("SetClassLong(%x, %d, %x)\n", Window
->hSelf
, Offset
, dwNewLong
);
571 if ((Offset
+ sizeof(LONG
)) > Window
->Class
->cbClsExtra
)
573 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
576 *((LONG
*)(Window
->Class
->ExtraData
+ Offset
)) = dwNewLong
;
583 Window
->Class
->cbWndExtra
= dwNewLong
;
586 Window
->Class
->cbClsExtra
= dwNewLong
;
588 case GCL_HBRBACKGROUND
:
589 Window
->Class
->hbrBackground
= (HBRUSH
)dwNewLong
;
592 Window
->Class
->hCursor
= (HCURSOR
)dwNewLong
;
595 Window
->Class
->hIcon
= (HICON
)dwNewLong
;
596 Owner
= IntGetOwner(Window
);
597 Parent
= IntGetParent(Window
);
599 if ((!Owner
) && (!Parent
))
601 co_IntShellHookNotify(HSHELL_REDRAW
, (LPARAM
) Window
->hSelf
);
606 IntReleaseWindowObject(Parent
);
611 IntReleaseWindowObject(Owner
);
617 Window
->Class
->hIconSm
= (HICON
)dwNewLong
;
620 Window
->Class
->hInstance
= (HINSTANCE
)dwNewLong
;
623 if (Window
->Class
->lpszMenuName
.MaximumLength
)
624 RtlFreeUnicodeString(&Window
->Class
->lpszMenuName
);
625 if (!IS_INTRESOURCE(dwNewLong
))
627 Window
->Class
->lpszMenuName
.Length
=
628 Window
->Class
->lpszMenuName
.MaximumLength
= ((PUNICODE_STRING
)dwNewLong
)->MaximumLength
;
629 Window
->Class
->lpszMenuName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, Window
->Class
->lpszMenuName
.MaximumLength
, TAG_STRING
);
630 RtlCopyUnicodeString(&Window
->Class
->lpszMenuName
, (PUNICODE_STRING
)dwNewLong
);
634 Window
->Class
->lpszMenuName
.Length
=
635 Window
->Class
->lpszMenuName
.MaximumLength
= 0;
636 Window
->Class
->lpszMenuName
.Buffer
= (LPWSTR
)dwNewLong
;
640 Window
->Class
->style
= dwNewLong
;
645 Window
->Class
->lpfnWndProcA
= (WNDPROC
)dwNewLong
;
646 Window
->Class
->lpfnWndProcW
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,FALSE
);
647 Window
->Class
->Unicode
= FALSE
;
651 Window
->Class
->lpfnWndProcW
= (WNDPROC
)dwNewLong
;
652 Window
->Class
->lpfnWndProcA
= (WNDPROC
) IntAddWndProcHandle((WNDPROC
)dwNewLong
,TRUE
);
653 Window
->Class
->Unicode
= TRUE
;
660 NtUserSetClassLong(HWND hWnd
,
665 PWINDOW_OBJECT Window
;
667 DECLARE_RETURN(DWORD
);
669 DPRINT("Enter NtUserSetClassLong\n");
670 UserEnterExclusive();
672 if (!(Window
= IntGetWindowObject(hWnd
)))
674 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
677 Ret
= IntGetClassLong(Window
, Offset
, Ansi
);
678 co_IntSetClassLong(Window
, Offset
, dwNewLong
, Ansi
);
679 IntReleaseWindowObject(Window
);
683 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_
);
689 NtUserSetClassWord(DWORD Unknown0
,
698 NtUserUnregisterClass(
699 LPCWSTR ClassNameOrAtom
,
703 PWNDCLASS_OBJECT Class
;
704 PWINSTATION_OBJECT WinSta
;
705 DECLARE_RETURN(BOOL
);
707 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom
);
708 UserEnterExclusive();
710 if (!ClassNameOrAtom
|| !PsGetWin32Thread()->Desktop
)
712 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
716 WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
718 if (!ClassReferenceClassByNameOrAtom(&Class
, ClassNameOrAtom
, hInstance
))
720 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
724 if (Class
->hInstance
&& Class
->hInstance
!= hInstance
)
726 ClassDereferenceObject(Class
);
727 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST
);
731 if (!IsListEmpty(&Class
->ClassWindowsListHead
))
733 /* Dereference the ClassReferenceClassByNameOrAtom() call */
734 ObmDereferenceObject(Class
);
735 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS
);
739 /* Dereference the ClassReferenceClassByNameOrAtom() call */
740 ClassDereferenceObject(Class
);
742 RemoveEntryList(&Class
->ListEntry
);
744 RtlDeleteAtomFromAtomTable(WinSta
->AtomTable
, Class
->Atom
);
746 /* Free the object */
747 ClassDereferenceObject(Class
);
752 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_
);