Add -Wno-format to dmusic
[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->rpdeskParent != NULL)
89 {
90 DesktopHeapFree(Class->rpdeskParent,
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 PPROCESSINFO pi = (PPROCESSINFO)Process;
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 PPROCESSINFO 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->rpdeskParent == 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->rpdeskParent == 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->rpdeskParent == 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->rpdeskParent = Desktop;
461 Class->Windows = 0;
462
463 if (BaseClass->rpdeskParent == 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->rpdeskParent != NULL);
532 ASSERT(Class->Windows != 0);
533 ASSERT(Class->Base->rpdeskParent != 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 PDESKTOPINFO Desktop,
567 IN PPROCESSINFO 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->rpdeskParent != 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->rpdeskParent = 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->rpdeskParent == 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 PPROCESSINFO 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 PPROCESSINFO 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->rpdeskParent = 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 _SEH2_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 _SEH2_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 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
914 {
915 Status = _SEH2_GetExceptionCode();
916 }
917 _SEH2_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 PPROCESSINFO 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 PTHREADINFO pti;
1135 PW32THREADINFO ti;
1136 PPROCESSINFO pi;
1137 PWINDOWCLASS Class;
1138 RTL_ATOM ClassAtom;
1139 RTL_ATOM Ret = (RTL_ATOM)0;
1140
1141 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1142
1143 pti = PsGetCurrentThreadWin32Thread();
1144 ti = GetW32ThreadInfo();
1145 if (ti == NULL || !ti->ppi->RegisteredSysClasses)
1146 {
1147 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1148 return (RTL_ATOM)0;
1149 }
1150
1151 pi = ti->ppi;
1152
1153 /* try to find a previously registered class */
1154 ClassAtom = IntGetClassAtom(ClassName,
1155 lpwcx->hInstance,
1156 pi,
1157 &Class,
1158 NULL);
1159 if (ClassAtom != (RTL_ATOM)0)
1160 {
1161 if (lpwcx->style & CS_GLOBALCLASS)
1162 {
1163 // global classes shall not have same names as system classes
1164 if (Class->Global || Class->System)
1165 {
1166 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1167 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1168 return (RTL_ATOM)0;
1169 }
1170 }
1171 else if ( !Class->Global && !Class->System)
1172 {
1173 // local class already exists
1174 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1175 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1176 return (RTL_ATOM)0;
1177 }
1178 }
1179
1180 Class = IntCreateClass(lpwcx,
1181 ClassName,
1182 MenuName,
1183 wpExtra,
1184 dwFlags,
1185 pti->Desktop,
1186 pi);
1187
1188 if (Class != NULL)
1189 {
1190 PWINDOWCLASS *List;
1191
1192 /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
1193 Class->hMenu = hMenu;
1194
1195 /* Register the class */
1196 if (Class->System)
1197 List = &pi->SystemClassList;
1198 else if (Class->Global)
1199 List = &pi->GlobalClassList;
1200 else
1201 List = &pi->LocalClassList;
1202
1203 Class->Next = *List;
1204 (void)InterlockedExchangePointer((PVOID*)List,
1205 Class);
1206
1207 Ret = Class->Atom;
1208 }
1209
1210 return Ret;
1211 }
1212
1213 BOOL
1214 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1215 IN HINSTANCE hInstance)
1216 {
1217 PWINDOWCLASS *Link;
1218 PPROCESSINFO pi;
1219 RTL_ATOM ClassAtom;
1220 PWINDOWCLASS Class;
1221
1222 pi = GetW32ProcessInfo();
1223 if (pi == NULL)
1224 {
1225 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1226 return FALSE;
1227 }
1228
1229 TRACE("UserUnregisterClass(%wZ)\n", ClassName);
1230
1231 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1232 ClassAtom = IntGetClassAtom(ClassName,
1233 hInstance,
1234 pi,
1235 &Class,
1236 &Link);
1237 if (ClassAtom == (RTL_ATOM)0)
1238 {
1239 return FALSE;
1240 }
1241
1242 ASSERT(Class != NULL);
1243
1244 if (Class->Windows != 0 ||
1245 Class->Clone != NULL)
1246 {
1247 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
1248 return FALSE;
1249 }
1250
1251 /* must be a base class! */
1252 ASSERT(Class->Base == Class);
1253
1254 /* unlink the class */
1255 *Link = Class->Next;
1256
1257 if (NT_SUCCESS(IntDeregisterClassAtom(Class->Atom)))
1258 {
1259 /* finally free the resources */
1260 IntDestroyClass(Class);
1261 return TRUE;
1262 }
1263 return FALSE;
1264 }
1265
1266 INT
1267 UserGetClassName(IN PWINDOWCLASS Class,
1268 IN OUT PUNICODE_STRING ClassName,
1269 IN BOOL Ansi)
1270 {
1271 NTSTATUS Status = STATUS_SUCCESS;
1272 WCHAR szStaticTemp[32];
1273 PWSTR szTemp = NULL;
1274 ULONG BufLen = sizeof(szStaticTemp);
1275 INT Ret = 0;
1276
1277 /* Note: Accessing the buffer in ClassName may raise an exception! */
1278
1279 _SEH2_TRY
1280 {
1281 if (Ansi)
1282 {
1283 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1284 UNICODE_STRING UnicodeClassName;
1285
1286 /* limit the size of the static buffer on the stack to the
1287 size of the buffer provided by the caller */
1288 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1289 {
1290 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1291 }
1292
1293 /* find out how big the buffer needs to be */
1294 Status = RtlQueryAtomInAtomTable(gAtomTable,
1295 Class->Atom,
1296 NULL,
1297 NULL,
1298 szStaticTemp,
1299 &BufLen);
1300 if (Status == STATUS_BUFFER_TOO_SMALL)
1301 {
1302 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1303 {
1304 /* the buffer required exceeds the ansi buffer provided,
1305 pretend like we're using the ansi buffer and limit the
1306 size to the buffer size provided */
1307 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1308 }
1309
1310 /* allocate a temporary buffer that can hold the unicode class name */
1311 szTemp = ExAllocatePool(PagedPool,
1312 BufLen);
1313 if (szTemp == NULL)
1314 {
1315 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1316 _SEH2_LEAVE;
1317 }
1318
1319 /* query the class name */
1320 Status = RtlQueryAtomInAtomTable(gAtomTable,
1321 Class->Atom,
1322 NULL,
1323 NULL,
1324 szTemp,
1325 &BufLen);
1326 }
1327 else
1328 szTemp = szStaticTemp;
1329
1330 if (NT_SUCCESS(Status))
1331 {
1332 /* convert the atom name to ansi */
1333
1334 RtlInitUnicodeString(&UnicodeClassName,
1335 szTemp);
1336
1337 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1338 &UnicodeClassName,
1339 FALSE);
1340 if (!NT_SUCCESS(Status))
1341 {
1342 SetLastNtError(Status);
1343 _SEH2_LEAVE;
1344 }
1345 }
1346
1347 Ret = BufLen / sizeof(WCHAR);
1348 }
1349 else /* !Ansi */
1350 {
1351 BufLen = ClassName->MaximumLength;
1352
1353 /* query the atom name */
1354 Status = RtlQueryAtomInAtomTable(gAtomTable,
1355 Class->Atom,
1356 NULL,
1357 NULL,
1358 ClassName->Buffer,
1359 &BufLen);
1360
1361 if (!NT_SUCCESS(Status))
1362 {
1363 SetLastNtError(Status);
1364 _SEH2_LEAVE;
1365 }
1366
1367 Ret = BufLen / sizeof(WCHAR);
1368 }
1369 }
1370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1371 {
1372 SetLastNtError(_SEH2_GetExceptionCode());
1373 }
1374 _SEH2_END;
1375
1376 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1377 {
1378 ExFreePool(szTemp);
1379 }
1380
1381 return Ret;
1382 }
1383
1384 ULONG_PTR
1385 UserGetClassLongPtr(IN PWINDOWCLASS Class,
1386 IN INT Index,
1387 IN BOOL Ansi)
1388 {
1389 ULONG_PTR Ret = 0;
1390
1391 if (Index >= 0)
1392 {
1393 PULONG_PTR Data;
1394
1395 TRACE("GetClassLong(%d)\n", Index);
1396 if (Index + sizeof(ULONG_PTR) < Index ||
1397 Index + sizeof(ULONG_PTR) > Class->ClsExtra)
1398 {
1399 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1400 return 0;
1401 }
1402
1403 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1404
1405 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1406 certain architectures, maybe using RtlCopyMemory is a
1407 better choice for those architectures! */
1408
1409 TRACE("Result: %x\n", Ret);
1410 return *Data;
1411 }
1412
1413 switch (Index)
1414 {
1415 case GCL_CBWNDEXTRA:
1416 Ret = (ULONG_PTR)Class->WndExtra;
1417 break;
1418
1419 case GCL_CBCLSEXTRA:
1420 Ret = (ULONG_PTR)Class->ClsExtra;
1421 break;
1422
1423 case GCLP_HBRBACKGROUND:
1424 Ret = (ULONG_PTR)Class->hbrBackground;
1425 break;
1426
1427 case GCLP_HCURSOR:
1428 /* FIXME - get handle from pointer to CURSOR object */
1429 Ret = (ULONG_PTR)Class->hCursor;
1430 break;
1431
1432 case GCLP_HICON:
1433 /* FIXME - get handle from pointer to ICON object */
1434 Ret = (ULONG_PTR)Class->hIcon;
1435 break;
1436
1437 case GCLP_HICONSM:
1438 /* FIXME - get handle from pointer to ICON object */
1439 Ret = (ULONG_PTR)Class->hIconSm;
1440 break;
1441
1442 case GCLP_HMODULE:
1443 Ret = (ULONG_PTR)Class->hInstance;
1444 break;
1445
1446 case GCLP_MENUNAME:
1447 /* NOTE: Returns pointer in kernel heap! */
1448 if (Ansi)
1449 Ret = (ULONG_PTR)Class->AnsiMenuName;
1450 else
1451 Ret = (ULONG_PTR)Class->MenuName;
1452 break;
1453
1454 case GCL_STYLE:
1455 Ret = (ULONG_PTR)Class->Style;
1456 break;
1457
1458 case GCLP_WNDPROC:
1459 Ret = (ULONG_PTR)IntGetClassWndProc(Class,
1460 GetW32ProcessInfo(),
1461 Ansi);
1462 break;
1463
1464 case GCW_ATOM:
1465 Ret = (ULONG_PTR)Class->Atom;
1466 break;
1467
1468 default:
1469 SetLastWin32Error(ERROR_INVALID_INDEX);
1470 break;
1471 }
1472
1473 return Ret;
1474 }
1475
1476 static BOOL
1477 IntSetClassMenuName(IN PWINDOWCLASS Class,
1478 IN PUNICODE_STRING MenuName)
1479 {
1480 BOOL Ret = FALSE;
1481
1482 /* change the base class first */
1483 Class = Class->Base;
1484
1485 if (MenuName->Length != 0)
1486 {
1487 ANSI_STRING AnsiString;
1488 PWSTR strBufW;
1489
1490 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
1491
1492 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1493 AnsiString.MaximumLength);
1494 if (strBufW != NULL)
1495 {
1496 _SEH2_TRY
1497 {
1498 NTSTATUS Status;
1499
1500 /* copy the unicode string */
1501 RtlCopyMemory(strBufW,
1502 MenuName->Buffer,
1503 MenuName->Length);
1504 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1505
1506 /* create an ansi copy of the string */
1507 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1508 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1509 MenuName,
1510 FALSE);
1511 if (!NT_SUCCESS(Status))
1512 {
1513 SetLastNtError(Status);
1514 _SEH2_LEAVE;
1515 }
1516
1517 Ret = TRUE;
1518 }
1519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1520 {
1521 SetLastNtError(_SEH2_GetExceptionCode());
1522 }
1523 _SEH2_END;
1524
1525 if (Ret)
1526 {
1527 /* update the base class */
1528 IntFreeClassMenuName(Class);
1529 Class->MenuName = strBufW;
1530 Class->AnsiMenuName = AnsiString.Buffer;
1531 Class->MenuNameIsString = TRUE;
1532
1533 /* update the clones */
1534 Class = Class->Clone;
1535 while (Class != NULL)
1536 {
1537 Class->MenuName = strBufW;
1538 Class->AnsiMenuName = AnsiString.Buffer;
1539 Class->MenuNameIsString = TRUE;
1540
1541 Class = Class->Next;
1542 }
1543 }
1544 else
1545 {
1546 DPRINT1("Failed to copy class menu name!\n");
1547 UserHeapFree(strBufW);
1548 }
1549 }
1550 else
1551 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1552 }
1553 else
1554 {
1555 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1556
1557 /* update the base class */
1558 IntFreeClassMenuName(Class);
1559 Class->MenuName = MenuName->Buffer;
1560 Class->AnsiMenuName = (PSTR)MenuName->Buffer;
1561 Class->MenuNameIsString = FALSE;
1562
1563 /* update the clones */
1564 Class = Class->Clone;
1565 while (Class != NULL)
1566 {
1567 Class->MenuName = MenuName->Buffer;
1568 Class->AnsiMenuName = (PSTR)MenuName->Buffer;
1569 Class->MenuNameIsString = FALSE;
1570
1571 Class = Class->Next;
1572 }
1573
1574 Ret = TRUE;
1575 }
1576
1577 return Ret;
1578 }
1579
1580 ULONG_PTR
1581 UserSetClassLongPtr(IN PWINDOWCLASS Class,
1582 IN INT Index,
1583 IN ULONG_PTR NewLong,
1584 IN BOOL Ansi)
1585 {
1586 ULONG_PTR Ret = 0;
1587
1588 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1589
1590 /* change the information in the base class first, then update the clones */
1591 Class = Class->Base;
1592
1593 if (Index >= 0)
1594 {
1595 PULONG_PTR Data;
1596
1597 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1598
1599 if (Index + sizeof(ULONG_PTR) < Index ||
1600 Index + sizeof(ULONG_PTR) > Class->ClsExtra)
1601 {
1602 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1603 return 0;
1604 }
1605
1606 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1607
1608 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1609 certain architectures, maybe using RtlCopyMemory is a
1610 better choice for those architectures! */
1611 Ret = *Data;
1612 *Data = NewLong;
1613
1614 /* update the clones */
1615 Class = Class->Clone;
1616 while (Class != NULL)
1617 {
1618 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1619 Class = Class->Next;
1620 }
1621
1622 return Ret;
1623 }
1624
1625 switch (Index)
1626 {
1627 case GCL_CBWNDEXTRA:
1628 Ret = (ULONG_PTR)Class->WndExtra;
1629 Class->WndExtra = (INT)NewLong;
1630
1631 /* update the clones */
1632 Class = Class->Clone;
1633 while (Class != NULL)
1634 {
1635 Class->WndExtra = (INT)NewLong;
1636 Class = Class->Next;
1637 }
1638
1639 break;
1640
1641 case GCL_CBCLSEXTRA:
1642 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1643 break;
1644
1645 case GCLP_HBRBACKGROUND:
1646 Ret = (ULONG_PTR)Class->hbrBackground;
1647 Class->hbrBackground = (HBRUSH)NewLong;
1648
1649 /* update the clones */
1650 Class = Class->Clone;
1651 while (Class != NULL)
1652 {
1653 Class->hbrBackground = (HBRUSH)NewLong;
1654 Class = Class->Next;
1655 }
1656 break;
1657
1658 case GCLP_HCURSOR:
1659 /* FIXME - get handle from pointer to CURSOR object */
1660 Ret = (ULONG_PTR)Class->hCursor;
1661 Class->hCursor = (HANDLE)NewLong;
1662
1663 /* update the clones */
1664 Class = Class->Clone;
1665 while (Class != NULL)
1666 {
1667 Class->hCursor = (HANDLE)NewLong;
1668 Class = Class->Next;
1669 }
1670 break;
1671
1672 case GCLP_HICON:
1673 /* FIXME - get handle from pointer to ICON object */
1674 Ret = (ULONG_PTR)Class->hIcon;
1675 Class->hIcon = (HANDLE)NewLong;
1676
1677 /* update the clones */
1678 Class = Class->Clone;
1679 while (Class != NULL)
1680 {
1681 Class->hIcon = (HANDLE)NewLong;
1682 Class = Class->Next;
1683 }
1684 break;
1685
1686 case GCLP_HICONSM:
1687 /* FIXME - get handle from pointer to ICON object */
1688 Ret = (ULONG_PTR)Class->hIconSm;
1689 Class->hIconSm = (HANDLE)NewLong;
1690
1691 /* update the clones */
1692 Class = Class->Clone;
1693 while (Class != NULL)
1694 {
1695 Class->hIconSm = (HANDLE)NewLong;
1696 Class = Class->Next;
1697 }
1698 break;
1699
1700 case GCLP_HMODULE:
1701 Ret = (ULONG_PTR)Class->hInstance;
1702 Class->hInstance = (HINSTANCE)NewLong;
1703
1704 /* update the clones */
1705 Class = Class->Clone;
1706 while (Class != NULL)
1707 {
1708 Class->hInstance = (HINSTANCE)NewLong;
1709 Class = Class->Next;
1710 }
1711 break;
1712
1713 case GCLP_MENUNAME:
1714 {
1715 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1716
1717 if (!IntSetClassMenuName(Class,
1718 Value))
1719 {
1720 DPRINT("Setting the class menu name failed!\n");
1721 }
1722
1723 /* FIXME - really return NULL? Wine does so... */
1724 break;
1725 }
1726
1727 case GCL_STYLE:
1728 Ret = (ULONG_PTR)Class->Style;
1729 Class->Style = (UINT)NewLong;
1730
1731 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1732 move the class to the appropriate list? For now, we save
1733 the original value in Class->Global, so we can always
1734 locate the appropriate list */
1735
1736 /* update the clones */
1737 Class = Class->Clone;
1738 while (Class != NULL)
1739 {
1740 Class->Style = (UINT)NewLong;
1741 Class = Class->Next;
1742 }
1743 break;
1744
1745 case GCLP_WNDPROC:
1746 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1747 (WNDPROC)NewLong,
1748 Ansi);
1749 break;
1750
1751 case GCW_ATOM:
1752 {
1753 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1754
1755 Ret = (ULONG_PTR)Class->Atom;
1756 if (!IntSetClassAtom(Class,
1757 Value))
1758 {
1759 Ret = 0;
1760 }
1761 break;
1762 }
1763
1764 default:
1765 SetLastWin32Error(ERROR_INVALID_INDEX);
1766 break;
1767 }
1768
1769 return Ret;
1770 }
1771
1772 static BOOL
1773 UserGetClassInfo(IN PWINDOWCLASS Class,
1774 OUT PWNDCLASSEXW lpwcx,
1775 IN BOOL Ansi,
1776 HINSTANCE hInstance)
1777 {
1778 PPROCESSINFO pi;
1779
1780 lpwcx->style = Class->Style;
1781
1782 pi = GetW32ProcessInfo();
1783 lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
1784 pi,
1785 Ansi);
1786
1787 lpwcx->cbClsExtra = Class->ClsExtra;
1788 lpwcx->cbWndExtra = Class->WndExtra;
1789 lpwcx->hIcon = Class->hIcon; /* FIXME - get handle from pointer */
1790 lpwcx->hCursor = Class->hCursor; /* FIXME - get handle from pointer */
1791 lpwcx->hbrBackground = Class->hbrBackground;
1792
1793 if (Ansi)
1794 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->AnsiMenuName;
1795 else
1796 lpwcx->lpszMenuName = Class->MenuName;
1797
1798 if (Class->hInstance == pi->hModUser)
1799 lpwcx->hInstance = NULL;
1800 else
1801 lpwcx->hInstance = Class->hInstance;
1802
1803 lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->Atom); /* FIXME - return the string? */
1804
1805 lpwcx->hIconSm = Class->hIconSm; /* FIXME - get handle from pointer */
1806
1807 return TRUE;
1808 }
1809
1810 BOOL
1811 UserRegisterSystemClasses(IN ULONG Count,
1812 IN PREGISTER_SYSCLASS SystemClasses)
1813 {
1814 /* NOTE: This routine may raise exceptions! */
1815 UINT i;
1816 UNICODE_STRING ClassName, MenuName;
1817 PPROCESSINFO pi = GetW32ProcessInfo();
1818 WNDCLASSEXW wc;
1819 PWINDOWCLASS Class;
1820 BOOL Ret = TRUE;
1821
1822 if (pi->RegisteredSysClasses || pi->hModUser == NULL)
1823 return FALSE;
1824
1825 RtlZeroMemory(&MenuName, sizeof(MenuName));
1826
1827 for (i = 0; i != Count; i++)
1828 {
1829 ClassName = ProbeForReadUnicodeString(&SystemClasses[i].ClassName);
1830 if (ClassName.Length != 0)
1831 {
1832 ProbeForRead(ClassName.Buffer,
1833 ClassName.Length,
1834 sizeof(WCHAR));
1835 }
1836
1837 wc.cbSize = sizeof(wc);
1838 wc.style = SystemClasses[i].Style;
1839 wc.lpfnWndProc = SystemClasses[i].ProcW;
1840 wc.cbClsExtra = 0;
1841 wc.cbWndExtra = SystemClasses[i].ExtraBytes;
1842 wc.hInstance = pi->hModUser;
1843 wc.hIcon = NULL;
1844 wc.hCursor = SystemClasses[i].hCursor;
1845 wc.hbrBackground = SystemClasses[i].hBrush;
1846 wc.lpszMenuName = NULL;
1847 wc.lpszClassName = ClassName.Buffer;
1848 wc.hIconSm = NULL;
1849
1850 Class = IntCreateClass(&wc,
1851 &ClassName,
1852 &MenuName,
1853 SystemClasses[i].ProcA,
1854 REGISTERCLASS_SYSTEM,
1855 NULL,
1856 pi);
1857 if (Class != NULL)
1858 {
1859 Class->fnID = SystemClasses[i].ClassId;
1860
1861 ASSERT(Class->System);
1862 Class->Next = pi->SystemClassList;
1863 (void)InterlockedExchangePointer((PVOID*)&pi->SystemClassList,
1864 Class);
1865 }
1866 else
1867 {
1868 WARN("!!! Registering system class failed!\n");
1869 Ret = FALSE;
1870 }
1871 }
1872
1873 if (Ret)
1874 pi->RegisteredSysClasses = TRUE;
1875 return Ret;
1876 }
1877
1878 /* SYSCALLS *****************************************************************/
1879
1880
1881 RTL_ATOM APIENTRY
1882 NtUserRegisterClassEx(IN CONST WNDCLASSEXW* lpwcx,
1883 IN PUNICODE_STRING ClassName,
1884 IN PUNICODE_STRING MenuName,
1885 IN WNDPROC wpExtra,
1886 IN DWORD Flags,
1887 IN HMENU hMenu)
1888
1889 /*
1890 * FUNCTION:
1891 * Registers a new class with the window manager
1892 * ARGUMENTS:
1893 * lpwcx = Win32 extended window class structure
1894 * bUnicodeClass = Whether to send ANSI or unicode strings
1895 * to window procedures
1896 * wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
1897 * RETURNS:
1898 * Atom identifying the new class
1899 */
1900 {
1901 WNDCLASSEXW CapturedClassInfo = {0};
1902 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
1903 RTL_ATOM Ret = (RTL_ATOM)0;
1904
1905 if (Flags & ~REGISTERCLASS_ALL)
1906 {
1907 SetLastWin32Error(ERROR_INVALID_FLAGS);
1908 return Ret;
1909 }
1910
1911 UserEnterExclusive();
1912
1913 _SEH2_TRY
1914 {
1915 /* Probe the parameters and basic parameter checks */
1916 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
1917 {
1918 goto InvalidParameter;
1919 }
1920
1921 ProbeForRead(lpwcx,
1922 sizeof(WNDCLASSEXW),
1923 sizeof(ULONG));
1924 RtlCopyMemory(&CapturedClassInfo,
1925 lpwcx,
1926 sizeof(WNDCLASSEXW));
1927
1928 CapturedName = ProbeForReadUnicodeString(ClassName);
1929 CapturedMenuName = ProbeForReadUnicodeString(MenuName);
1930
1931 if (CapturedName.Length & 1 || CapturedMenuName.Length & 1 ||
1932 CapturedClassInfo.cbClsExtra < 0 ||
1933 CapturedClassInfo.cbClsExtra + CapturedName.Length +
1934 CapturedMenuName.Length + sizeof(WINDOWCLASS) < CapturedClassInfo.cbClsExtra ||
1935 CapturedClassInfo.cbWndExtra < 0 ||
1936 CapturedClassInfo.hInstance == NULL)
1937 {
1938 goto InvalidParameter;
1939 }
1940
1941 if (CapturedName.Length != 0)
1942 {
1943 ProbeForRead(CapturedName.Buffer,
1944 CapturedName.Length,
1945 sizeof(WCHAR));
1946 }
1947 else
1948 {
1949 if (!IS_ATOM(CapturedName.Buffer))
1950 {
1951 goto InvalidParameter;
1952 }
1953 }
1954
1955 if (CapturedMenuName.Length != 0)
1956 {
1957 ProbeForRead(CapturedMenuName.Buffer,
1958 CapturedMenuName.Length,
1959 sizeof(WCHAR));
1960 }
1961 else if (CapturedMenuName.Buffer != NULL &&
1962 !IS_INTRESOURCE(CapturedMenuName.Buffer))
1963 {
1964 InvalidParameter:
1965 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1966 _SEH2_LEAVE;
1967 }
1968
1969 /* Register the class */
1970 Ret = UserRegisterClass(&CapturedClassInfo,
1971 &CapturedName,
1972 &CapturedMenuName,
1973 hMenu, /* FIXME - pass pointer */
1974 wpExtra,
1975 Flags);
1976
1977 }
1978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1979 {
1980 SetLastNtError(_SEH2_GetExceptionCode());
1981 }
1982 _SEH2_END;
1983
1984 UserLeave();
1985
1986 return Ret;
1987 }
1988
1989
1990 RTL_ATOM
1991 APIENTRY
1992 NtUserRegisterClassExWOW(
1993 WNDCLASSEXW* lpwcx,
1994 PUNICODE_STRING ClassName,
1995 PUNICODE_STRING ClsNVersion,
1996 PCLSMENUNAME pClassMenuName,
1997 DWORD fnID,
1998 DWORD Flags,
1999 LPDWORD pWow)
2000 {
2001 WNDCLASSEXW CapturedClassInfo = {0};
2002 UNICODE_STRING CapturedName = {0}, ClassnametoVersion = {0};
2003 RTL_ATOM Ret = (RTL_ATOM)0;
2004
2005 UserEnterExclusive();
2006
2007 _SEH2_TRY
2008 {
2009 /* Probe the parameters and basic parameter checks */
2010 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2011 {
2012 goto InvalidParameter;
2013 }
2014 if (!pClassMenuName)
2015 {
2016 goto InvalidParameter;
2017 }
2018
2019 ProbeForRead(lpwcx,
2020 sizeof(WNDCLASSEXW),
2021 sizeof(ULONG));
2022 RtlCopyMemory(&CapturedClassInfo,
2023 lpwcx,
2024 sizeof(WNDCLASSEXW));
2025 /*
2026 Need to watch this. When UnregisterClass is called these pointers
2027 are freed by the caller in user space. So, we just probe the data
2028 for now and pass it on and copy it to the shared class structure.
2029 */
2030 ProbeForRead(pClassMenuName,
2031 sizeof(CLSMENUNAME),
2032 sizeof(ULONG));
2033
2034 CapturedName = ProbeForReadUnicodeString(ClassName);
2035 ClassnametoVersion = ProbeForReadUnicodeString(ClsNVersion);
2036
2037 if (CapturedName.Length & 1 || ClassnametoVersion.Length & 1 ||
2038 CapturedClassInfo.cbClsExtra < 0 ||
2039 CapturedClassInfo.cbClsExtra + CapturedName.Length +
2040 ClassnametoVersion.Length + sizeof(WINDOWCLASS) < CapturedClassInfo.cbClsExtra ||
2041 CapturedClassInfo.cbWndExtra < 0 ||
2042 CapturedClassInfo.hInstance == NULL)
2043 {
2044 goto InvalidParameter;
2045 }
2046
2047 if (CapturedName.Length != 0)
2048 {
2049 ProbeForRead(CapturedName.Buffer,
2050 CapturedName.Length,
2051 sizeof(WCHAR));
2052 }
2053 else
2054 {
2055 if (!IS_ATOM(CapturedName.Buffer))
2056 {
2057 goto InvalidParameter;
2058 }
2059 }
2060
2061 if (ClassnametoVersion.Length != 0)
2062 {
2063 ProbeForRead(ClassnametoVersion.Buffer,
2064 ClassnametoVersion.Length,
2065 sizeof(WCHAR));
2066 }
2067 else if (ClassnametoVersion.Buffer != NULL &&
2068 !IS_INTRESOURCE(ClassnametoVersion.Buffer))
2069 {
2070 InvalidParameter:
2071 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2072 _SEH2_LEAVE;
2073 }
2074
2075 /* Register the class */
2076 // Ret = UserRegisterClass(&CapturedClassInfo,
2077 // &CapturedName,
2078 // &ClassnametoVersion,
2079 // hMenu, /* FIXME - pass pointer */
2080 // wpExtra,
2081 // Flags);
2082
2083 }
2084 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2085 {
2086 SetLastNtError(_SEH2_GetExceptionCode());
2087 }
2088 _SEH2_END;
2089
2090 UserLeave();
2091
2092 return Ret;
2093 }
2094
2095
2096 ULONG_PTR APIENTRY
2097 NtUserGetClassLong(IN HWND hWnd,
2098 IN INT Offset,
2099 IN BOOL Ansi)
2100 {
2101 PWINDOW_OBJECT Window;
2102 ULONG_PTR Ret = 0;
2103
2104 if (Offset != GCLP_WNDPROC)
2105 {
2106 UserEnterShared();
2107 }
2108 else
2109 {
2110 UserEnterExclusive();
2111 }
2112
2113 Window = UserGetWindowObject(hWnd);
2114 if (Window != NULL)
2115 {
2116 Ret = UserGetClassLongPtr(Window->Wnd->Class,
2117 Offset,
2118 Ansi);
2119
2120 if (Ret != 0 && Offset == GCLP_MENUNAME && Window->Wnd->Class->MenuNameIsString)
2121 {
2122 Ret = (ULONG_PTR)UserHeapAddressToUser((PVOID)Ret);
2123 }
2124 }
2125
2126 UserLeave();
2127
2128 return Ret;
2129 }
2130
2131
2132
2133 ULONG_PTR APIENTRY
2134 NtUserSetClassLong(HWND hWnd,
2135 INT Offset,
2136 ULONG_PTR dwNewLong,
2137 BOOL Ansi)
2138 {
2139 PPROCESSINFO pi;
2140 PWINDOW_OBJECT Window;
2141 ULONG_PTR Ret = 0;
2142
2143 UserEnterExclusive();
2144
2145 pi = GetW32ProcessInfo();
2146 if (pi == NULL)
2147 goto Cleanup;
2148
2149 Window = UserGetWindowObject(hWnd);
2150 if (Window != NULL)
2151 {
2152 if (Window->ti->ppi != pi)
2153 {
2154 SetLastWin32Error(ERROR_ACCESS_DENIED);
2155 goto Cleanup;
2156 }
2157
2158 _SEH2_TRY
2159 {
2160 UNICODE_STRING Value;
2161
2162 /* probe the parameters */
2163 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2164 {
2165 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2166 if (Value.Length & 1)
2167 {
2168 goto InvalidParameter;
2169 }
2170
2171 if (Value.Length != 0)
2172 {
2173 ProbeForRead(Value.Buffer,
2174 Value.Length,
2175 sizeof(WCHAR));
2176 }
2177 else
2178 {
2179 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2180 {
2181 goto InvalidParameter;
2182 }
2183 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2184 {
2185 InvalidParameter:
2186 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2187 _SEH2_LEAVE;
2188 }
2189 }
2190
2191 dwNewLong = (ULONG_PTR)&Value;
2192 }
2193
2194 Ret = UserSetClassLongPtr(Window->Wnd->Class,
2195 Offset,
2196 dwNewLong,
2197 Ansi);
2198 }
2199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2200 {
2201 SetLastNtError(_SEH2_GetExceptionCode());
2202 }
2203 _SEH2_END;
2204 }
2205
2206 Cleanup:
2207 UserLeave();
2208
2209 return Ret;
2210 }
2211
2212 WORD
2213 APIENTRY
2214 NtUserSetClassWord(
2215 HWND hWnd,
2216 INT nIndex,
2217 WORD wNewWord)
2218 {
2219 return(0);
2220 }
2221
2222 BOOL APIENTRY
2223 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2224 IN HINSTANCE hInstance,
2225 OUT PCLSMENUNAME pClassMenuName)
2226 {
2227 UNICODE_STRING CapturedClassName;
2228 BOOL Ret = FALSE;
2229
2230 UserEnterExclusive();
2231
2232 _SEH2_TRY
2233 {
2234 /* probe the paramters */
2235 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2236 if (CapturedClassName.Length & 1)
2237 {
2238 goto InvalidParameter;
2239 }
2240
2241 if (CapturedClassName.Length != 0)
2242 {
2243 ProbeForRead(CapturedClassName.Buffer,
2244 CapturedClassName.Length,
2245 sizeof(WCHAR));
2246 }
2247 else
2248 {
2249 if (!IS_ATOM(CapturedClassName.Buffer))
2250 {
2251 InvalidParameter:
2252 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2253 _SEH2_LEAVE;
2254 }
2255 }
2256
2257 /* unregister the class */
2258 Ret = UserUnregisterClass(&CapturedClassName,
2259 hInstance);
2260 }
2261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2262 {
2263 SetLastNtError(_SEH2_GetExceptionCode());
2264 }
2265 _SEH2_END;
2266
2267 UserLeave();
2268
2269 return Ret;
2270 }
2271
2272 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2273 BOOL APIENTRY
2274 NtUserGetClassInfo(
2275 HINSTANCE hInstance,
2276 PUNICODE_STRING ClassName,
2277 LPWNDCLASSEXW lpWndClassEx,
2278 LPWSTR *ppszMenuName,
2279 BOOL Ansi)
2280 {
2281 UNICODE_STRING CapturedClassName;
2282 PWINDOWCLASS Class;
2283 RTL_ATOM ClassAtom;
2284 PPROCESSINFO pi;
2285 BOOL Ret = FALSE;
2286
2287 /* NOTE: need exclusive lock because getting the wndproc might require the
2288 creation of a call procedure handle */
2289 UserEnterExclusive();
2290
2291 pi = GetW32ProcessInfo();
2292 if (pi == NULL)
2293 {
2294 ERR("GetW32ProcessInfo() returned NULL!\n");
2295 goto Cleanup;
2296 }
2297 _SEH2_TRY
2298 {
2299 /* probe the paramters */
2300 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2301
2302 if (CapturedClassName.Length == 0)
2303 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2304 else
2305 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2306
2307 if (CapturedClassName.Length & 1)
2308 {
2309 goto InvalidParameter;
2310 }
2311
2312 if (CapturedClassName.Length != 0)
2313 {
2314 ProbeForRead(CapturedClassName.Buffer,
2315 CapturedClassName.Length,
2316 sizeof(WCHAR));
2317 }
2318 else
2319 {
2320 if (!IS_ATOM(CapturedClassName.Buffer))
2321 {
2322 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2323 goto InvalidParameter;
2324 }
2325 }
2326
2327 if (ProbeForReadUint(&lpWndClassEx->cbSize) != sizeof(WNDCLASSEXW))
2328 {
2329 InvalidParameter:
2330 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2331 _SEH2_LEAVE;
2332 }
2333
2334 ProbeForWrite(lpWndClassEx,
2335 sizeof(WNDCLASSEXW),
2336 sizeof(ULONG));
2337
2338 ClassAtom = IntGetClassAtom(&CapturedClassName,
2339 hInstance,
2340 pi,
2341 &Class,
2342 NULL);
2343 if (ClassAtom != (RTL_ATOM)0)
2344 {
2345 if (hInstance == NULL)
2346 hInstance = pi->hModUser;
2347
2348 Ret = UserGetClassInfo(Class,
2349 lpWndClassEx,
2350 Ansi,
2351 hInstance);
2352
2353 if (Ret)
2354 {
2355 lpWndClassEx->lpszClassName = CapturedClassName.Buffer;
2356 /* FIXME - handle Class->Desktop == NULL!!!!! */
2357
2358 if (Class->MenuName != NULL && Class->MenuNameIsString)
2359 {
2360 lpWndClassEx->lpszMenuName = UserHeapAddressToUser(Ansi ?
2361 (PVOID)Class->AnsiMenuName :
2362 (PVOID)Class->MenuName);
2363 }
2364
2365 /* Undocumented behavior! Return the class atom as a BOOL! */
2366 Ret = (BOOL)ClassAtom;
2367 }
2368 }
2369 else
2370 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2371 }
2372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2373 {
2374 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2375 }
2376 _SEH2_END;
2377
2378 Cleanup:
2379 UserLeave();
2380 return Ret;
2381 }
2382
2383
2384
2385 INT APIENTRY
2386 NtUserGetClassName (IN HWND hWnd,
2387 OUT PUNICODE_STRING ClassName,
2388 IN BOOL Ansi)
2389 {
2390 PWINDOW_OBJECT Window;
2391 UNICODE_STRING CapturedClassName;
2392 INT Ret = 0;
2393
2394 UserEnterShared();
2395
2396 Window = UserGetWindowObject(hWnd);
2397 if (Window != NULL)
2398 {
2399 _SEH2_TRY
2400 {
2401 ProbeForWriteUnicodeString(ClassName);
2402 CapturedClassName = *ClassName;
2403
2404 /* get the class name */
2405 Ret = UserGetClassName(Window->Wnd->Class,
2406 &CapturedClassName,
2407 Ansi);
2408
2409 if (Ret != 0)
2410 {
2411 /* update the Length field */
2412 ClassName->Length = CapturedClassName.Length;
2413 }
2414 }
2415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2416 {
2417 SetLastNtError(_SEH2_GetExceptionCode());
2418 }
2419 _SEH2_END;
2420 }
2421
2422 UserLeave();
2423
2424 return Ret;
2425 }
2426
2427 DWORD APIENTRY
2428 NtUserGetWOWClass(DWORD Unknown0,
2429 DWORD Unknown1)
2430 {
2431 return(0);
2432 }
2433
2434 /* EOF */