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