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