sync to trunk revision 36700
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / class.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2006 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 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Window classes
23 * FILE: subsys/win32k/ntuser/class.c
24 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * REVISION HISTORY:
26 * 06-06-2001 CSH Created
27 */
28 /* INCLUDES ******************************************************************/
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34 #define TRACE DPRINT
35 #define WARN DPRINT1
36 #define ERR DPRINT1
37
38 /* WINDOWCLASS ***************************************************************/
39
40 #define REGISTERCLASS_SYSTEM 0x4
41
42 static VOID
43 IntFreeClassMenuName(IN OUT PWINDOWCLASS Class)
44 {
45 /* free the menu name, if it was changed and allocated */
46 if (Class->MenuName != NULL && Class->MenuNameIsString)
47 {
48 UserHeapFree(Class->MenuName);
49 Class->MenuName = NULL;
50 Class->AnsiMenuName = NULL;
51 }
52 }
53
54 static VOID
55 IntDestroyClass(IN OUT PWINDOWCLASS Class)
56 {
57 /* there shouldn't be any clones anymore */
58 ASSERT(Class->Windows == 0);
59 ASSERT(Class->Clone == NULL);
60
61 if (Class->Base == Class)
62 {
63 PCALLPROC CallProc, NextCallProc;
64
65 /* Destroy allocated callproc handles */
66 CallProc = Class->CallProcList;
67 while (CallProc != NULL)
68 {
69 NextCallProc = CallProc->Next;
70
71 CallProc->Next = NULL;
72 DestroyCallProc(NULL,
73 CallProc);
74
75 CallProc = NextCallProc;
76 }
77
78 if (Class->Dce)
79 {
80 DceFreeClassDCE(((PDCE)Class->Dce)->hDC);
81 Class->Dce = NULL;
82 }
83
84 IntFreeClassMenuName(Class);
85 }
86
87 /* free the structure */
88 if (Class->Desktop != NULL)
89 {
90 DesktopHeapFree(Class->Desktop,
91 Class);
92 }
93 else
94 {
95 UserHeapFree(Class);
96 }
97 }
98
99
100 /* clean all process classes. all process windows must cleaned first!! */
101 void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
102 {
103 PWINDOWCLASS Class;
104 PW32PROCESSINFO pi = Process->ProcessInfo;
105
106 if (pi != NULL)
107 {
108 /* free all local classes */
109 Class = pi->LocalClassList;
110 while (Class != NULL)
111 {
112 pi->LocalClassList = Class->Next;
113
114 ASSERT(Class->Base == Class);
115 IntDestroyClass(Class);
116
117 Class = pi->LocalClassList;
118 }
119
120 /* free all global classes */
121 Class = pi->GlobalClassList;
122 while (Class != NULL)
123 {
124 pi->GlobalClassList = Class->Next;
125
126 ASSERT(Class->Base == Class);
127 IntDestroyClass(Class);
128
129 Class = pi->GlobalClassList;
130 }
131
132 /* free all system classes */
133 Class = pi->SystemClassList;
134 while (Class != NULL)
135 {
136 pi->SystemClassList = Class->Next;
137
138 ASSERT(Class->Base == Class);
139 IntDestroyClass(Class);
140
141 Class = pi->SystemClassList;
142 }
143 }
144 }
145
146 static BOOL
147 IntRegisterClassAtom(IN PUNICODE_STRING ClassName,
148 OUT RTL_ATOM *pAtom)
149 {
150 WCHAR szBuf[65];
151 PWSTR AtomName;
152 NTSTATUS Status;
153
154 if (ClassName->Length != 0)
155 {
156 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
157 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
158 {
159 SetLastWin32Error(ERROR_INVALID_PARAMETER);
160 return (RTL_ATOM)0;
161 }
162
163 RtlCopyMemory(szBuf,
164 ClassName->Buffer,
165 ClassName->Length);
166 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
167 AtomName = szBuf;
168 }
169 else
170 AtomName = ClassName->Buffer;
171
172 Status = RtlAddAtomToAtomTable(gAtomTable,
173 AtomName,
174 pAtom);
175
176 if (!NT_SUCCESS(Status))
177 {
178 SetLastNtError(Status);
179 return FALSE;
180 }
181
182 return TRUE;
183 }
184
185 static NTSTATUS
186 IntDeregisterClassAtom(IN RTL_ATOM Atom)
187 {
188 return RtlDeleteAtomFromAtomTable(gAtomTable,
189 Atom);
190 }
191
192 PCALLPROC
193 UserFindCallProc(IN PWINDOWCLASS Class,
194 IN WNDPROC WndProc,
195 IN BOOL bUnicode)
196 {
197 PCALLPROC CallProc;
198
199 CallProc = Class->CallProcList;
200 while (CallProc != NULL)
201 {
202 if (CallProc->WndProc == WndProc &&
203 CallProc->Unicode == (UINT)bUnicode)
204 {
205 return CallProc;
206 }
207
208 CallProc = CallProc->Next;
209 }
210
211 return NULL;
212 }
213
214 VOID
215 UserAddCallProcToClass(IN OUT PWINDOWCLASS Class,
216 IN PCALLPROC CallProc)
217 {
218 PWINDOWCLASS BaseClass;
219
220 ASSERT(CallProc->Next == NULL);
221
222 BaseClass = Class->Base;
223 ASSERT(CallProc->Next == NULL);
224 CallProc->Next = BaseClass->CallProcList;
225 BaseClass->CallProcList = CallProc;
226
227 /* Update all clones */
228 Class = Class->Clone;
229 while (Class != NULL)
230 {
231 Class->CallProcList = BaseClass->CallProcList;
232 Class = Class->Next;
233 }
234 }
235
236 static BOOL
237 IntSetClassAtom(IN OUT PWINDOWCLASS Class,
238 IN PUNICODE_STRING ClassName)
239 {
240 RTL_ATOM Atom = (RTL_ATOM)0;
241
242 /* update the base class first */
243 Class = Class->Base;
244
245 if (!IntRegisterClassAtom(ClassName,
246 &Atom))
247 {
248 return FALSE;
249 }
250
251 IntDeregisterClassAtom(Class->Atom);
252
253 Class->Atom = Atom;
254
255 /* update the clones */
256 Class = Class->Clone;
257 while (Class != NULL)
258 {
259 Class->Atom = Atom;
260
261 Class = Class->Next;
262 }
263
264 return TRUE;
265 }
266
267 static WNDPROC
268 IntGetClassWndProc(IN PWINDOWCLASS Class,
269 IN PW32PROCESSINFO pi,
270 IN BOOL Ansi)
271 {
272 ASSERT(UserIsEnteredExclusive() == TRUE);
273
274 if (Class->System)
275 {
276 return (Ansi ? Class->WndProcExtra : Class->WndProc);
277 }
278 else
279 {
280 if (!Ansi == Class->Unicode)
281 {
282 return Class->WndProc;
283 }
284 else
285 {
286 PWINDOWCLASS BaseClass;
287
288 /* make sure the call procedures are located on the desktop
289 of the base class! */
290 BaseClass = Class->Base;
291 Class = BaseClass;
292
293 if (Class->CallProc != NULL)
294 {
295 return GetCallProcHandle(Class->CallProc);
296 }
297 else
298 {
299 PCALLPROC NewCallProc;
300
301 if (pi == NULL)
302 return NULL;
303
304 NewCallProc = UserFindCallProc(Class,
305 Class->WndProc,
306 Class->Unicode);
307 if (NewCallProc == NULL)
308 {
309 NewCallProc = CreateCallProc(NULL,
310 Class->WndProc,
311 Class->Unicode,
312 pi);
313 if (NewCallProc == NULL)
314 {
315 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
316 return NULL;
317 }
318
319 UserAddCallProcToClass(Class,
320 NewCallProc);
321 }
322
323 Class->CallProc = NewCallProc;
324
325 /* update the clones */
326 Class = Class->Clone;
327 while (Class != NULL)
328 {
329 Class->CallProc = NewCallProc;
330
331 Class = Class->Next;
332 }
333
334 return GetCallProcHandle(NewCallProc);
335 }
336 }
337 }
338 }
339
340 static WNDPROC
341 IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
342 IN WNDPROC WndProc,
343 IN BOOL Ansi)
344 {
345 WNDPROC Ret;
346
347 if (Class->System)
348 {
349 DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class->Atom);
350 SetLastWin32Error(ERROR_ACCESS_DENIED);
351 return NULL;
352 }
353
354 /* update the base class first */
355 Class = Class->Base;
356
357 /* resolve any callproc handle if possible */
358 if (IsCallProcHandle(WndProc))
359 {
360 WNDPROC_INFO wpInfo;
361
362 if (UserGetCallProcInfo((HANDLE)WndProc,
363 &wpInfo))
364 {
365 WndProc = wpInfo.WindowProc;
366 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
367 }
368 }
369
370 Ret = IntGetClassWndProc(Class,
371 GetW32ProcessInfo(),
372 Ansi);
373 if (Ret == NULL)
374 {
375 return NULL;
376 }
377
378 /* update the class info */
379 Class->Unicode = !Ansi;
380 Class->WndProc = WndProc;
381
382 /* update the clones */
383 Class = Class->Clone;
384 while (Class != NULL)
385 {
386 Class->Unicode = !Ansi;
387 Class->WndProc = WndProc;
388
389 Class = Class->Next;
390 }
391
392 return Ret;
393 }
394
395 static PWINDOWCLASS
396 IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
397 IN OUT PWINDOWCLASS *ClassLink,
398 IN PDESKTOP Desktop)
399 {
400 SIZE_T ClassSize;
401 PWINDOWCLASS Class;
402
403 ASSERT(Desktop != NULL);
404 ASSERT(BaseClass->Base == BaseClass);
405
406 if (BaseClass->Desktop == Desktop)
407 {
408 /* it is most likely that a window is created on the same
409 desktop as the window class. */
410
411 return BaseClass;
412 }
413
414 if (BaseClass->Desktop == NULL)
415 {
416 ASSERT(BaseClass->Windows == 0);
417 ASSERT(BaseClass->Clone == NULL);
418
419 /* Classes are also located in the shared heap when the class
420 was created before the thread attached to a desktop. As soon
421 as a window is created for such a class located on the shared
422 heap, the class is cloned into the desktop heap on which the
423 window is created. */
424 Class = NULL;
425 }
426 else
427 {
428 /* The user is asking for a class object on a different desktop,
429 try to find one! */
430 Class = BaseClass->Clone;
431 while (Class != NULL)
432 {
433 if (Class->Desktop == Desktop)
434 {
435 ASSERT(Class->Base == BaseClass);
436 ASSERT(Class->Clone == NULL);
437 break;
438 }
439
440 Class = Class->Next;
441 }
442 }
443
444 if (Class == NULL)
445 {
446 /* The window is created on a different desktop, we need to
447 clone the class object to the desktop heap of the window! */
448 ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->ClsExtra;
449
450 Class = DesktopHeapAlloc(Desktop,
451 ClassSize);
452 if (Class != NULL)
453 {
454 /* simply clone the class */
455 RtlCopyMemory(Class,
456 BaseClass,
457 ClassSize);
458
459 /* update some pointers and link the class */
460 Class->Desktop = Desktop;
461 Class->Windows = 0;
462
463 if (BaseClass->Desktop == NULL)
464 {
465 /* we don't really need the base class on the shared
466 heap anymore, delete it so the only class left is
467 the clone we just created, which now serves as the
468 new base class */
469 ASSERT(BaseClass->Clone == NULL);
470 ASSERT(Class->Clone == NULL);
471 Class->Base = Class;
472 Class->Next = BaseClass->Next;
473
474 /* replace the base class */
475 (void)InterlockedExchangePointer((PVOID*)ClassLink,
476 Class);
477
478 /* destroy the obsolete copy on the shared heap */
479 BaseClass->Base = NULL;
480 BaseClass->Clone = NULL;
481 IntDestroyClass(BaseClass);
482 }
483 else
484 {
485 /* link in the clone */
486 Class->Clone = NULL;
487 Class->Base = BaseClass;
488 Class->Next = BaseClass->Clone;
489 (void)InterlockedExchangePointer((VOID*)&BaseClass->Clone,
490 Class);
491 }
492 }
493 else
494 {
495 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
496 }
497 }
498
499 return Class;
500 }
501
502 PWINDOWCLASS
503 IntReferenceClass(IN OUT PWINDOWCLASS BaseClass,
504 IN OUT PWINDOWCLASS *ClassLink,
505 IN PDESKTOP Desktop)
506 {
507 PWINDOWCLASS Class;
508
509 ASSERT(BaseClass->Base == BaseClass);
510
511 Class = IntGetClassForDesktop(BaseClass,
512 ClassLink,
513 Desktop);
514 if (Class != NULL)
515 {
516 Class->Windows++;
517 }
518
519 return Class;
520 }
521
522 static VOID
523 IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
524 IN OUT PWINDOWCLASS *BaseClassLink,
525 IN OUT PWINDOWCLASS *CloneLink)
526 {
527 PWINDOWCLASS Clone, BaseClass;
528
529 ASSERT(Class->Base != Class);
530 ASSERT(Class->Base->Clone != NULL);
531 ASSERT(Class->Desktop != NULL);
532 ASSERT(Class->Windows != 0);
533 ASSERT(Class->Base->Desktop != NULL);
534 ASSERT(Class->Base->Windows == 0);
535
536 /* unlink the clone */
537 *CloneLink = Class->Next;
538 Class->Clone = Class->Base->Clone;
539
540 BaseClass = Class->Base;
541
542 /* update the class information to make it a base class */
543 Class->Base = Class;
544 Class->Next = (*BaseClassLink)->Next;
545
546 /* update all clones */
547 Clone = Class->Clone;
548 while (Clone != NULL)
549 {
550 ASSERT(Clone->Clone == NULL);
551 Clone->Base = Class;
552
553 if (!Class->System)
554 Clone->CallProc = Class->CallProc;
555
556 Clone = Clone->Next;
557 }
558
559 /* link in the new base class */
560 (void)InterlockedExchangePointer((PVOID*)BaseClassLink,
561 Class);
562 }
563
564 VOID
565 IntDereferenceClass(IN OUT PWINDOWCLASS Class,
566 IN PDESKTOP Desktop,
567 IN PW32PROCESSINFO pi)
568 {
569 PWINDOWCLASS *PrevLink, BaseClass, CurrentClass;
570
571 BaseClass = Class->Base;
572
573 if (--Class->Windows == 0)
574 {
575 if (BaseClass == Class)
576 {
577 ASSERT(Class->Base == Class);
578
579 /* check if there are clones of the class on other desktops,
580 link the first clone in if possible. If there are no clones
581 then leave the class on the desktop heap. It will get moved
582 to the shared heap when the thread detaches. */
583 if (BaseClass->Clone != NULL)
584 {
585 if (BaseClass->System)
586 PrevLink = &pi->SystemClassList;
587 else if (BaseClass->Global)
588 PrevLink = &pi->GlobalClassList;
589 else
590 PrevLink = &pi->LocalClassList;
591
592 CurrentClass = *PrevLink;
593 while (CurrentClass != BaseClass)
594 {
595 ASSERT(CurrentClass != NULL);
596
597 PrevLink = &CurrentClass->Next;
598 CurrentClass = CurrentClass->Next;
599 }
600
601 ASSERT(*PrevLink == BaseClass);
602
603 /* make the first clone become the new base class */
604 IntMakeCloneBaseClass(BaseClass->Clone,
605 PrevLink,
606 &BaseClass->Clone);
607
608 /* destroy the class, there's still another clone of the class
609 that now serves as a base class. Make sure we don't destruct
610 resources shared by all classes (Base = NULL)! */
611 BaseClass->Base = NULL;
612 BaseClass->Clone = NULL;
613 IntDestroyClass(BaseClass);
614 }
615 }
616 else
617 {
618 /* locate the cloned class and unlink it */
619 PrevLink = &BaseClass->Clone;
620 CurrentClass = BaseClass->Clone;
621 while (CurrentClass != Class)
622 {
623 ASSERT(CurrentClass != NULL);
624
625 PrevLink = &CurrentClass->Next;
626 CurrentClass = CurrentClass->Next;
627 }
628
629 ASSERT(CurrentClass == Class);
630
631 (void)InterlockedExchangePointer((PVOID*)PrevLink,
632 Class->Next);
633
634 ASSERT(Class->Base == BaseClass);
635 ASSERT(Class->Clone == NULL);
636
637 /* the class was just a clone, we don't need it anymore */
638 IntDestroyClass(Class);
639 }
640 }
641 }
642
643 static BOOL
644 IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
645 IN OUT PWINDOWCLASS **ClassLinkPtr)
646 {
647 PWINDOWCLASS NewClass;
648 SIZE_T ClassSize;
649
650 ASSERT(Class->Base == Class);
651 ASSERT(Class->Desktop != NULL);
652 ASSERT(Class->Windows == 0);
653 ASSERT(Class->Clone == NULL);
654
655 ClassSize = sizeof(*Class) + (SIZE_T)Class->ClsExtra;
656
657 /* allocate the new base class on the shared heap */
658 NewClass = UserHeapAlloc(ClassSize);
659 if (NewClass != NULL)
660 {
661 RtlCopyMemory(NewClass,
662 Class,
663 ClassSize);
664
665 NewClass->Desktop = NULL;
666 NewClass->Base = NewClass;
667
668 /* replace the class in the list */
669 (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
670 NewClass);
671 *ClassLinkPtr = &NewClass->Next;
672
673 /* free the obsolete class on the desktop heap */
674 Class->Base = NULL;
675 IntDestroyClass(Class);
676 return TRUE;
677 }
678
679 return FALSE;
680 }
681
682 static VOID
683 IntCheckDesktopClasses(IN PDESKTOP Desktop,
684 IN OUT PWINDOWCLASS *ClassList,
685 IN BOOL FreeOnFailure,
686 OUT BOOL *Ret)
687 {
688 PWINDOWCLASS Class, NextClass, *Link;
689
690 /* NOTE: We only need to check base classes! When classes are no longer needed
691 on a desktop, the clones will be freed automatically as soon as possible.
692 However, we need to move base classes to the shared heap, as soon as
693 the last desktop heap where a class is allocated on is about to be destroyed.
694 If we didn't move the class to the shared heap, the class would become
695 inaccessible! */
696
697 ASSERT(Desktop != NULL);
698
699 Link = ClassList;
700 Class = *Link;
701 while (Class != NULL)
702 {
703 NextClass = Class->Next;
704
705 ASSERT(Class->Base == Class);
706
707 if (Class->Desktop == Desktop &&
708 Class->Windows == 0)
709 {
710 /* there shouldn't be any clones around anymore! */
711 ASSERT(Class->Clone == NULL);
712
713 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
714 /* FIXME - We could move the class to another desktop heap if there's still desktops
715 mapped into the process... */
716
717 /* move the class to the shared heap */
718 if (IntMoveClassToSharedHeap(Class,
719 &Link))
720 {
721 ASSERT(*Link == NextClass);
722 }
723 else
724 {
725 ASSERT(NextClass == Class->Next);
726
727 if (FreeOnFailure)
728 {
729 /* unlink the base class */
730 (void)InterlockedExchangePointer((PVOID*)Link,
731 Class->Next);
732
733 /* we can free the old base class now */
734 Class->Base = NULL;
735 IntDestroyClass(Class);
736 }
737 else
738 {
739 Link = &Class->Next;
740 *Ret = FALSE;
741 }
742 }
743 }
744 else
745 Link = &Class->Next;
746
747 Class = NextClass;
748 }
749 }
750
751 BOOL
752 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
753 IN BOOL FreeOnFailure)
754 {
755 PW32PROCESSINFO pi;
756 BOOL Ret = TRUE;
757
758 pi = GetW32ProcessInfo();
759 if (pi == NULL)
760 return TRUE;
761
762 /* check all local classes */
763 IntCheckDesktopClasses(Desktop,
764 &pi->LocalClassList,
765 FreeOnFailure,
766 &Ret);
767
768 /* check all global classes */
769 IntCheckDesktopClasses(Desktop,
770 &pi->GlobalClassList,
771 FreeOnFailure,
772 &Ret);
773
774 /* check all system classes */
775 IntCheckDesktopClasses(Desktop,
776 &pi->SystemClassList,
777 FreeOnFailure,
778 &Ret);
779
780 if (!Ret)
781 {
782 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
783 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
784 }
785
786 return Ret;
787 }
788
789 static PWINDOWCLASS
790 IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
791 IN PUNICODE_STRING ClassName,
792 IN PUNICODE_STRING MenuName,
793 IN WNDPROC wpExtra,
794 IN DWORD dwFlags,
795 IN PDESKTOP Desktop,
796 IN PW32PROCESSINFO pi)
797 {
798 SIZE_T ClassSize;
799 PWINDOWCLASS Class = NULL;
800 RTL_ATOM Atom;
801 PWSTR pszMenuName = NULL;
802 NTSTATUS Status = STATUS_SUCCESS;
803
804 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
805 lpwcx, ClassName, MenuName, wpExtra, dwFlags, Desktop, pi);
806
807 if (!IntRegisterClassAtom(ClassName,
808 &Atom))
809 {
810 DPRINT1("Failed to register class atom!\n");
811 return NULL;
812 }
813
814 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
815 if (MenuName->Length != 0)
816 {
817 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
818 RtlUnicodeStringToAnsiSize(MenuName));
819 if (pszMenuName == NULL)
820 goto NoMem;
821 }
822
823 if (Desktop != NULL)
824 {
825 Class = DesktopHeapAlloc(Desktop,
826 ClassSize);
827 }
828 else
829 {
830 /* FIXME - the class was created before being connected
831 to a desktop. It is possible for the desktop window,
832 but should it be allowed for any other case? */
833 Class = UserHeapAlloc(ClassSize);
834 }
835
836 if (Class != NULL)
837 {
838 RtlZeroMemory(Class,
839 ClassSize);
840
841 Class->Desktop = Desktop;
842 Class->Base = Class;
843 Class->Atom = Atom;
844
845 if (dwFlags & REGISTERCLASS_SYSTEM)
846 {
847 dwFlags &= ~REGISTERCLASS_ANSI;
848 Class->WndProcExtra = wpExtra;
849 Class->System = TRUE;
850 }
851
852 _SEH_TRY
853 {
854 PWSTR pszMenuNameBuffer = pszMenuName;
855
856 /* need to protect with SEH since accessing the WNDCLASSEX structure
857 and string buffers might raise an exception! We don't want to
858 leak memory... */
859 Class->WndProc = lpwcx->lpfnWndProc;
860 Class->Style = lpwcx->style;
861 Class->ClsExtra = lpwcx->cbClsExtra;
862 Class->WndExtra = lpwcx->cbWndExtra;
863 Class->hInstance = lpwcx->hInstance;
864 Class->hIcon = lpwcx->hIcon; /* FIXME */
865 Class->hIconSm = lpwcx->hIconSm; /* FIXME */
866 Class->hCursor = lpwcx->hCursor; /* FIXME */
867 Class->hbrBackground = lpwcx->hbrBackground;
868
869 /* make a copy of the string */
870 if (pszMenuNameBuffer != NULL)
871 {
872 Class->MenuNameIsString = TRUE;
873
874 Class->MenuName = pszMenuNameBuffer;
875 RtlCopyMemory(Class->MenuName,
876 MenuName->Buffer,
877 MenuName->Length);
878 Class->MenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
879
880 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
881 }
882 else
883 Class->MenuName = MenuName->Buffer;
884
885 /* save an ansi copy of the string */
886 if (pszMenuNameBuffer != NULL)
887 {
888 ANSI_STRING AnsiString;
889
890 Class->AnsiMenuName = (PSTR)pszMenuNameBuffer;
891 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
892 AnsiString.Buffer = Class->AnsiMenuName;
893 Status = RtlUnicodeStringToAnsiString(&AnsiString,
894 MenuName,
895 FALSE);
896 if (!NT_SUCCESS(Status))
897 {
898 DPRINT1("Failed to convert unicode menu name to ansi!\n");
899
900 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
901 _SEH_LEAVE;
902 }
903 }
904 else
905 Class->AnsiMenuName = (PSTR)MenuName->Buffer;
906
907 if (!(dwFlags & REGISTERCLASS_ANSI))
908 Class->Unicode = TRUE;
909
910 if (Class->Style & CS_GLOBALCLASS)
911 Class->Global = TRUE;
912 }
913 _SEH_HANDLE
914 {
915 Status = _SEH_GetExceptionCode();
916 }
917 _SEH_END;
918
919 if (!NT_SUCCESS(Status))
920 {
921 DPRINT1("Failed creating the class: 0x%x\n", Status);
922
923 SetLastNtError(Status);
924
925 if (pszMenuName != NULL)
926 UserHeapFree(pszMenuName);
927
928 DesktopHeapFree(Desktop,
929 Class);
930 Class = NULL;
931
932 IntDeregisterClassAtom(Atom);
933 }
934 }
935 else
936 {
937 NoMem:
938 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop);
939
940 if (pszMenuName != NULL)
941 UserHeapFree(pszMenuName);
942
943 IntDeregisterClassAtom(Atom);
944
945 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
946 }
947
948 return Class;
949 }
950
951 static PWINDOWCLASS
952 IntFindClass(IN RTL_ATOM Atom,
953 IN HINSTANCE hInstance,
954 IN PWINDOWCLASS *ClassList,
955 OUT PWINDOWCLASS **Link OPTIONAL)
956 {
957 PWINDOWCLASS Class, *PrevLink = ClassList;
958
959 Class = *PrevLink;
960 while (Class != NULL)
961 {
962 if (Class->Atom == Atom &&
963 (hInstance == NULL || Class->hInstance == hInstance) &&
964 !Class->Destroying)
965 {
966 ASSERT(Class->Base == Class);
967
968 if (Link != NULL)
969 *Link = PrevLink;
970 break;
971 }
972
973 PrevLink = &Class->Next;
974 Class = Class->Next;
975 }
976
977 return Class;
978 }
979
980 BOOL
981 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
982 OUT RTL_ATOM *Atom)
983 {
984 BOOL Ret = FALSE;
985
986 if (ClassName->Length != 0)
987 {
988 WCHAR szBuf[65];
989 PWSTR AtomName;
990 NTSTATUS Status;
991
992 /* NOTE: Caller has to protect the call with SEH! */
993
994 if (ClassName->Length != 0)
995 {
996 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
997 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
998 {
999 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1000 return (RTL_ATOM)0;
1001 }
1002
1003 /* We need to make a local copy of the class name! The caller could
1004 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1005 We're protected by SEH, but the ranges that might be accessed were
1006 not probed... */
1007 RtlCopyMemory(szBuf,
1008 ClassName->Buffer,
1009 ClassName->Length);
1010 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1011 AtomName = szBuf;
1012 }
1013 else
1014 AtomName = ClassName->Buffer;
1015
1016 /* lookup the atom */
1017 Status = RtlLookupAtomInAtomTable(gAtomTable,
1018 AtomName,
1019 Atom);
1020 if (NT_SUCCESS(Status))
1021 {
1022 Ret = TRUE;
1023 }
1024 else
1025 {
1026 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1027 {
1028 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
1029 }
1030 else
1031 {
1032 SetLastNtError(Status);
1033 }
1034 }
1035 }
1036 else
1037 {
1038 ASSERT(IS_ATOM(ClassName->Buffer));
1039 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1040 Ret = TRUE;
1041 }
1042
1043 return Ret;
1044 }
1045
1046 RTL_ATOM
1047 IntGetClassAtom(IN PUNICODE_STRING ClassName,
1048 IN HINSTANCE hInstance OPTIONAL,
1049 IN PW32PROCESSINFO pi OPTIONAL,
1050 OUT PWINDOWCLASS *BaseClass OPTIONAL,
1051 OUT PWINDOWCLASS **Link OPTIONAL)
1052 {
1053 RTL_ATOM Atom = (RTL_ATOM)0;
1054
1055 ASSERT(BaseClass != NULL);
1056
1057 if (IntGetAtomFromStringOrAtom(ClassName,
1058 &Atom) &&
1059 Atom != (RTL_ATOM)0)
1060 {
1061 PWINDOWCLASS Class;
1062
1063 /* attempt to locate the class object */
1064
1065 ASSERT(pi != NULL);
1066
1067 /* Step 1: try to find an exact match of locally registered classes */
1068 Class = IntFindClass(Atom,
1069 hInstance,
1070 &pi->LocalClassList,
1071 Link);
1072 if (Class != NULL)
1073 {
1074 goto FoundClass;
1075 }
1076
1077 /* Step 2: try to find any globally registered class. The hInstance
1078 is not relevant for global classes */
1079 Class = IntFindClass(Atom,
1080 NULL,
1081 &pi->GlobalClassList,
1082 Link);
1083 if (Class != NULL)
1084 {
1085 goto FoundClass;
1086 }
1087
1088 /* Step 3: try to find any local class registered by user32 */
1089 Class = IntFindClass(Atom,
1090 pi->hModUser,
1091 &pi->LocalClassList,
1092 Link);
1093 if (Class != NULL)
1094 {
1095 goto FoundClass;
1096 }
1097
1098 /* Step 4: try to find any global class registered by user32 */
1099 Class = IntFindClass(Atom,
1100 pi->hModUser,
1101 &pi->GlobalClassList,
1102 Link);
1103 if (Class != NULL)
1104 {
1105 goto FoundClass;
1106 }
1107
1108 /* Step 5: try to find a system class */
1109 Class = IntFindClass(Atom,
1110 NULL,
1111 &pi->SystemClassList,
1112 Link);
1113 if (Class == NULL)
1114 {
1115 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
1116 return (RTL_ATOM)0;
1117 }
1118
1119 FoundClass:
1120 *BaseClass = Class;
1121 }
1122
1123 return Atom;
1124 }
1125
1126 RTL_ATOM
1127 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1128 IN PUNICODE_STRING ClassName,
1129 IN PUNICODE_STRING MenuName,
1130 IN HANDLE hMenu, /* FIXME */
1131 IN WNDPROC wpExtra,
1132 IN DWORD dwFlags)
1133 {
1134 PW32THREADINFO ti;
1135 PW32PROCESSINFO pi;
1136 PWINDOWCLASS Class;
1137 RTL_ATOM ClassAtom;
1138 RTL_ATOM Ret = (RTL_ATOM)0;
1139
1140 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1141
1142 ti = GetW32ThreadInfo();
1143 if (ti == NULL || !ti->kpi->RegisteredSysClasses)
1144 {
1145 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1146 return (RTL_ATOM)0;
1147 }
1148
1149 pi = ti->kpi;
1150
1151 /* try to find a previously registered class */
1152 ClassAtom = IntGetClassAtom(ClassName,
1153 lpwcx->hInstance,
1154 pi,
1155 &Class,
1156 NULL);
1157 if (ClassAtom != (RTL_ATOM)0)
1158 {
1159 if (lpwcx->style & CS_GLOBALCLASS)
1160 {
1161 // global classes shall not have same names as system classes
1162 if (Class->Global || Class->System)
1163 {
1164 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1165 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1166 return (RTL_ATOM)0;
1167 }
1168 }
1169 else if ( !Class->Global && !Class->System)
1170 {
1171 // local class already exists
1172 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1173 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1174 return (RTL_ATOM)0;
1175 }
1176 }
1177
1178 Class = IntCreateClass(lpwcx,
1179 ClassName,
1180 MenuName,
1181 wpExtra,
1182 dwFlags,
1183 ti->Desktop,
1184 pi);
1185
1186 if (Class != NULL)
1187 {
1188 PWINDOWCLASS *List;
1189
1190 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1191 Class->hMenu = hMenu;
1192
1193 /* Register the class */
1194 if (Class->System)
1195 List = &pi->SystemClassList;
1196 else if (Class->Global)
1197 List = &pi->GlobalClassList;
1198 else
1199 List = &pi->LocalClassList;
1200
1201 Class->Next = *List;
1202 (void)InterlockedExchangePointer((PVOID*)List,
1203 Class);
1204
1205 Ret = Class->Atom;
1206 }
1207
1208 return Ret;
1209 }
1210
1211 BOOL
1212 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1213 IN HINSTANCE hInstance)
1214 {
1215 PWINDOWCLASS *Link;
1216 PW32PROCESSINFO pi;
1217 RTL_ATOM ClassAtom;
1218 PWINDOWCLASS Class;
1219
1220 pi = GetW32ProcessInfo();
1221 if (pi == NULL)
1222 {
1223 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1224 return FALSE;
1225 }
1226
1227 TRACE("UserUnregisterClass(%wZ)\n", ClassName);
1228
1229 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1230 ClassAtom = IntGetClassAtom(ClassName,
1231 hInstance,
1232 pi,
1233 &Class,
1234 &Link);
1235 if (ClassAtom == (RTL_ATOM)0)
1236 {
1237 return FALSE;
1238 }
1239
1240 ASSERT(Class != NULL);
1241
1242 if (Class->Windows != 0 ||
1243 Class->Clone != NULL)
1244 {
1245 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
1246 return FALSE;
1247 }
1248
1249 /* must be a base class! */
1250 ASSERT(Class->Base == Class);
1251
1252 /* unlink the class */
1253 *Link = Class->Next;
1254
1255 if (NT_SUCCESS(IntDeregisterClassAtom(Class->Atom)))
1256 {
1257 /* finally free the resources */
1258 IntDestroyClass(Class);
1259 return TRUE;
1260 }
1261 return FALSE;
1262 }
1263
1264 INT
1265 UserGetClassName(IN PWINDOWCLASS Class,
1266 IN OUT PUNICODE_STRING ClassName,
1267 IN BOOL Ansi)
1268 {
1269 NTSTATUS Status = STATUS_SUCCESS;
1270 WCHAR szStaticTemp[32];
1271 PWSTR szTemp = NULL;
1272 ULONG BufLen = sizeof(szStaticTemp);
1273 INT Ret = 0;
1274
1275 /* Note: Accessing the buffer in ClassName may raise an exception! */
1276
1277 _SEH_TRY
1278 {
1279 if (Ansi)
1280 {
1281 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1282 UNICODE_STRING UnicodeClassName;
1283
1284 /* limit the size of the static buffer on the stack to the
1285 size of the buffer provided by the caller */
1286 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1287 {
1288 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1289 }
1290
1291 /* find out how big the buffer needs to be */
1292 Status = RtlQueryAtomInAtomTable(gAtomTable,
1293 Class->Atom,
1294 NULL,
1295 NULL,
1296 szStaticTemp,
1297 &BufLen);
1298 if (Status == STATUS_BUFFER_TOO_SMALL)
1299 {
1300 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1301 {
1302 /* the buffer required exceeds the ansi buffer provided,
1303 pretend like we're using the ansi buffer and limit the
1304 size to the buffer size provided */
1305 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1306 }
1307
1308 /* allocate a temporary buffer that can hold the unicode class name */
1309 szTemp = ExAllocatePool(PagedPool,
1310 BufLen);
1311 if (szTemp == NULL)
1312 {
1313 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1314 _SEH_LEAVE;
1315 }
1316
1317 /* query the class name */
1318 Status = RtlQueryAtomInAtomTable(gAtomTable,
1319 Class->Atom,
1320 NULL,
1321 NULL,
1322 szTemp,
1323 &BufLen);
1324 }
1325 else
1326 szTemp = szStaticTemp;
1327
1328 if (NT_SUCCESS(Status))
1329 {
1330 /* convert the atom name to ansi */
1331
1332 RtlInitUnicodeString(&UnicodeClassName,
1333 szTemp);
1334
1335 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1336 &UnicodeClassName,
1337 FALSE);
1338 if (!NT_SUCCESS(Status))
1339 {
1340 SetLastNtError(Status);
1341 _SEH_LEAVE;
1342 }
1343 }
1344
1345 Ret = BufLen / sizeof(WCHAR);
1346 }
1347 else /* !Ansi */
1348 {
1349 BufLen = ClassName->MaximumLength;
1350
1351 /* query the atom name */
1352 Status = RtlQueryAtomInAtomTable(gAtomTable,
1353 Class->Atom,
1354 NULL,
1355 NULL,
1356 ClassName->Buffer,
1357 &BufLen);
1358
1359 if (!NT_SUCCESS(Status))
1360 {
1361 SetLastNtError(Status);
1362 _SEH_LEAVE;
1363 }
1364
1365 Ret = BufLen / sizeof(WCHAR);
1366 }
1367 }
1368 _SEH_HANDLE
1369 {
1370 SetLastNtError(_SEH_GetExceptionCode());
1371 }
1372 _SEH_END;
1373
1374 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1375 {
1376 ExFreePool(szTemp);
1377 }
1378
1379 return Ret;
1380 }
1381
1382 ULONG_PTR
1383 UserGetClassLongPtr(IN PWINDOWCLASS Class,
1384 IN INT Index,
1385 IN BOOL Ansi)
1386 {
1387 ULONG_PTR Ret = 0;
1388
1389 if (Index >= 0)
1390 {
1391 PULONG_PTR Data;
1392
1393 TRACE("GetClassLong(%d)\n", Index);
1394 if (Index + sizeof(ULONG_PTR) < Index ||
1395 Index + sizeof(ULONG_PTR) > Class->ClsExtra)
1396 {
1397 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1398 return 0;
1399 }
1400
1401 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1402
1403 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1404 certain architectures, maybe using RtlCopyMemory is a
1405 better choice for those architectures! */
1406
1407 TRACE("Result: %x\n", Ret);
1408 return *Data;
1409 }
1410
1411 switch (Index)
1412 {
1413 case GCL_CBWNDEXTRA:
1414 Ret = (ULONG_PTR)Class->WndExtra;
1415 break;
1416
1417 case GCL_CBCLSEXTRA:
1418 Ret = (ULONG_PTR)Class->ClsExtra;
1419 break;
1420
1421 case GCLP_HBRBACKGROUND:
1422 Ret = (ULONG_PTR)Class->hbrBackground;
1423 break;
1424
1425 case GCLP_HCURSOR:
1426 /* FIXME - get handle from pointer to CURSOR object */
1427 Ret = (ULONG_PTR)Class->hCursor;
1428 break;
1429
1430 case GCLP_HICON:
1431 /* FIXME - get handle from pointer to ICON object */
1432 Ret = (ULONG_PTR)Class->hIcon;
1433 break;
1434
1435 case GCLP_HICONSM:
1436 /* FIXME - get handle from pointer to ICON object */
1437 Ret = (ULONG_PTR)Class->hIconSm;
1438 break;
1439
1440 case GCLP_HMODULE:
1441 Ret = (ULONG_PTR)Class->hInstance;
1442 break;
1443
1444 case GCLP_MENUNAME:
1445 /* NOTE: Returns pointer in kernel heap! */
1446 if (Ansi)
1447 Ret = (ULONG_PTR)Class->AnsiMenuName;
1448 else
1449 Ret = (ULONG_PTR)Class->MenuName;
1450 break;
1451
1452 case GCL_STYLE:
1453 Ret = (ULONG_PTR)Class->Style;
1454 break;
1455
1456 case GCLP_WNDPROC:
1457 Ret = (ULONG_PTR)IntGetClassWndProc(Class,
1458 GetW32ProcessInfo(),
1459 Ansi);
1460 break;
1461
1462 case GCW_ATOM:
1463 Ret = (ULONG_PTR)Class->Atom;
1464 break;
1465
1466 default:
1467 SetLastWin32Error(ERROR_INVALID_INDEX);
1468 break;
1469 }
1470
1471 return Ret;
1472 }
1473
1474 static BOOL
1475 IntSetClassMenuName(IN PWINDOWCLASS Class,
1476 IN PUNICODE_STRING MenuName)
1477 {
1478 BOOL Ret = FALSE;
1479
1480 /* change the base class first */
1481 Class = Class->Base;
1482
1483 if (MenuName->Length != 0)
1484 {
1485 ANSI_STRING AnsiString;
1486 PWSTR strBufW;
1487
1488 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
1489
1490 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1491 AnsiString.MaximumLength);
1492 if (strBufW != NULL)
1493 {
1494 _SEH_TRY
1495 {
1496 NTSTATUS Status;
1497
1498 /* copy the unicode string */
1499 RtlCopyMemory(strBufW,
1500 MenuName->Buffer,
1501 MenuName->Length);
1502 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1503
1504 /* create an ansi copy of the string */
1505 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1506 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1507 MenuName,
1508 FALSE);
1509 if (!NT_SUCCESS(Status))
1510 {
1511 SetLastNtError(Status);
1512 _SEH_LEAVE;
1513 }
1514
1515 Ret = TRUE;
1516 }
1517 _SEH_HANDLE
1518 {
1519 SetLastNtError(_SEH_GetExceptionCode());
1520 }
1521 _SEH_END;
1522
1523 if (Ret)
1524 {
1525 /* update the base class */
1526 IntFreeClassMenuName(Class);
1527 Class->MenuName = strBufW;
1528 Class->AnsiMenuName = AnsiString.Buffer;
1529 Class->MenuNameIsString = TRUE;
1530
1531 /* update the clones */
1532 Class = Class->Clone;
1533 while (Class != NULL)
1534 {
1535 Class->MenuName = strBufW;
1536 Class->AnsiMenuName = AnsiString.Buffer;
1537 Class->MenuNameIsString = TRUE;
1538
1539 Class = Class->Next;
1540 }
1541 }
1542 else
1543 {
1544 DPRINT1("Failed to copy class menu name!\n");
1545 UserHeapFree(strBufW);
1546 }
1547 }
1548 else
1549 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1550 }
1551 else
1552 {
1553 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1554
1555 /* update the base class */
1556 IntFreeClassMenuName(Class);
1557 Class->MenuName = MenuName->Buffer;
1558 Class->AnsiMenuName = (PSTR)MenuName->Buffer;
1559 Class->MenuNameIsString = FALSE;
1560
1561 /* update the clones */
1562 Class = Class->Clone;
1563 while (Class != NULL)
1564 {
1565 Class->MenuName = MenuName->Buffer;
1566 Class->AnsiMenuName = (PSTR)MenuName->Buffer;
1567 Class->MenuNameIsString = FALSE;
1568
1569 Class = Class->Next;
1570 }
1571
1572 Ret = TRUE;
1573 }
1574
1575 return Ret;
1576 }
1577
1578 ULONG_PTR
1579 UserSetClassLongPtr(IN PWINDOWCLASS Class,
1580 IN INT Index,
1581 IN ULONG_PTR NewLong,
1582 IN BOOL Ansi)
1583 {
1584 ULONG_PTR Ret = 0;
1585
1586 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1587
1588 /* change the information in the base class first, then update the clones */
1589 Class = Class->Base;
1590
1591 if (Index >= 0)
1592 {
1593 PULONG_PTR Data;
1594
1595 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1596
1597 if (Index + sizeof(ULONG_PTR) < Index ||
1598 Index + sizeof(ULONG_PTR) > Class->ClsExtra)
1599 {
1600 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1601 return 0;
1602 }
1603
1604 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1605
1606 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1607 certain architectures, maybe using RtlCopyMemory is a
1608 better choice for those architectures! */
1609 Ret = *Data;
1610 *Data = NewLong;
1611
1612 /* update the clones */
1613 Class = Class->Clone;
1614 while (Class != NULL)
1615 {
1616 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1617 Class = Class->Next;
1618 }
1619
1620 return Ret;
1621 }
1622
1623 switch (Index)
1624 {
1625 case GCL_CBWNDEXTRA:
1626 Ret = (ULONG_PTR)Class->WndExtra;
1627 Class->WndExtra = (INT)NewLong;
1628
1629 /* update the clones */
1630 Class = Class->Clone;
1631 while (Class != NULL)
1632 {
1633 Class->WndExtra = (INT)NewLong;
1634 Class = Class->Next;
1635 }
1636
1637 break;
1638
1639 case GCL_CBCLSEXTRA:
1640 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1641 break;
1642
1643 case GCLP_HBRBACKGROUND:
1644 Ret = (ULONG_PTR)Class->hbrBackground;
1645 Class->hbrBackground = (HBRUSH)NewLong;
1646
1647 /* update the clones */
1648 Class = Class->Clone;
1649 while (Class != NULL)
1650 {
1651 Class->hbrBackground = (HBRUSH)NewLong;
1652 Class = Class->Next;
1653 }
1654 break;
1655
1656 case GCLP_HCURSOR:
1657 /* FIXME - get handle from pointer to CURSOR object */
1658 Ret = (ULONG_PTR)Class->hCursor;
1659 Class->hCursor = (HANDLE)NewLong;
1660
1661 /* update the clones */
1662 Class = Class->Clone;
1663 while (Class != NULL)
1664 {
1665 Class->hCursor = (HANDLE)NewLong;
1666 Class = Class->Next;
1667 }
1668 break;
1669
1670 case GCLP_HICON:
1671 /* FIXME - get handle from pointer to ICON object */
1672 Ret = (ULONG_PTR)Class->hIcon;
1673 Class->hIcon = (HANDLE)NewLong;
1674
1675 /* update the clones */
1676 Class = Class->Clone;
1677 while (Class != NULL)
1678 {
1679 Class->hIcon = (HANDLE)NewLong;
1680 Class = Class->Next;
1681 }
1682 break;
1683
1684 case GCLP_HICONSM:
1685 /* FIXME - get handle from pointer to ICON object */
1686 Ret = (ULONG_PTR)Class->hIconSm;
1687 Class->hIconSm = (HANDLE)NewLong;
1688
1689 /* update the clones */
1690 Class = Class->Clone;
1691 while (Class != NULL)
1692 {
1693 Class->hIconSm = (HANDLE)NewLong;
1694 Class = Class->Next;
1695 }
1696 break;
1697
1698 case GCLP_HMODULE:
1699 Ret = (ULONG_PTR)Class->hInstance;
1700 Class->hInstance = (HINSTANCE)NewLong;
1701
1702 /* update the clones */
1703 Class = Class->Clone;
1704 while (Class != NULL)
1705 {
1706 Class->hInstance = (HINSTANCE)NewLong;
1707 Class = Class->Next;
1708 }
1709 break;
1710
1711 case GCLP_MENUNAME:
1712 {
1713 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1714
1715 if (!IntSetClassMenuName(Class,
1716 Value))
1717 {
1718 DPRINT("Setting the class menu name failed!\n");
1719 }
1720
1721 /* FIXME - really return NULL? Wine does so... */
1722 break;
1723 }
1724
1725 case GCL_STYLE:
1726 Ret = (ULONG_PTR)Class->Style;
1727 Class->Style = (UINT)NewLong;
1728
1729 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1730 move the class to the appropriate list? For now, we save
1731 the original value in Class->Global, so we can always
1732 locate the appropriate list */
1733
1734 /* update the clones */
1735 Class = Class->Clone;
1736 while (Class != NULL)
1737 {
1738 Class->Style = (UINT)NewLong;
1739 Class = Class->Next;
1740 }
1741 break;
1742
1743 case GCLP_WNDPROC:
1744 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1745 (WNDPROC)NewLong,
1746 Ansi);
1747 break;
1748
1749 case GCW_ATOM:
1750 {
1751 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1752
1753 Ret = (ULONG_PTR)Class->Atom;
1754 if (!IntSetClassAtom(Class,
1755 Value))
1756 {
1757 Ret = 0;
1758 }
1759 break;
1760 }
1761
1762 default:
1763 SetLastWin32Error(ERROR_INVALID_INDEX);
1764 break;
1765 }
1766
1767 return Ret;
1768 }
1769
1770 static BOOL
1771 UserGetClassInfo(IN PWINDOWCLASS Class,
1772 OUT PWNDCLASSEXW lpwcx,
1773 IN BOOL Ansi,
1774 HINSTANCE hInstance)
1775 {
1776 PW32PROCESSINFO pi;
1777
1778 lpwcx->style = Class->Style;
1779
1780 pi = GetW32ProcessInfo();
1781 lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
1782 pi,
1783 Ansi);
1784
1785 lpwcx->cbClsExtra = Class->ClsExtra;
1786 lpwcx->cbWndExtra = Class->WndExtra;
1787 lpwcx->hIcon = Class->hIcon; /* FIXME - get handle from pointer */
1788 lpwcx->hCursor = Class->hCursor; /* FIXME - get handle from pointer */
1789 lpwcx->hbrBackground = Class->hbrBackground;
1790
1791 if (Ansi)
1792 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->AnsiMenuName;
1793 else
1794 lpwcx->lpszMenuName = Class->MenuName;
1795
1796 if (Class->hInstance == pi->hModUser)
1797 lpwcx->hInstance = NULL;
1798 else
1799 lpwcx->hInstance = Class->hInstance;
1800
1801 lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->Atom); /* FIXME - return the string? */
1802
1803 lpwcx->hIconSm = Class->hIconSm; /* FIXME - get handle from pointer */
1804
1805 return TRUE;
1806 }
1807
1808 BOOL
1809 UserRegisterSystemClasses(IN ULONG Count,
1810 IN PREGISTER_SYSCLASS SystemClasses)
1811 {
1812 /* NOTE: This routine may raise exceptions! */
1813 UINT i;
1814 UNICODE_STRING ClassName, MenuName;
1815 PW32PROCESSINFO pi = GetW32ProcessInfo();
1816 WNDCLASSEXW wc;
1817 PWINDOWCLASS Class;
1818 BOOL Ret = TRUE;
1819
1820 if (pi->RegisteredSysClasses || pi->hModUser == NULL)
1821 return FALSE;
1822
1823 RtlZeroMemory(&MenuName, sizeof(MenuName));
1824
1825 for (i = 0; i != Count; i++)
1826 {
1827 ClassName = ProbeForReadUnicodeString(&SystemClasses[i].ClassName);
1828 if (ClassName.Length != 0)
1829 {
1830 ProbeForRead(ClassName.Buffer,
1831 ClassName.Length,
1832 sizeof(WCHAR));
1833 }
1834
1835 wc.cbSize = sizeof(wc);
1836 wc.style = SystemClasses[i].Style;
1837 wc.lpfnWndProc = SystemClasses[i].ProcW;
1838 wc.cbClsExtra = 0;
1839 wc.cbWndExtra = SystemClasses[i].ExtraBytes;
1840 wc.hInstance = pi->hModUser;
1841 wc.hIcon = NULL;
1842 wc.hCursor = SystemClasses[i].hCursor;
1843 wc.hbrBackground = SystemClasses[i].hBrush;
1844 wc.lpszMenuName = NULL;
1845 wc.lpszClassName = ClassName.Buffer;
1846 wc.hIconSm = NULL;
1847
1848 Class = IntCreateClass(&wc,
1849 &ClassName,
1850 &MenuName,
1851 SystemClasses[i].ProcA,
1852 REGISTERCLASS_SYSTEM,
1853 NULL,
1854 pi);
1855 if (Class != NULL)
1856 {
1857 Class->fnID = SystemClasses[i].ClassId;
1858
1859 ASSERT(Class->System);
1860 Class->Next = pi->SystemClassList;
1861 (void)InterlockedExchangePointer((PVOID*)&pi->SystemClassList,
1862 Class);
1863 }
1864 else
1865 {
1866 WARN("!!! Registering system class failed!\n");
1867 Ret = FALSE;
1868 }
1869 }
1870
1871 if (Ret)
1872 pi->RegisteredSysClasses = TRUE;
1873 return Ret;
1874 }
1875
1876 /* SYSCALLS *****************************************************************/
1877
1878
1879 RTL_ATOM NTAPI
1880 NtUserRegisterClassEx(IN CONST WNDCLASSEXW* lpwcx,
1881 IN PUNICODE_STRING ClassName,
1882 IN PUNICODE_STRING MenuName,
1883 IN WNDPROC wpExtra,
1884 IN DWORD Flags,
1885 IN HMENU hMenu)
1886
1887 /*
1888 * FUNCTION:
1889 * Registers a new class with the window manager
1890 * ARGUMENTS:
1891 * lpwcx = Win32 extended window class structure
1892 * bUnicodeClass = Whether to send ANSI or unicode strings
1893 * to window procedures
1894 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1895 * RETURNS:
1896 * Atom identifying the new class
1897 */
1898 {
1899 WNDCLASSEXW CapturedClassInfo = {0};
1900 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
1901 RTL_ATOM Ret = (RTL_ATOM)0;
1902
1903 if (Flags & ~REGISTERCLASS_ALL)
1904 {
1905 SetLastWin32Error(ERROR_INVALID_FLAGS);
1906 return Ret;
1907 }
1908
1909 UserEnterExclusive();
1910
1911 _SEH_TRY
1912 {
1913 /* Probe the parameters and basic parameter checks */
1914 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
1915 {
1916 goto InvalidParameter;
1917 }
1918
1919 ProbeForRead(lpwcx,
1920 sizeof(WNDCLASSEXW),
1921 sizeof(ULONG));
1922 RtlCopyMemory(&CapturedClassInfo,
1923 lpwcx,
1924 sizeof(WNDCLASSEXW));
1925
1926 CapturedName = ProbeForReadUnicodeString(ClassName);
1927 CapturedMenuName = ProbeForReadUnicodeString(MenuName);
1928
1929 if (CapturedName.Length & 1 || CapturedMenuName.Length & 1 ||
1930 CapturedClassInfo.cbClsExtra < 0 ||
1931 CapturedClassInfo.cbClsExtra + CapturedName.Length +
1932 CapturedMenuName.Length + sizeof(WINDOWCLASS) < CapturedClassInfo.cbClsExtra ||
1933 CapturedClassInfo.cbWndExtra < 0 ||
1934 CapturedClassInfo.hInstance == NULL)
1935 {
1936 goto InvalidParameter;
1937 }
1938
1939 if (CapturedName.Length != 0)
1940 {
1941 ProbeForRead(CapturedName.Buffer,
1942 CapturedName.Length,
1943 sizeof(WCHAR));
1944 }
1945 else
1946 {
1947 if (!IS_ATOM(CapturedName.Buffer))
1948 {
1949 goto InvalidParameter;
1950 }
1951 }
1952
1953 if (CapturedMenuName.Length != 0)
1954 {
1955 ProbeForRead(CapturedMenuName.Buffer,
1956 CapturedMenuName.Length,
1957 sizeof(WCHAR));
1958 }
1959 else if (CapturedMenuName.Buffer != NULL &&
1960 !IS_INTRESOURCE(CapturedMenuName.Buffer))
1961 {
1962 InvalidParameter:
1963 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1964 _SEH_LEAVE;
1965 }
1966
1967 /* Register the class */
1968 Ret = UserRegisterClass(&CapturedClassInfo,
1969 &CapturedName,
1970 &CapturedMenuName,
1971 hMenu, /* FIXME - pass pointer */
1972 wpExtra,
1973 Flags);
1974
1975 }
1976 _SEH_HANDLE
1977 {
1978 SetLastNtError(_SEH_GetExceptionCode());
1979 }
1980 _SEH_END;
1981
1982 UserLeave();
1983
1984 return Ret;
1985 }
1986
1987
1988 RTL_ATOM
1989 NTAPI
1990 NtUserRegisterClassExWOW(
1991 WNDCLASSEXW* lpwcx,
1992 PUNICODE_STRING ClassName,
1993 PUNICODE_STRING ClsNVersion,
1994 PCLSMENUNAME pClassMenuName,
1995 DWORD fnID,
1996 DWORD Flags,
1997 LPDWORD pWow)
1998 {
1999 WNDCLASSEXW CapturedClassInfo = {0};
2000 UNICODE_STRING CapturedName = {0}, ClassnametoVersion = {0};
2001 RTL_ATOM Ret = (RTL_ATOM)0;
2002
2003 UserEnterExclusive();
2004
2005 _SEH_TRY
2006 {
2007 /* Probe the parameters and basic parameter checks */
2008 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2009 {
2010 goto InvalidParameter;
2011 }
2012 if (!pClassMenuName)
2013 {
2014 goto InvalidParameter;
2015 }
2016
2017 ProbeForRead(lpwcx,
2018 sizeof(WNDCLASSEXW),
2019 sizeof(ULONG));
2020 RtlCopyMemory(&CapturedClassInfo,
2021 lpwcx,
2022 sizeof(WNDCLASSEXW));
2023 /*
2024 Need to watch this. When UnregisterClass is called these pointers
2025 are freed by the caller in user space. So, we just probe the data
2026 for now and pass it on and copy it to the shared class structure.
2027 */
2028 ProbeForRead(pClassMenuName,
2029 sizeof(CLSMENUNAME),
2030 sizeof(ULONG));
2031
2032 CapturedName = ProbeForReadUnicodeString(ClassName);
2033 ClassnametoVersion = ProbeForReadUnicodeString(ClsNVersion);
2034
2035 if (CapturedName.Length & 1 || ClassnametoVersion.Length & 1 ||
2036 CapturedClassInfo.cbClsExtra < 0 ||
2037 CapturedClassInfo.cbClsExtra + CapturedName.Length +
2038 ClassnametoVersion.Length + sizeof(WINDOWCLASS) < CapturedClassInfo.cbClsExtra ||
2039 CapturedClassInfo.cbWndExtra < 0 ||
2040 CapturedClassInfo.hInstance == NULL)
2041 {
2042 goto InvalidParameter;
2043 }
2044
2045 if (CapturedName.Length != 0)
2046 {
2047 ProbeForRead(CapturedName.Buffer,
2048 CapturedName.Length,
2049 sizeof(WCHAR));
2050 }
2051 else
2052 {
2053 if (!IS_ATOM(CapturedName.Buffer))
2054 {
2055 goto InvalidParameter;
2056 }
2057 }
2058
2059 if (ClassnametoVersion.Length != 0)
2060 {
2061 ProbeForRead(ClassnametoVersion.Buffer,
2062 ClassnametoVersion.Length,
2063 sizeof(WCHAR));
2064 }
2065 else if (ClassnametoVersion.Buffer != NULL &&
2066 !IS_INTRESOURCE(ClassnametoVersion.Buffer))
2067 {
2068 InvalidParameter:
2069 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2070 _SEH_LEAVE;
2071 }
2072
2073 /* Register the class */
2074 // Ret = UserRegisterClass(&CapturedClassInfo,
2075 // &CapturedName,
2076 // &ClassnametoVersion,
2077 // hMenu, /* FIXME - pass pointer */
2078 // wpExtra,
2079 // Flags);
2080
2081 }
2082 _SEH_HANDLE
2083 {
2084 SetLastNtError(_SEH_GetExceptionCode());
2085 }
2086 _SEH_END;
2087
2088 UserLeave();
2089
2090 return Ret;
2091 }
2092
2093
2094 ULONG_PTR NTAPI
2095 NtUserGetClassLong(IN HWND hWnd,
2096 IN INT Offset,
2097 IN BOOL Ansi)
2098 {
2099 PWINDOW_OBJECT Window;
2100 ULONG_PTR Ret = 0;
2101
2102 if (Offset != GCLP_WNDPROC)
2103 {
2104 UserEnterShared();
2105 }
2106 else
2107 {
2108 UserEnterExclusive();
2109 }
2110
2111 Window = UserGetWindowObject(hWnd);
2112 if (Window != NULL)
2113 {
2114 Ret = UserGetClassLongPtr(Window->Wnd->Class,
2115 Offset,
2116 Ansi);
2117
2118 if (Ret != 0 && Offset == GCLP_MENUNAME && Window->Wnd->Class->MenuNameIsString)
2119 {
2120 Ret = (ULONG_PTR)UserHeapAddressToUser((PVOID)Ret);
2121 }
2122 }
2123
2124 UserLeave();
2125
2126 return Ret;
2127 }
2128
2129
2130
2131 ULONG_PTR STDCALL
2132 NtUserSetClassLong(HWND hWnd,
2133 INT Offset,
2134 ULONG_PTR dwNewLong,
2135 BOOL Ansi)
2136 {
2137 PW32PROCESSINFO pi;
2138 PWINDOW_OBJECT Window;
2139 ULONG_PTR Ret = 0;
2140
2141 UserEnterExclusive();
2142
2143 pi = GetW32ProcessInfo();
2144 if (pi == NULL)
2145 goto Cleanup;
2146
2147 Window = UserGetWindowObject(hWnd);
2148 if (Window != NULL)
2149 {
2150 if (Window->ti->kpi != pi)
2151 {
2152 SetLastWin32Error(ERROR_ACCESS_DENIED);
2153 goto Cleanup;
2154 }
2155
2156 _SEH_TRY
2157 {
2158 UNICODE_STRING Value;
2159
2160 /* probe the parameters */
2161 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2162 {
2163 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2164 if (Value.Length & 1)
2165 {
2166 goto InvalidParameter;
2167 }
2168
2169 if (Value.Length != 0)
2170 {
2171 ProbeForRead(Value.Buffer,
2172 Value.Length,
2173 sizeof(WCHAR));
2174 }
2175 else
2176 {
2177 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2178 {
2179 goto InvalidParameter;
2180 }
2181 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2182 {
2183 InvalidParameter:
2184 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2185 _SEH_LEAVE;
2186 }
2187 }
2188
2189 dwNewLong = (ULONG_PTR)&Value;
2190 }
2191
2192 Ret = UserSetClassLongPtr(Window->Wnd->Class,
2193 Offset,
2194 dwNewLong,
2195 Ansi);
2196 }
2197 _SEH_HANDLE
2198 {
2199 SetLastNtError(_SEH_GetExceptionCode());
2200 }
2201 _SEH_END;
2202 }
2203
2204 Cleanup:
2205 UserLeave();
2206
2207 return Ret;
2208 }
2209
2210 WORD
2211 STDCALL
2212 NtUserSetClassWord(
2213 HWND hWnd,
2214 INT nIndex,
2215 WORD wNewWord)
2216 {
2217 return(0);
2218 }
2219
2220 BOOL NTAPI
2221 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2222 IN HINSTANCE hInstance,
2223 OUT PCLSMENUNAME pClassMenuName)
2224 {
2225 UNICODE_STRING CapturedClassName;
2226 BOOL Ret = FALSE;
2227
2228 UserEnterExclusive();
2229
2230 _SEH_TRY
2231 {
2232 /* probe the paramters */
2233 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2234 if (CapturedClassName.Length & 1)
2235 {
2236 goto InvalidParameter;
2237 }
2238
2239 if (CapturedClassName.Length != 0)
2240 {
2241 ProbeForRead(CapturedClassName.Buffer,
2242 CapturedClassName.Length,
2243 sizeof(WCHAR));
2244 }
2245 else
2246 {
2247 if (!IS_ATOM(CapturedClassName.Buffer))
2248 {
2249 InvalidParameter:
2250 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2251 _SEH_LEAVE;
2252 }
2253 }
2254
2255 /* unregister the class */
2256 Ret = UserUnregisterClass(&CapturedClassName,
2257 hInstance);
2258 }
2259 _SEH_HANDLE
2260 {
2261 SetLastNtError(_SEH_GetExceptionCode());
2262 }
2263 _SEH_END;
2264
2265 UserLeave();
2266
2267 return Ret;
2268 }
2269
2270 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2271 BOOL STDCALL
2272 NtUserGetClassInfo(
2273 HINSTANCE hInstance,
2274 PUNICODE_STRING ClassName,
2275 LPWNDCLASSEXW lpWndClassEx,
2276 LPWSTR *ppszMenuName,
2277 BOOL Ansi)
2278 {
2279 UNICODE_STRING CapturedClassName;
2280 PWINDOWCLASS Class;
2281 RTL_ATOM ClassAtom;
2282 PW32PROCESSINFO pi;
2283 BOOL Ret = FALSE;
2284
2285 /* NOTE: need exclusive lock because getting the wndproc might require the
2286 creation of a call procedure handle */
2287 UserEnterExclusive();
2288
2289 pi = GetW32ProcessInfo();
2290 if (pi == NULL)
2291 {
2292 ERR("GetW32ProcessInfo() returned NULL!\n");
2293 goto Cleanup;
2294 }
2295 _SEH_TRY
2296 {
2297 /* probe the paramters */
2298 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2299
2300 if (CapturedClassName.Length == 0)
2301 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2302 else
2303 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2304
2305 if (CapturedClassName.Length & 1)
2306 {
2307 goto InvalidParameter;
2308 }
2309
2310 if (CapturedClassName.Length != 0)
2311 {
2312 ProbeForRead(CapturedClassName.Buffer,
2313 CapturedClassName.Length,
2314 sizeof(WCHAR));
2315 }
2316 else
2317 {
2318 if (!IS_ATOM(CapturedClassName.Buffer))
2319 {
2320 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2321 goto InvalidParameter;
2322 }
2323 }
2324
2325 if (ProbeForReadUint(&lpWndClassEx->cbSize) != sizeof(WNDCLASSEXW))
2326 {
2327 InvalidParameter:
2328 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2329 _SEH_LEAVE;
2330 }
2331
2332 ProbeForWrite(lpWndClassEx,
2333 sizeof(WNDCLASSEXW),
2334 sizeof(ULONG));
2335
2336 ClassAtom = IntGetClassAtom(&CapturedClassName,
2337 hInstance,
2338 pi,
2339 &Class,
2340 NULL);
2341 if (ClassAtom != (RTL_ATOM)0)
2342 {
2343 if (hInstance == NULL)
2344 hInstance = pi->hModUser;
2345
2346 Ret = UserGetClassInfo(Class,
2347 lpWndClassEx,
2348 Ansi,
2349 hInstance);
2350
2351 if (Ret)
2352 {
2353 lpWndClassEx->lpszClassName = CapturedClassName.Buffer;
2354 /* FIXME - handle Class->Desktop == NULL!!!!! */
2355
2356 if (Class->MenuName != NULL && Class->MenuNameIsString)
2357 {
2358 lpWndClassEx->lpszMenuName = UserHeapAddressToUser(Ansi ?
2359 (PVOID)Class->AnsiMenuName :
2360 (PVOID)Class->MenuName);
2361 }
2362
2363 /* Undocumented behavior! Return the class atom as a BOOL! */
2364 Ret = (BOOL)ClassAtom;
2365 }
2366 }
2367 else
2368 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2369 }
2370 _SEH_HANDLE
2371 {
2372 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2373 }
2374 _SEH_END;
2375
2376 Cleanup:
2377 UserLeave();
2378 return Ret;
2379 }
2380
2381
2382
2383 INT NTAPI
2384 NtUserGetClassName (IN HWND hWnd,
2385 OUT PUNICODE_STRING ClassName,
2386 IN BOOL Ansi)
2387 {
2388 PWINDOW_OBJECT Window;
2389 UNICODE_STRING CapturedClassName;
2390 INT Ret = 0;
2391
2392 UserEnterShared();
2393
2394 Window = UserGetWindowObject(hWnd);
2395 if (Window != NULL)
2396 {
2397 _SEH_TRY
2398 {
2399 ProbeForWriteUnicodeString(ClassName);
2400 CapturedClassName = *ClassName;
2401
2402 /* get the class name */
2403 Ret = UserGetClassName(Window->Wnd->Class,
2404 &CapturedClassName,
2405 Ansi);
2406
2407 if (Ret != 0)
2408 {
2409 /* update the Length field */
2410 ClassName->Length = CapturedClassName.Length;
2411 }
2412 }
2413 _SEH_HANDLE
2414 {
2415 SetLastNtError(_SEH_GetExceptionCode());
2416 }
2417 _SEH_END;
2418 }
2419
2420 UserLeave();
2421
2422 return Ret;
2423 }
2424
2425 DWORD STDCALL
2426 NtUserGetWOWClass(DWORD Unknown0,
2427 DWORD Unknown1)
2428 {
2429 return(0);
2430 }
2431
2432 /* EOF */