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