733916e85c11c4ea0b6663a22cd633abff0ada63
[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$
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 <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* FUNCTIONS *****************************************************************/
37
38 NTSTATUS FASTCALL
39 InitClassImpl(VOID)
40 {
41 return(STATUS_SUCCESS);
42 }
43
44 NTSTATUS FASTCALL
45 CleanupClassImpl(VOID)
46 {
47 return(STATUS_SUCCESS);
48 }
49
50
51 inline VOID FASTCALL
52 ClassDerefObject(PWNDCLASS_OBJECT Class)
53 {
54 ASSERT(Class->refs >= 1);
55 Class->refs--;
56 }
57
58
59 inline VOID FASTCALL
60 ClassRefObject(PWNDCLASS_OBJECT Class)
61 {
62 ASSERT(Class->refs >= 0);
63 Class->refs++;
64 }
65
66
67 VOID FASTCALL DestroyClass(PWNDCLASS_OBJECT Class)
68 {
69 ASSERT(Class->refs == 0);
70
71 RemoveEntryList(&Class->ListEntry);
72 RtlDeleteAtomFromAtomTable(gAtomTable, Class->Atom);
73 ExFreePool(Class);
74 }
75
76
77 /* clean all process classes. all process windows must cleaned first!! */
78 void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
79 {
80 PWNDCLASS_OBJECT Class;
81
82 while (!IsListEmpty(&Process->ClassList))
83 {
84 Class = CONTAINING_RECORD(RemoveHeadList(&Process->ClassList), WNDCLASS_OBJECT, ListEntry);
85 DestroyClass(Class);
86 }
87 }
88
89
90
91
92 PWNDCLASS_OBJECT FASTCALL
93 ClassGetClassByAtom(RTL_ATOM Atom, HINSTANCE hInstance)
94 {
95 PWNDCLASS_OBJECT Class;
96 PW32PROCESS Process = PsGetWin32Process();
97
98 LIST_FOR_EACH(Class, &Process->ClassList, WNDCLASS_OBJECT, ListEntry)
99 {
100 if (Class->Atom != Atom) continue;
101
102 if (!hInstance || Class->Global || Class->hInstance == hInstance) return Class;
103 }
104
105 return NULL;
106 }
107
108
109 PWNDCLASS_OBJECT FASTCALL
110 ClassGetClassByName(LPCWSTR ClassName, HINSTANCE hInstance)
111 {
112 NTSTATUS Status;
113 RTL_ATOM Atom;
114
115 if (!ClassName || !PsGetWin32Thread()->Desktop)
116 return FALSE;
117
118 Status = RtlLookupAtomInAtomTable(
119 gAtomTable,
120 (LPWSTR)ClassName,
121 &Atom);
122
123 if (!NT_SUCCESS(Status))
124 {
125 DPRINT1("Failed to lookup class atom!\n");
126 return FALSE;
127 }
128
129 return ClassGetClassByAtom(Atom, hInstance);
130 }
131
132
133 PWNDCLASS_OBJECT FASTCALL
134 ClassGetClassByNameOrAtom(LPCWSTR ClassNameOrAtom, HINSTANCE hInstance)
135 {
136 if (!ClassNameOrAtom) return NULL;
137
138 if (IS_ATOM(ClassNameOrAtom))
139 return ClassGetClassByAtom((RTL_ATOM)((ULONG_PTR)ClassNameOrAtom), hInstance);
140 else
141 return ClassGetClassByName(ClassNameOrAtom, hInstance);
142 }
143
144
145 static
146 BOOL FASTCALL
147 IntRegisterClass(
148 CONST WNDCLASSEXW *lpwcx,
149 DWORD Flags,
150 WNDPROC wpExtra,
151 PUNICODE_STRING MenuName,
152 RTL_ATOM Atom)
153 {
154 PWNDCLASS_OBJECT Class;
155 ULONG objectSize;
156 BOOL Global;
157
158 ASSERT(lpwcx);
159 ASSERT(Atom);
160 ASSERT(lpwcx->hInstance);
161
162 Global = (Flags & REGISTERCLASS_SYSTEM) || (lpwcx->style & CS_GLOBALCLASS);
163
164 /* Check for double registration of the class. */
165 Class = ClassGetClassByAtom(Atom, lpwcx->hInstance);
166 if (Class && Global == Class->Global)
167 {
168 /* can max have one class of each type (global/local) */
169 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
170 return(FALSE);
171 }
172
173 objectSize = sizeof(WNDCLASS_OBJECT) + lpwcx->cbClsExtra;
174
175 //FIXME: allocate in session heap (or possibly desktop heap)
176 Class = ExAllocatePool(PagedPool, objectSize);
177 if (!Class)
178 {
179 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
180 return(FALSE);
181 }
182 RtlZeroMemory(Class, objectSize);
183
184 Class->cbSize = lpwcx->cbSize;
185 Class->style = lpwcx->style;
186 Class->cbClsExtra = lpwcx->cbClsExtra;
187 Class->cbWndExtra = lpwcx->cbWndExtra;
188 Class->hInstance = lpwcx->hInstance;
189 Class->hIcon = lpwcx->hIcon;
190 Class->hCursor = lpwcx->hCursor;
191 Class->hbrBackground = lpwcx->hbrBackground;
192 Class->Unicode = !(Flags & REGISTERCLASS_ANSI);
193 Class->Global = Global;
194 Class->hIconSm = lpwcx->hIconSm;
195 Class->Atom = Atom;
196
197 if (wpExtra == NULL)
198 {
199 if (Flags & REGISTERCLASS_ANSI)
200 {
201 Class->lpfnWndProcA = lpwcx->lpfnWndProc;
202 Class->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
203 }
204 else
205 {
206 Class->lpfnWndProcW = lpwcx->lpfnWndProc;
207 Class->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
208 }
209 }
210 else
211 {
212 if (Flags & REGISTERCLASS_ANSI)
213 {
214 Class->lpfnWndProcA = lpwcx->lpfnWndProc;
215 Class->lpfnWndProcW = wpExtra;
216 }
217 else
218 {
219 Class->lpfnWndProcW = lpwcx->lpfnWndProc;
220 Class->lpfnWndProcA = wpExtra;
221 }
222 }
223
224 if (MenuName->Length == 0)
225 {
226 Class->lpszMenuName.Length =
227 Class->lpszMenuName.MaximumLength = 0;
228 Class->lpszMenuName.Buffer = MenuName->Buffer;
229 }
230 else
231 {
232 Class->lpszMenuName.Length =
233 Class->lpszMenuName.MaximumLength = MenuName->MaximumLength;
234 Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Class->lpszMenuName.MaximumLength, TAG_STRING);
235 RtlCopyUnicodeString(&Class->lpszMenuName, MenuName);
236 }
237
238 /* Extra class data */
239 if (Class->cbClsExtra)
240 Class->ExtraData = (PCHAR)(Class + 1);
241
242 if (Global)
243 {
244 /* global classes go last (incl. system classes) */
245 InsertTailList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
246 }
247 else
248 {
249 /* local classes have priority so we put them first */
250 InsertHeadList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
251 }
252
253 return TRUE;
254 }
255
256
257 ULONG FASTCALL
258 IntGetClassLong(PWINDOW_OBJECT Window, ULONG Offset, BOOL Ansi)
259 {
260 LONG Ret;
261
262 if ((int)Offset >= 0)
263 {
264 DPRINT("GetClassLong(%x, %d)\n", Window->hSelf, Offset);
265 if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
266 {
267 SetLastWin32Error(ERROR_INVALID_PARAMETER);
268 return 0;
269 }
270 Ret = *((LONG *)(Window->Class->ExtraData + Offset));
271 DPRINT("Result: %x\n", Ret);
272 return Ret;
273 }
274
275 switch (Offset)
276 {
277 case GCL_CBWNDEXTRA:
278 Ret = Window->Class->cbWndExtra;
279 break;
280 case GCL_CBCLSEXTRA:
281 Ret = Window->Class->cbClsExtra;
282 break;
283 case GCL_HBRBACKGROUND:
284 Ret = (ULONG)Window->Class->hbrBackground;
285 break;
286 case GCL_HCURSOR:
287 Ret = (ULONG)Window->Class->hCursor;
288 break;
289 case GCL_HICON:
290 Ret = (ULONG)Window->Class->hIcon;
291 break;
292 case GCL_HICONSM:
293 Ret = (ULONG)Window->Class->hIconSm;
294 break;
295 case GCL_HMODULE:
296 Ret = (ULONG)Window->Class->hInstance;
297 break;
298 case GCL_MENUNAME:
299 Ret = (ULONG)Window->Class->lpszMenuName.Buffer;
300 break;
301 case GCL_STYLE:
302 Ret = Window->Class->style;
303 break;
304 case GCL_WNDPROC:
305 if (Ansi)
306 {
307 Ret = (ULONG)Window->Class->lpfnWndProcA;
308 }
309 else
310 {
311 Ret = (ULONG)Window->Class->lpfnWndProcW;
312 }
313 break;
314 case GCW_ATOM:
315 Ret = Window->Class->Atom;
316 break;
317 default:
318 Ret = 0;
319 break;
320 }
321 return(Ret);
322 }
323
324 static
325 void FASTCALL
326 co_IntSetClassLong(PWINDOW_OBJECT Window, ULONG Offset, LONG dwNewLong, BOOL Ansi)
327 {
328 ASSERT_REFS_CO(Window);
329
330 if ((int)Offset >= 0)
331 {
332 DPRINT("SetClassLong(%x, %d, %x)\n", Window->hSelf, Offset, dwNewLong);
333 if ((Offset + sizeof(LONG)) > Window->Class->cbClsExtra)
334 {
335 SetLastWin32Error(ERROR_INVALID_PARAMETER);
336 return;
337 }
338 *((LONG *)(Window->Class->ExtraData + Offset)) = dwNewLong;
339 return;
340 }
341
342 switch (Offset)
343 {
344 case GCL_CBWNDEXTRA:
345 Window->Class->cbWndExtra = dwNewLong;
346 break;
347 case GCL_CBCLSEXTRA:
348 Window->Class->cbClsExtra = dwNewLong;
349 break;
350 case GCL_HBRBACKGROUND:
351 Window->Class->hbrBackground = (HBRUSH)dwNewLong;
352 break;
353 case GCL_HCURSOR:
354 Window->Class->hCursor = (HCURSOR)dwNewLong;
355 break;
356 case GCL_HICON:
357 Window->Class->hIcon = (HICON)dwNewLong;
358
359 if (!IntGetOwner(Window) && !IntGetParent(Window))
360 {
361 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) Window->hSelf);
362 }
363 break;
364 case GCL_HICONSM:
365 Window->Class->hIconSm = (HICON)dwNewLong;
366 break;
367 case GCL_HMODULE:
368 Window->Class->hInstance = (HINSTANCE)dwNewLong;
369 break;
370 case GCL_MENUNAME:
371 if (Window->Class->lpszMenuName.MaximumLength)
372 RtlFreeUnicodeString(&Window->Class->lpszMenuName);
373 if (!IS_INTRESOURCE(dwNewLong))
374 {
375 Window->Class->lpszMenuName.Length =
376 Window->Class->lpszMenuName.MaximumLength = ((PUNICODE_STRING)dwNewLong)->MaximumLength;
377 Window->Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Window->Class->lpszMenuName.MaximumLength, TAG_STRING);
378 RtlCopyUnicodeString(&Window->Class->lpszMenuName, (PUNICODE_STRING)dwNewLong);
379 }
380 else
381 {
382 Window->Class->lpszMenuName.Length =
383 Window->Class->lpszMenuName.MaximumLength = 0;
384 Window->Class->lpszMenuName.Buffer = (LPWSTR)dwNewLong;
385 }
386 break;
387 case GCL_STYLE:
388 Window->Class->style = dwNewLong;
389 break;
390 case GCL_WNDPROC:
391 if (Ansi)
392 {
393 Window->Class->lpfnWndProcA = (WNDPROC)dwNewLong;
394 Window->Class->lpfnWndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,FALSE);
395 Window->Class->Unicode = FALSE;
396 }
397 else
398 {
399 Window->Class->lpfnWndProcW = (WNDPROC)dwNewLong;
400 Window->Class->lpfnWndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)dwNewLong,TRUE);
401 Window->Class->Unicode = TRUE;
402 }
403 break;
404 }
405 }
406 /* SYSCALLS *****************************************************************/
407
408
409 RTL_ATOM STDCALL
410 NtUserRegisterClassExWOW(
411 CONST WNDCLASSEXW* lpwcx,
412 PUNICODE_STRING ClassName,
413 PUNICODE_STRING ClassNameCopy,//huhuhuhu???
414 PUNICODE_STRING MenuName,
415 WNDPROC wpExtra,
416 DWORD Flags,
417 DWORD Unknown7)
418
419 /*
420 * FUNCTION:
421 * Registers a new class with the window manager
422 * ARGUMENTS:
423 * lpwcx = Win32 extended window class structure
424 * bUnicodeClass = Whether to send ANSI or unicode strings
425 * to window procedures
426 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
427 * RETURNS:
428 * Atom identifying the new class
429 */
430 {
431 WNDCLASSEXW SafeClass;
432 NTSTATUS Status;
433 RTL_ATOM Atom;
434 DECLARE_RETURN(RTL_ATOM);
435
436 DPRINT("Enter NtUserRegisterClassExWOW\n");
437 UserEnterExclusive();
438
439 if (!lpwcx)
440 {
441 SetLastWin32Error(ERROR_INVALID_PARAMETER);
442 RETURN( (RTL_ATOM)0);
443 }
444
445 if (Flags & ~REGISTERCLASS_ALL)
446 {
447 SetLastWin32Error(ERROR_INVALID_FLAGS);
448 RETURN( (RTL_ATOM)0);
449 }
450
451 Status = MmCopyFromCaller(&SafeClass, lpwcx, sizeof(WNDCLASSEXW));
452 if (!NT_SUCCESS(Status))
453 {
454 SetLastNtError(Status);
455 RETURN( (RTL_ATOM)0);
456 }
457
458 /* Deny negative sizes */
459 if (lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0)
460 {
461 SetLastWin32Error(ERROR_INVALID_PARAMETER);
462 RETURN( (RTL_ATOM)0);
463 }
464
465 if (!lpwcx->hInstance)
466 {
467 SetLastWin32Error(ERROR_INVALID_PARAMETER);
468 RETURN( (RTL_ATOM)0);
469 }
470
471 //FIXME: make ClassName ptr the atom, not buffer
472 if (ClassName->Length > 0)
473 {
474 DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer);
475 /* FIXME - Safely copy/verify the buffer first!!! */
476 Status = RtlAddAtomToAtomTable(gAtomTable,
477 ClassName->Buffer,
478 &Atom);
479 if (!NT_SUCCESS(Status))
480 {
481 DPRINT1("Failed adding class name (%S) to atom table\n",
482 ClassName->Buffer);
483 SetLastNtError(Status);
484 RETURN((RTL_ATOM)0);
485 }
486 }
487 else
488 {
489 Atom = (RTL_ATOM)(ULONG)ClassName->Buffer;
490 }
491
492 if (!Atom)
493 {
494 SetLastWin32Error(ERROR_INVALID_PARAMETER);
495 RETURN(0);
496 }
497
498 if (!IntRegisterClass(&SafeClass, Flags, wpExtra, MenuName, Atom))
499 {
500 if (ClassName->Length)
501 {
502 RtlDeleteAtomFromAtomTable(gAtomTable, Atom);
503 }
504 DPRINT("Failed creating window class object\n");
505 RETURN((RTL_ATOM)0);
506 }
507
508 RETURN(Atom);
509
510 CLEANUP:
511 DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_);
512 UserLeave();
513 END_CLEANUP;
514 }
515
516
517
518 DWORD STDCALL
519 NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
520 {
521 PWINDOW_OBJECT Window;
522 DECLARE_RETURN(DWORD);
523
524 DPRINT("Enter NtUserGetClassLong\n");
525 UserEnterExclusive();
526
527 if (!(Window = UserGetWindowObject(hWnd)))
528 {
529 RETURN(0);
530 }
531
532 RETURN(IntGetClassLong(Window, Offset, Ansi));
533
534 CLEANUP:
535 DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_);
536 UserLeave();
537 END_CLEANUP;
538 }
539
540
541
542 DWORD STDCALL
543 NtUserSetClassLong(HWND hWnd,
544 DWORD Offset,
545 LONG dwNewLong,
546 BOOL Ansi)
547 {
548 PWINDOW_OBJECT Window;
549 LONG Ret;
550 USER_REFERENCE_ENTRY Ref;
551 DECLARE_RETURN(DWORD);
552
553 DPRINT("Enter NtUserSetClassLong\n");
554 UserEnterExclusive();
555
556 if (!(Window = UserGetWindowObject(hWnd)))
557 {
558 RETURN(0);
559 }
560
561 UserRefObjectCo(Window, &Ref);
562
563 Ret = IntGetClassLong(Window, Offset, Ansi);
564 co_IntSetClassLong(Window, Offset, dwNewLong, Ansi);
565
566 UserDerefObjectCo(Window);
567
568 RETURN(Ret);
569
570 CLEANUP:
571 DPRINT("Leave NtUserSetClassLong, ret=%i\n",_ret_);
572 UserLeave();
573 END_CLEANUP;
574 }
575
576 DWORD STDCALL
577 NtUserSetClassWord(DWORD Unknown0,
578 DWORD Unknown1,
579 DWORD Unknown2)
580 {
581 UNIMPLEMENTED;
582 return(0);
583 }
584
585 BOOL STDCALL
586 NtUserUnregisterClass(
587 LPCWSTR ClassNameOrAtom,
588 HINSTANCE hInstance, /* can be 0 */
589 DWORD Unknown)
590 {
591 PWNDCLASS_OBJECT Class;
592 DECLARE_RETURN(BOOL);
593
594 DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom);
595 UserEnterExclusive();
596
597 if (!ClassNameOrAtom)
598 {
599 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
600 RETURN(FALSE);
601 }
602
603 if (!(Class = ClassGetClassByNameOrAtom(ClassNameOrAtom, hInstance)))
604 {
605 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
606 RETURN(FALSE);
607 }
608
609 if (Class->refs)
610 {
611 /* NOTE: the class will not be freed when its refs become 0 ie. no more
612 * windows are using it. I dunno why that is but its how Windows does it (and Wine).
613 * The class will hang around until the process exit. -Gunnar
614 */
615 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
616 RETURN(FALSE);
617 }
618
619 DestroyClass(Class);
620
621 RETURN(TRUE);
622
623 CLEANUP:
624 DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_);
625 UserLeave();
626 END_CLEANUP;
627 }
628
629 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
630 DWORD STDCALL
631 NtUserGetClassInfo(
632 HINSTANCE hInstance,
633 LPCWSTR lpClassName,
634 LPWNDCLASSEXW lpWndClassEx,
635 BOOL Ansi,
636 DWORD unknown3)
637 {
638 PWNDCLASS_OBJECT Class;
639 RTL_ATOM Atom;
640 DECLARE_RETURN(DWORD);
641
642 if (IS_ATOM(lpClassName))
643 DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName, hInstance);
644 else
645 DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName, hInstance);
646
647 UserEnterExclusive();
648
649 if (!hInstance)
650 {
651 SetLastWin32Error(ERROR_INVALID_PARAMETER);
652 RETURN(0);
653 }
654
655 if (!(Class = ClassGetClassByNameOrAtom(lpClassName, hInstance)))
656 {
657 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
658 RETURN(0);
659 }
660
661 lpWndClassEx->cbSize = sizeof(WNDCLASSEXW);
662 lpWndClassEx->style = Class->style;
663 if (Ansi)
664 lpWndClassEx->lpfnWndProc = Class->lpfnWndProcA;
665 else
666 lpWndClassEx->lpfnWndProc = Class->lpfnWndProcW;
667 lpWndClassEx->cbClsExtra = Class->cbClsExtra;
668 lpWndClassEx->cbWndExtra = Class->cbWndExtra;
669 /* This is not typo, we're really not going to use Class->hInstance here. */
670 /* Well, i think its wrong so i changed it -Gunnar */
671 lpWndClassEx->hInstance = Class->hInstance;
672 lpWndClassEx->hIcon = Class->hIcon;
673 lpWndClassEx->hCursor = Class->hCursor;
674 lpWndClassEx->hbrBackground = Class->hbrBackground;
675 if (Class->lpszMenuName.MaximumLength)
676 RtlCopyUnicodeString((PUNICODE_STRING)lpWndClassEx->lpszMenuName, &Class->lpszMenuName);
677 else
678 lpWndClassEx->lpszMenuName = Class->lpszMenuName.Buffer;
679 lpWndClassEx->lpszClassName = lpClassName;
680 lpWndClassEx->hIconSm = Class->hIconSm;
681 Atom = Class->Atom;
682
683 RETURN(Atom);
684
685 CLEANUP:
686 DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_);
687 UserLeave();
688 END_CLEANUP;
689 }
690
691
692
693 DWORD STDCALL
694 NtUserGetClassName (
695 HWND hWnd,
696 LPWSTR lpClassName,
697 ULONG nMaxCount /* in TCHARS */
698 )
699 {
700 PWINDOW_OBJECT Window;
701 DECLARE_RETURN(DWORD);
702 NTSTATUS Status;
703
704 UserEnterShared();
705 DPRINT("Enter NtUserGetClassName\n");
706
707 if (!(Window = UserGetWindowObject(hWnd)))
708 {
709 RETURN(0);
710 }
711
712 nMaxCount *= sizeof(WCHAR);
713
714 //FIXME: wrap in SEH to protect lpClassName access
715 Status = RtlQueryAtomInAtomTable(gAtomTable,
716 Window->Class->Atom, NULL, NULL,
717 lpClassName, &nMaxCount);
718 if (!NT_SUCCESS(Status))
719 {
720 SetLastNtError(Status);
721 RETURN(0);
722 }
723
724 RETURN(nMaxCount / sizeof(WCHAR));
725
726 CLEANUP:
727 DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_);
728 UserLeave();
729 END_CLEANUP;
730 }
731
732 DWORD STDCALL
733 NtUserGetWOWClass(DWORD Unknown0,
734 DWORD Unknown1)
735 {
736 UNIMPLEMENTED;
737 return(0);
738 }
739
740
741 /* EOF */