Repairs to WNDPROC and class handling by Jonathan Wilson
[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.27 2003/08/11 10:30:19 gvg 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
41 #define NDEBUG
42 #include <debug.h>
43
44 /* FUNCTIONS *****************************************************************/
45
46 NTSTATUS FASTCALL
47 InitClassImpl(VOID)
48 {
49 return(STATUS_SUCCESS);
50 }
51
52 NTSTATUS FASTCALL
53 CleanupClassImpl(VOID)
54 {
55 return(STATUS_SUCCESS);
56 }
57
58
59 NTSTATUS FASTCALL
60 ClassReferenceClassByAtom(PWNDCLASS_OBJECT* Class,
61 RTL_ATOM Atom)
62 {
63 PWNDCLASS_OBJECT Current;
64 PLIST_ENTRY CurrentEntry;
65 PW32PROCESS Process = PsGetWin32Process();
66
67 ExAcquireFastMutexUnsafe (&Process->ClassListLock);
68 CurrentEntry = Process->ClassListHead.Flink;
69 while (CurrentEntry != &Process->ClassListHead)
70 {
71 Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry);
72
73 if (Current->lpszClassName == (PUNICODE_STRING)(ULONG)Atom)
74 {
75 *Class = Current;
76 ObmReferenceObject(Current);
77 ExReleaseFastMutexUnsafe (&Process->ClassListLock);
78 return(STATUS_SUCCESS);
79 }
80
81 CurrentEntry = CurrentEntry->Flink;
82 }
83 ExReleaseFastMutexUnsafe (&Process->ClassListLock);
84
85 return(STATUS_NOT_FOUND);
86 }
87
88 NTSTATUS STDCALL
89 ClassReferenceClassByName(PWNDCLASS_OBJECT *Class,
90 PWSTR ClassName)
91 {
92 PWINSTATION_OBJECT WinStaObject;
93 NTSTATUS Status;
94 RTL_ATOM ClassAtom;
95
96 if (!ClassName)
97 {
98 return(STATUS_INVALID_PARAMETER);
99 }
100
101 Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
102 KernelMode,
103 0,
104 &WinStaObject);
105 if (!NT_SUCCESS(Status))
106 {
107 DPRINT("Validation of window station handle (0x%X) failed\n",
108 PROCESS_WINDOW_STATION());
109 return(STATUS_UNSUCCESSFUL);
110 }
111
112 Status = RtlLookupAtomInAtomTable(WinStaObject->AtomTable,
113 ClassName,
114 &ClassAtom);
115
116 if (!NT_SUCCESS(Status))
117 {
118 ObDereferenceObject(WinStaObject);
119 return(Status);
120 }
121 Status = ClassReferenceClassByAtom(Class,
122 ClassAtom);
123
124 ObDereferenceObject(WinStaObject);
125 return(Status);
126 }
127
128 NTSTATUS FASTCALL
129 ClassReferenceClassByNameOrAtom(PWNDCLASS_OBJECT *Class,
130 LPWSTR ClassNameOrAtom)
131 {
132 NTSTATUS Status;
133
134 if (IS_ATOM(ClassNameOrAtom))
135 {
136 Status = ClassReferenceClassByAtom(Class,
137 (RTL_ATOM)((ULONG_PTR)ClassNameOrAtom));
138 }
139 else
140 {
141 Status = ClassReferenceClassByName(Class,
142 ClassNameOrAtom);
143 }
144
145 if (!NT_SUCCESS(Status))
146 {
147 SetLastNtError(Status);
148 }
149
150 return(Status);
151 }
152
153 DWORD STDCALL
154 NtUserGetClassInfo(HINSTANCE hInst,
155 LPCWSTR str,
156 LPWNDCLASSEXW wcex,
157 BOOL Ansi,
158 DWORD unknown3)
159 {
160 PWNDCLASS_OBJECT Class;
161 NTSTATUS Status;
162 Status = ClassReferenceClassByNameOrAtom(&Class,(LPWSTR)str);
163 if (!NT_SUCCESS(Status))
164 {
165 SetLastNtError(Status);
166 return 0;
167 }
168 wcex->cbSize = sizeof(LPWNDCLASSEXW);
169 wcex->style = Class->style;
170 if (Ansi)
171 {
172 wcex->lpfnWndProc = Class->lpfnWndProcA;
173 }
174 else
175 {
176 wcex->lpfnWndProc = Class->lpfnWndProcW;
177 }
178 wcex->cbClsExtra = Class->cbClsExtra;
179 wcex->cbWndExtra = Class->cbWndExtra;
180 wcex->hInstance = Class->hInstance;
181 wcex->hIcon = Class->hIcon;
182 wcex->hCursor = Class->hCursor;
183 wcex->hbrBackground = Class->hbrBackground;
184 wcex->lpszMenuName = (LPCWSTR)Class->lpszMenuName;
185 wcex->lpszClassName = (LPCWSTR)Class->lpszClassName;
186 wcex->hIconSm = Class->hIconSm;
187 return 1;
188 }
189
190 ULONG FASTCALL
191 W32kGetClassName(struct _WINDOW_OBJECT *WindowObject,
192 LPWSTR lpClassName,
193 int nMaxCount)
194 {
195 ULONG length;
196 LPWSTR name;
197 BOOL free;
198 PWINSTATION_OBJECT WinStaObject;
199 NTSTATUS Status;
200 if (IS_ATOM(WindowObject->Class->lpszClassName))
201 {
202 DPRINT("About to open window station handle (0x%X)\n",
203 PROCESS_WINDOW_STATION());
204 Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
205 KernelMode,
206 0,
207 &WinStaObject);
208 if (!NT_SUCCESS(Status))
209 {
210 DPRINT("Validation of window station handle (0x%X) failed\n",
211 PROCESS_WINDOW_STATION());
212 return((RTL_ATOM)0);
213 }
214 length = 0;
215 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,(RTL_ATOM)WindowObject->Class->lpszClassName,NULL,NULL,name,&length);
216 name = ExAllocatePool(PagedPool,length+1);
217 free = TRUE;
218 Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,(RTL_ATOM)WindowObject->Class->lpszClassName,NULL,NULL,name,&length);
219 if (!NT_SUCCESS(Status))
220 {
221 DPRINT("Validation of window station handle (0x%X) failed\n",
222 PROCESS_WINDOW_STATION());
223 return((RTL_ATOM)0);
224 }
225 ObDereferenceObject(WinStaObject);
226 }
227 else
228 {
229 name = WindowObject->Class->lpszClassName->Buffer;
230 length = WindowObject->Class->lpszClassName->Length / sizeof(WCHAR);
231 free = FALSE;
232 }
233 if (length > nMaxCount)
234 {
235 length = nMaxCount;
236 }
237 *(lpClassName+length) = 0;
238 wcsncpy(lpClassName,name,length);
239 if (free)
240 {
241 ExFreePool(name);
242 }
243 return length;
244 }
245
246 DWORD STDCALL
247 NtUserGetClassName (
248 HWND hWnd,
249 LPWSTR lpClassName,
250 int nMaxCount)
251 {
252 PWINDOW_OBJECT WindowObject;
253 LONG Ret;
254
255 WindowObject = W32kGetWindowObject(hWnd);
256 if (WindowObject == NULL)
257 {
258 return(0);
259 }
260 Ret = W32kGetClassName(WindowObject, lpClassName, nMaxCount);
261 W32kReleaseWindowObject(WindowObject);
262 return(Ret);
263 }
264
265 DWORD STDCALL
266 NtUserGetWOWClass(DWORD Unknown0,
267 DWORD Unknown1)
268 {
269 UNIMPLEMENTED;
270 return(0);
271 }
272
273 PWNDCLASS_OBJECT FASTCALL
274 W32kCreateClass(CONST WNDCLASSEXW *lpwcx,
275 BOOL bUnicodeClass,
276 RTL_ATOM Atom)
277 {
278 PWNDCLASS_OBJECT ClassObject;
279 WORD objectSize;
280 objectSize = sizeof(WNDCLASS_OBJECT);
281 ClassObject = ObmCreateObject(NULL, NULL, otClass, objectSize);
282 if (ClassObject == 0)
283 {
284 return(NULL);
285 }
286
287 ClassObject->cbSize = lpwcx->cbSize;
288 ClassObject->style = lpwcx->style;
289 ClassObject->cbClsExtra = lpwcx->cbClsExtra;
290 ClassObject->cbWndExtra = lpwcx->cbWndExtra;
291 ClassObject->hInstance = lpwcx->hInstance;
292 ClassObject->hIcon = lpwcx->hIcon;
293 ClassObject->hCursor = lpwcx->hCursor;
294 ClassObject->hbrBackground = lpwcx->hbrBackground;
295 ClassObject->Unicode = bUnicodeClass;
296 ClassObject->hIconSm = lpwcx->hIconSm;
297 ClassObject->lpszClassName = (PUNICODE_STRING)(ULONG)Atom;
298 if (bUnicodeClass)
299 {
300 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
301 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc+0x80000000;
302 }
303 else
304 {
305 ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
306 ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc+0x80000000;
307 }
308 if (IS_INTRESOURCE(lpwcx->lpszMenuName))
309 {
310 ClassObject->lpszMenuName = (PUNICODE_STRING)lpwcx->lpszMenuName;
311 }
312 else
313 {
314 ClassObject->lpszMenuName = ExAllocatePool(NonPagedPool,sizeof(UNICODE_STRING));
315 RtlCreateUnicodeString(ClassObject->lpszMenuName,(LPWSTR)lpwcx->lpszMenuName);
316 }
317 return(ClassObject);
318 }
319
320 RTL_ATOM STDCALL
321 NtUserRegisterClassExWOW(
322 CONST WNDCLASSEXW *lpwcx,
323 BOOL bUnicodeClass,
324 DWORD Unknown3,
325 DWORD Unknown4,
326 DWORD Unknown5)
327
328 /*
329 * FUNCTION:
330 * Registers a new class with the window manager
331 * ARGUMENTS:
332 * lpwcx = Win32 extended window class structure
333 * bUnicodeClass = Whether to send ANSI or unicode strings
334 * to window procedures
335 * RETURNS:
336 * Atom identifying the new class
337 */
338 {
339 PWINSTATION_OBJECT WinStaObject;
340 PWNDCLASS_OBJECT ClassObject;
341 NTSTATUS Status;
342 RTL_ATOM Atom;
343 DPRINT("About to open window station handle (0x%X)\n",
344 PROCESS_WINDOW_STATION());
345 Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
346 KernelMode,
347 0,
348 &WinStaObject);
349 if (!NT_SUCCESS(Status))
350 {
351 DPRINT("Validation of window station handle (0x%X) failed\n",
352 PROCESS_WINDOW_STATION());
353 return((RTL_ATOM)0);
354 }
355 if (!IS_ATOM(lpwcx->lpszClassName))
356 {
357 Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable,
358 (LPWSTR)lpwcx->lpszClassName,
359 &Atom);
360 if (!NT_SUCCESS(Status))
361 {
362 ObDereferenceObject(WinStaObject);
363 DPRINT("Failed adding class name (%wS) to atom table\n",
364 lpwcx->lpszClassName);
365 SetLastNtError(Status);
366 return((RTL_ATOM)0);
367 }
368 }
369 else
370 {
371 Atom = (RTL_ATOM)(ULONG)lpwcx->lpszClassName;
372 }
373 ClassObject = W32kCreateClass(lpwcx, bUnicodeClass, Atom);
374 if (ClassObject == NULL)
375 {
376 if (!IS_ATOM(lpwcx->lpszClassName))
377 {
378 RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Atom);
379 }
380 ObDereferenceObject(WinStaObject);
381 DPRINT("Failed creating window class object\n");
382 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
383 return((RTL_ATOM)0);
384 }
385 ExAcquireFastMutex(&PsGetWin32Process()->ClassListLock);
386 InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry);
387 ExReleaseFastMutex(&PsGetWin32Process()->ClassListLock);
388 ObDereferenceObject(WinStaObject);
389 return(Atom);
390 }
391
392 ULONG FASTCALL
393 W32kGetClassLong(struct _WINDOW_OBJECT *WindowObject, ULONG Offset, BOOL Ansi)
394 {
395 LONG Ret;
396 switch (Offset)
397 {
398 case GCL_CBWNDEXTRA:
399 Ret = WindowObject->Class->cbWndExtra;
400 break;
401 case GCL_CBCLSEXTRA:
402 Ret = WindowObject->Class->cbClsExtra;
403 break;
404 case GCL_HBRBACKGROUND:
405 Ret = (ULONG)WindowObject->Class->hbrBackground;
406 break;
407 case GCL_HCURSOR:
408 Ret = (ULONG)WindowObject->Class->hCursor;
409 break;
410 case GCL_HICON:
411 Ret = (ULONG)WindowObject->Class->hIcon;
412 break;
413 case GCL_HICONSM:
414 Ret = (ULONG)WindowObject->Class->hIconSm;
415 break;
416 case GCL_HMODULE:
417 Ret = (ULONG)WindowObject->Class->hInstance;
418 break;
419 case GCL_MENUNAME:
420 Ret = (ULONG)WindowObject->Class->lpszMenuName;
421 break;
422 case GCL_STYLE:
423 Ret = WindowObject->Class->style;
424 break;
425 case GCL_WNDPROC:
426 if (Ansi)
427 {
428 Ret = (ULONG)WindowObject->Class->lpfnWndProcA;
429 }
430 else
431 {
432 Ret = (ULONG)WindowObject->Class->lpfnWndProcW;
433 }
434 break;
435 default:
436 Ret = 0;
437 break;
438 }
439 return(Ret);
440 }
441
442 DWORD STDCALL
443 NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
444 {
445 PWINDOW_OBJECT WindowObject;
446 LONG Ret;
447
448 WindowObject = W32kGetWindowObject(hWnd);
449 if (WindowObject == NULL)
450 {
451 return(0);
452 }
453 Ret = W32kGetClassLong(WindowObject, Offset, Ansi);
454 W32kReleaseWindowObject(WindowObject);
455 return(Ret);
456 }
457
458 void FASTCALL
459 W32kSetClassLong(PWINDOW_OBJECT WindowObject, ULONG Offset, LONG dwNewLong, BOOL Ansi)
460 {
461 PUNICODE_STRING str;
462 switch (Offset)
463 {
464 case GCL_CBWNDEXTRA:
465 WindowObject->Class->cbWndExtra = dwNewLong;
466 break;
467 case GCL_CBCLSEXTRA:
468 WindowObject->Class->cbClsExtra = dwNewLong;
469 break;
470 case GCL_HBRBACKGROUND:
471 WindowObject->Class->hbrBackground = (HBRUSH)dwNewLong;
472 break;
473 case GCL_HCURSOR:
474 WindowObject->Class->hCursor = (HCURSOR)dwNewLong;
475 break;
476 case GCL_HICON:
477 WindowObject->Class->hIcon = (HICON)dwNewLong;
478 break;
479 case GCL_HICONSM:
480 WindowObject->Class->hIconSm = (HICON)dwNewLong;
481 break;
482 case GCL_HMODULE:
483 WindowObject->Class->hInstance = (HINSTANCE)dwNewLong;
484 break;
485 case GCL_MENUNAME:
486 if (!IS_INTRESOURCE(dwNewLong))
487 {
488 str = ExAllocatePool(PagedPool,sizeof(UNICODE_STRING)+((PUNICODE_STRING)dwNewLong)->Length);
489 memcpy(str,(PUNICODE_STRING)dwNewLong,sizeof(UNICODE_STRING)+((PUNICODE_STRING)dwNewLong)->Length);
490 WindowObject->Class->lpszMenuName = str;
491 }
492 else
493 {
494 WindowObject->Class->lpszMenuName = (PUNICODE_STRING)dwNewLong;
495 }
496 break;
497 case GCL_STYLE:
498 WindowObject->Class->style = dwNewLong;
499 break;
500 case GCL_WNDPROC:
501 if (Ansi)
502 {
503 WindowObject->Class->lpfnWndProcA = (WNDPROC)dwNewLong;
504 WindowObject->Class->lpfnWndProcW = (WNDPROC)dwNewLong+0x80000000;
505 }
506 else
507 {
508 WindowObject->Class->lpfnWndProcW = (WNDPROC)dwNewLong;
509 WindowObject->Class->lpfnWndProcA = (WNDPROC)dwNewLong+0x80000000;
510 }
511 break;
512 }
513 }
514
515 DWORD STDCALL
516 NtUserSetClassLong(HWND hWnd,
517 DWORD Offset,
518 LONG dwNewLong,
519 BOOL Ansi)
520 {
521 PWINDOW_OBJECT WindowObject;
522 LONG Ret;
523
524 WindowObject = W32kGetWindowObject(hWnd);
525 if (WindowObject == NULL)
526 {
527 return(0);
528 }
529 Ret = W32kGetClassLong(WindowObject, Offset, Ansi);
530 W32kSetClassLong(WindowObject, Offset, dwNewLong, Ansi);
531 W32kReleaseWindowObject(WindowObject);
532 return(Ret);
533 }
534
535 DWORD STDCALL
536 NtUserSetClassWord(DWORD Unknown0,
537 DWORD Unknown1,
538 DWORD Unknown2)
539 {
540 UNIMPLEMENTED;
541 return(0);
542 }
543
544 DWORD STDCALL
545 NtUserUnregisterClass(DWORD Unknown0,
546 DWORD Unknown1,
547 DWORD Unknown2)
548 {
549 UNIMPLEMENTED;
550 return(0);
551 }
552
553 /* EOF */