- Added test for unimplemented EnumWindowStations and EnumDesktops functions.
[reactos.git] / reactos / subsys / win32k / ntuser / class.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: class.c,v 1.40 2003/11/23 11:39:48 navaraf Exp $
20 *
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)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <napi/win32.h>
34 #include <include/class.h>
35 #include <include/error.h>
36 #include <include/winsta.h>
37 #include <include/object.h>
38 #include <include/guicheck.h>
39 #include <include/window.h>
40 #include <include/color.h>
41
42 #define NDEBUG
43 #include <debug.h>
44
45 /* FUNCTIONS *****************************************************************/
46
47 NTSTATUS FASTCALL
48 InitClassImpl(VOID)
49 {
50 return(STATUS_SUCCESS);
51 }
52
53 NTSTATUS FASTCALL
54 CleanupClassImpl(VOID)
55 {
56 return(STATUS_SUCCESS);
57 }
58
59
60 NTSTATUS FASTCALL
61 ClassReferenceClassByAtom(PWNDCLASS_OBJECT* Class,
62 RTL_ATOM Atom)
63 {
64 PWNDCLASS_OBJECT Current;
65 PLIST_ENTRY CurrentEntry;
66 PW32PROCESS Process = PsGetWin32Process();
67
68 ExAcquireFastMutexUnsafe (&Process->ClassListLock);
69 CurrentEntry = Process->ClassListHead.Flink;
70 while (CurrentEntry != &Process->ClassListHead)
71 {
72 Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry);
73
74 if (Current->lpszClassName == (PUNICODE_STRING)(ULONG)Atom)
75 {
76 *Class = Current;
77 ObmReferenceObject(Current);
78 ExReleaseFastMutexUnsafe (&Process->ClassListLock);
79 return(STATUS_SUCCESS);
80 }
81
82 CurrentEntry = CurrentEntry->Flink;
83 }
84 ExReleaseFastMutexUnsafe (&Process->ClassListLock);
85
86 return(STATUS_NOT_FOUND);
87 }
88
89 NTSTATUS STDCALL
90 ClassReferenceClassByName(PWNDCLASS_OBJECT *Class,
91 PWSTR ClassName)
92 {
93 PWINSTATION_OBJECT WinStaObject;
94 NTSTATUS Status;
95 RTL_ATOM ClassAtom;
96
97 if (!ClassName)
98 {
99 return(STATUS_INVALID_PARAMETER);
100 }
101
102 Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
103 KernelMode,
104 0,
105 &WinStaObject);
106 if (!NT_SUCCESS(Status))
107 {
108 DPRINT("Validation of window station handle (0x%X) failed\n",
109 PROCESS_WINDOW_STATION());
110 return(STATUS_UNSUCCESSFUL);
111 }
112
113 Status = RtlLookupAtomInAtomTable(WinStaObject->AtomTable,
114 ClassName,
115 &ClassAtom);
116
117 if (!NT_SUCCESS(Status))
118 {
119 ObDereferenceObject(WinStaObject);
120 return(Status);
121 }
122 Status = ClassReferenceClassByAtom(Class,
123 ClassAtom);
124
125 ObDereferenceObject(WinStaObject);
126 return(Status);
127 }
128
129 NTSTATUS FASTCALL
130 ClassReferenceClassByNameOrAtom(PWNDCLASS_OBJECT *Class,
131 LPWSTR ClassNameOrAtom)
132 {
133 NTSTATUS Status;
134
135 if (IS_ATOM(ClassNameOrAtom))
136 {
137 Status = ClassReferenceClassByAtom(Class,
138 (RTL_ATOM)((ULONG_PTR)ClassNameOrAtom));
139 }
140 else
141 {
142 Status = ClassReferenceClassByName(Class,
143 ClassNameOrAtom);
144 }
145
146 if (!NT_SUCCESS(Status))
147 {
148 SetLastNtError(Status);
149 }
150
151 return(Status);
152 }
153
154 DWORD STDCALL
155 NtUserGetClassInfo(HINSTANCE hInst,
156 LPCWSTR str,
157 LPWNDCLASSEXW wcex,
158 BOOL Ansi,
159 DWORD unknown3)
160 {
161 PWNDCLASS_OBJECT Class;
162 NTSTATUS Status;
163 Status = ClassReferenceClassByNameOrAtom(&Class,(LPWSTR)str);
164 if (!NT_SUCCESS(Status))
165 {
166 SetLastNtError(Status);
167 return 0;
168 }
169 wcex->cbSize = sizeof(LPWNDCLASSEXW);
170 wcex->style = Class->style;
171 if (Ansi)
172 {
173 wcex->lpfnWndProc = Class->lpfnWndProcA;
174 }
175 else
176 {
177 wcex->lpfnWndProc = Class->lpfnWndProcW;
178 }
179 wcex->cbClsExtra = Class->cbClsExtra;
180 wcex->cbWndExtra = Class->cbWndExtra;
181 wcex->hInstance = Class->hInstance;
182 wcex->hIcon = Class->hIcon;
183 wcex->hCursor = Class->hCursor;
184 wcex->hbrBackground = Class->hbrBackground;
185 if(Class->lpszMenuName)
186 {
187 if(!IS_INTRESOURCE((LPCWSTR)Class->lpszMenuName))
188 RtlCopyUnicodeString((PUNICODE_STRING)wcex->lpszMenuName, Class->lpszMenuName);
189 else
190 wcex->lpszMenuName = (LPCWSTR)Class->lpszMenuName;
191 }
192 else
193 wcex->lpszMenuName = (LPCWSTR)NULL;
194 if(Class->lpszClassName)
195 {
196 if(!IS_ATOM((LPCWSTR)Class->lpszClassName))
197 RtlCopyUnicodeString((PUNICODE_STRING)wcex->lpszClassName, Class->lpszClassName);
198 else
199 wcex->lpszClassName = (LPCWSTR)Class->lpszClassName;
200 }
201 else
202 wcex->lpszClassName = (LPCWSTR)NULL;
203 wcex->hIconSm = Class->hIconSm;
204 return 1;
205 }
206
207 ULONG FASTCALL
208 IntGetClassName(struct _WINDOW_OBJECT *WindowObject,
209 LPWSTR lpClassName,
210 ULONG nMaxCount)
211 {
212 ULONG length;
213 LPWSTR name;
214 BOOL free;
215 PWINSTATION_OBJECT WinStaObject;
216 NTSTATUS Status;
217 if (IS_ATOM(WindowObject->Class->lpszClassName))
218 {
219 DPRINT("About to open window station handle (0x%X)\n",
220 PROCESS_WINDOW_STATION());
221 Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
222 KernelMode,
223 0,
224 &WinStaObject);
225 if (!NT_SUCCESS(Status))
226 {
227 DPRINT("Validation of window station handle (0x%X) failed\n",
228 PROCESS_WINDOW_STATION());
229 return((RTL_ATOM)0);
230 }
231 length = 0;
232 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,(RTL_ATOM)(size_t)WindowObject->Class->lpszClassName,NULL,NULL,name,&length);
233 name = ExAllocatePool(PagedPool,length+sizeof(WCHAR));
234 free = TRUE;
235 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,(RTL_ATOM)(size_t)WindowObject->Class->lpszClassName,NULL,NULL,name,&length);
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT("Validation of window station handle (0x%X) failed\n",
239 PROCESS_WINDOW_STATION());
240 return((RTL_ATOM)0);
241 }
242 ObDereferenceObject(WinStaObject);
243 }
244 else
245 {
246 name = WindowObject->Class->lpszClassName->Buffer;
247 length = WindowObject->Class->lpszClassName->Length / sizeof(WCHAR);
248 free = FALSE;
249 }
250 if (length > nMaxCount)
251 {
252 length = nMaxCount;
253 }
254 *(lpClassName+length) = 0;
255 wcsncpy(lpClassName,name,length);
256 if (free)
257 {
258 ExFreePool(name);
259 }
260 return length;
261 }
262
263 DWORD STDCALL
264 NtUserGetClassName (
265 HWND hWnd,
266 LPWSTR lpClassName,
267 ULONG nMaxCount)
268 {
269 PWINDOW_OBJECT WindowObject;
270 LONG Ret;
271
272 WindowObject = IntGetWindowObject(hWnd);
273 if (WindowObject == NULL)
274 {
275 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
276 return 0;
277 }
278 Ret = IntGetClassName(WindowObject, lpClassName, nMaxCount);
279 IntReleaseWindowObject(WindowObject);
280 return(Ret);
281 }
282
283 DWORD STDCALL
284 NtUserGetWOWClass(DWORD Unknown0,
285 DWORD Unknown1)
286 {
287 UNIMPLEMENTED;
288 return(0);
289 }
290
291 PWNDCLASS_OBJECT FASTCALL
292 IntCreateClass(CONST WNDCLASSEXW *lpwcx,
293 BOOL bUnicodeClass,
294 WNDPROC wpExtra,
295 RTL_ATOM Atom)
296 {
297 PWNDCLASS_OBJECT ClassObject;
298 WORD objectSize;
299 NTSTATUS Status;
300
301 /* Check for double registration of the class. */
302 if (PsGetWin32Process() != NULL)
303 {
304 Status = ClassReferenceClassByAtom(&ClassObject, Atom);
305 if (NT_SUCCESS(Status))
306 {
307 ObmDereferenceObject(ClassObject);
308 return(NULL);
309 }
310 }
311
312 objectSize = sizeof(WNDCLASS_OBJECT) + lpwcx->cbClsExtra;
313 ClassObject = ObmCreateObject(NULL, NULL, otClass, objectSize);
314 if (ClassObject == 0)
315 {
316 return(NULL);
317 }
318
319 ClassObject->cbSize = lpwcx->cbSize;
320 ClassObject->style = lpwcx->style;
321 ClassObject->cbClsExtra = lpwcx->cbClsExtra;
322 ClassObject->cbWndExtra = lpwcx->cbWndExtra;
323 ClassObject->hInstance = lpwcx->hInstance;
324 ClassObject->hIcon = lpwcx->hIcon;
325 ClassObject->hCursor = lpwcx->hCursor;
326 ClassObject->hbrBackground = lpwcx->hbrBackground;
327 ClassObject->Unicode = bUnicodeClass;
328 ClassObject->hIconSm = lpwcx->hIconSm;
329 ClassObject->lpszClassName = (PUNICODE_STRING)(ULONG)Atom;
330 if (wpExtra == 0) {
331 if (bUnicodeClass)
332 {
333 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
334 ClassObject->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
335 }
336 else
337 {
338 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
339 ClassObject->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
340 }
341 } else {
342 if (bUnicodeClass)
343 {
344 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
345 ClassObject->lpfnWndProcA = wpExtra;
346 }
347 else
348 {
349 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
350 ClassObject->lpfnWndProcW = wpExtra;
351 }
352 }
353 if (IS_INTRESOURCE(lpwcx->lpszMenuName))
354 {
355 ClassObject->lpszMenuName = (PUNICODE_STRING)lpwcx->lpszMenuName;
356 }
357 else
358 {
359 ClassObject->lpszMenuName = ExAllocatePool(NonPagedPool,sizeof(UNICODE_STRING));
360 RtlCreateUnicodeString(ClassObject->lpszMenuName,(LPWSTR)lpwcx->lpszMenuName);
361 }
362 /* Extra class data */
363 if (ClassObject->cbClsExtra != 0)
364 {
365 ClassObject->ExtraData = (PCHAR)(ClassObject + 1);
366 RtlZeroMemory(ClassObject->ExtraData, ClassObject->cbClsExtra);
367 }
368 else
369 {
370 ClassObject->ExtraData = NULL;
371 }
372
373 return(ClassObject);
374 }
375
376 RTL_ATOM STDCALL
377 NtUserRegisterClassExWOW(
378 CONST WNDCLASSEXW *lpwcx,
379 BOOL bUnicodeClass,
380 WNDPROC wpExtra,
381 DWORD Unknown4,
382 DWORD Unknown5)
383
384 /*
385 * FUNCTION:
386 * Registers a new class with the window manager
387 * ARGUMENTS:
388 * lpwcx = Win32 extended window class structure
389 * bUnicodeClass = Whether to send ANSI or unicode strings
390 * to window procedures
391 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
392 * RETURNS:
393 * Atom identifying the new class
394 */
395 {
396 PWINSTATION_OBJECT WinStaObject;
397 PWNDCLASS_OBJECT ClassObject;
398 NTSTATUS Status;
399 RTL_ATOM Atom;
400 DPRINT("About to open window station handle (0x%X)\n",
401 PROCESS_WINDOW_STATION());
402 Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
403 KernelMode,
404 0,
405 &WinStaObject);
406 if (!NT_SUCCESS(Status))
407 {
408 DPRINT("Validation of window station handle (0x%X) failed\n",
409 PROCESS_WINDOW_STATION());
410 return((RTL_ATOM)0);
411 }
412 if (!IS_ATOM(lpwcx->lpszClassName))
413 {
414 Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable,
415 (LPWSTR)lpwcx->lpszClassName,
416 &Atom);
417 if (!NT_SUCCESS(Status))
418 {
419 ObDereferenceObject(WinStaObject);
420 DPRINT("Failed adding class name (%wS) to atom table\n",
421 lpwcx->lpszClassName);
422 SetLastNtError(Status);
423 return((RTL_ATOM)0);
424 }
425 }
426 else
427 {
428 Atom = (RTL_ATOM)(ULONG)lpwcx->lpszClassName;
429 }
430 ClassObject = IntCreateClass(lpwcx, bUnicodeClass, wpExtra, Atom);
431 if (ClassObject == NULL)
432 {
433 if (!IS_ATOM(lpwcx->lpszClassName))
434 {
435 RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Atom);
436 }
437 ObDereferenceObject(WinStaObject);
438 DPRINT("Failed creating window class object\n");
439 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
440 return((RTL_ATOM)0);
441 }
442 ExAcquireFastMutex(&PsGetWin32Process()->ClassListLock);
443 InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry);
444 ExReleaseFastMutex(&PsGetWin32Process()->ClassListLock);
445 ObDereferenceObject(WinStaObject);
446 return(Atom);
447 }
448
449 ULONG FASTCALL
450 IntGetClassLong(struct _WINDOW_OBJECT *WindowObject, ULONG Offset, BOOL Ansi)
451 {
452 LONG Ret;
453
454 if ((int)Offset >= 0)
455 {
456 DbgPrint("GetClassLong(%x, %d)\n", WindowObject->Self, Offset);
457 if (Offset > WindowObject->Class->cbClsExtra - sizeof(LONG))
458 {
459 SetLastWin32Error(ERROR_INVALID_PARAMETER);
460 return 0;
461 }
462 Ret = *((LONG *)(WindowObject->Class->ExtraData + Offset));
463 DbgPrint("Result: %x\n", Ret);
464 return Ret;
465 }
466
467 switch (Offset)
468 {
469 case GCL_CBWNDEXTRA:
470 Ret = WindowObject->Class->cbWndExtra;
471 break;
472 case GCL_CBCLSEXTRA:
473 Ret = WindowObject->Class->cbClsExtra;
474 break;
475 case GCL_HBRBACKGROUND:
476 Ret = (ULONG)WindowObject->Class->hbrBackground;
477 if (Ret != 0 && Ret < 0x4000)
478 {
479 Ret = (ULONG)NtGdiGetSysColorBrush(Ret - 1);
480 }
481 break;
482 case GCL_HCURSOR:
483 Ret = (ULONG)WindowObject->Class->hCursor;
484 break;
485 case GCL_HICON:
486 Ret = (ULONG)WindowObject->Class->hIcon;
487 break;
488 case GCL_HICONSM:
489 Ret = (ULONG)WindowObject->Class->hIconSm;
490 break;
491 case GCL_HMODULE:
492 Ret = (ULONG)WindowObject->Class->hInstance;
493 break;
494 case GCL_MENUNAME:
495 Ret = (ULONG)WindowObject->Class->lpszMenuName;
496 break;
497 case GCL_STYLE:
498 Ret = WindowObject->Class->style;
499 break;
500 case GCL_WNDPROC:
501 if (Ansi)
502 {
503 Ret = (ULONG)WindowObject->Class->lpfnWndProcA;
504 }
505 else
506 {
507 Ret = (ULONG)WindowObject->Class->lpfnWndProcW;
508 }
509 break;
510 default:
511 Ret = 0;
512 break;
513 }
514 return(Ret);
515 }
516
517 DWORD STDCALL
518 NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
519 {
520 PWINDOW_OBJECT WindowObject;
521 LONG Ret;
522
523 WindowObject = IntGetWindowObject(hWnd);
524 if (WindowObject == NULL)
525 {
526 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
527 return 0;
528 }
529 Ret = IntGetClassLong(WindowObject, Offset, Ansi);
530 IntReleaseWindowObject(WindowObject);
531 return(Ret);
532 }
533
534 void FASTCALL
535 IntSetClassLong(PWINDOW_OBJECT WindowObject, ULONG Offset, LONG dwNewLong, BOOL Ansi)
536 {
537 PUNICODE_STRING str;
538
539 if ((int)Offset >= 0)
540 {
541 DbgPrint("SetClassLong(%x, %d, %x)\n", WindowObject->Self, Offset, dwNewLong);
542 if (Offset > WindowObject->Class->cbClsExtra - sizeof(LONG))
543 {
544 SetLastWin32Error(ERROR_INVALID_PARAMETER);
545 return;
546 }
547 *((LONG *)(WindowObject->Class->ExtraData + Offset)) = dwNewLong;
548 return;
549 }
550
551 switch (Offset)
552 {
553 case GCL_CBWNDEXTRA:
554 WindowObject->Class->cbWndExtra = dwNewLong;
555 break;
556 case GCL_CBCLSEXTRA:
557 WindowObject->Class->cbClsExtra = dwNewLong;
558 break;
559 case GCL_HBRBACKGROUND:
560 WindowObject->Class->hbrBackground = (HBRUSH)dwNewLong;
561 break;
562 case GCL_HCURSOR:
563 WindowObject->Class->hCursor = (HCURSOR)dwNewLong;
564 break;
565 case GCL_HICON:
566 WindowObject->Class->hIcon = (HICON)dwNewLong;
567 break;
568 case GCL_HICONSM:
569 WindowObject->Class->hIconSm = (HICON)dwNewLong;
570 break;
571 case GCL_HMODULE:
572 WindowObject->Class->hInstance = (HINSTANCE)dwNewLong;
573 break;
574 case GCL_MENUNAME:
575 if (!IS_INTRESOURCE(dwNewLong))
576 {
577 str = ExAllocatePool(PagedPool,sizeof(UNICODE_STRING)+((PUNICODE_STRING)dwNewLong)->Length);
578 memcpy(str,(PUNICODE_STRING)dwNewLong,sizeof(UNICODE_STRING)+((PUNICODE_STRING)dwNewLong)->Length);
579 WindowObject->Class->lpszMenuName = str;
580 }
581 else
582 {
583 WindowObject->Class->lpszMenuName = (PUNICODE_STRING)dwNewLong;
584 }
585 break;
586 case GCL_STYLE:
587 WindowObject->Class->style = dwNewLong;
588 break;
589 case GCL_WNDPROC:
590 if (Ansi)
591 {
592 WindowObject->Class->lpfnWndProcA = (WNDPROC)dwNewLong;
593 WindowObject->Class->lpfnWndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,FALSE);
594 WindowObject->Class->Unicode = FALSE;
595 }
596 else
597 {
598 WindowObject->Class->lpfnWndProcW = (WNDPROC)dwNewLong;
599 WindowObject->Class->lpfnWndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,TRUE);
600 WindowObject->Class->Unicode = TRUE;
601 }
602 break;
603 }
604 }
605
606 DWORD STDCALL
607 NtUserSetClassLong(HWND hWnd,
608 DWORD Offset,
609 LONG dwNewLong,
610 BOOL Ansi)
611 {
612 PWINDOW_OBJECT WindowObject;
613 LONG Ret;
614
615 WindowObject = IntGetWindowObject(hWnd);
616 if (WindowObject == NULL)
617 {
618 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
619 return 0;
620 }
621 Ret = IntGetClassLong(WindowObject, Offset, Ansi);
622 IntSetClassLong(WindowObject, Offset, dwNewLong, Ansi);
623 IntReleaseWindowObject(WindowObject);
624 return(Ret);
625 }
626
627 DWORD STDCALL
628 NtUserSetClassWord(DWORD Unknown0,
629 DWORD Unknown1,
630 DWORD Unknown2)
631 {
632 UNIMPLEMENTED;
633 return(0);
634 }
635
636 DWORD STDCALL
637 NtUserUnregisterClass(DWORD Unknown0,
638 DWORD Unknown1,
639 DWORD Unknown2)
640 {
641 UNIMPLEMENTED;
642 return(0);
643 }
644
645 /* EOF */