- Initialize MmLowestPhysicalPage to -1, otherwise setting this value will never...
[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(PPROCESSINFO 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 fnID,
819 IN DWORD dwFlags,
820 IN PDESKTOP Desktop,
821 IN PPROCESSINFO pi)
822 {
823 SIZE_T ClassSize;
824 PCLS Class = NULL;
825 RTL_ATOM Atom;
826 PWSTR pszMenuName = NULL;
827 NTSTATUS Status = STATUS_SUCCESS;
828
829 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
830 lpwcx, ClassName, MenuName, wpExtra, dwFlags, Desktop, pi);
831
832 if (!IntRegisterClassAtom(ClassName,
833 &Atom))
834 {
835 DPRINT1("Failed to register class atom!\n");
836 return NULL;
837 }
838
839 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
840 if (MenuName->Length != 0)
841 {
842 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
843 RtlUnicodeStringToAnsiSize(MenuName));
844 if (pszMenuName == NULL)
845 goto NoMem;
846 }
847
848 if (Desktop != NULL)
849 {
850 Class = DesktopHeapAlloc(Desktop,
851 ClassSize);
852 }
853 else
854 {
855 /* FIXME - the class was created before being connected
856 to a desktop. It is possible for the desktop window,
857 but should it be allowed for any other case? */
858 Class = UserHeapAlloc(ClassSize);
859 }
860
861 if (Class != NULL)
862 {
863 RtlZeroMemory(Class,
864 ClassSize);
865
866 Class->rpdeskParent = Desktop;
867 Class->pclsBase = Class;
868 Class->atomClassName = Atom;
869 Class->fnid = fnID;
870 Class->CSF_flags = dwFlags;
871
872 if (dwFlags & CSF_SYSTEMCLASS)
873 {
874 int iCls;
875
876 dwFlags &= ~CSF_ANSIPROC;
877 Class->WndProcExtra = wpExtra;
878 Class->System = TRUE;
879 /* Now set the Atom table, notice only non ntuser.c atoms can go in.*/
880 if (LockupFnIdToiCls(Class->fnid, &iCls))
881 {
882 gpsi->atomSysClass[iCls] = Class->atomClassName;
883 }
884 }
885
886 _SEH2_TRY
887 {
888 PWSTR pszMenuNameBuffer = pszMenuName;
889
890 /* need to protect with SEH since accessing the WNDCLASSEX structure
891 and string buffers might raise an exception! We don't want to
892 leak memory... */
893 Class->lpfnWndProc = lpwcx->lpfnWndProc;
894 Class->style = lpwcx->style;
895 Class->cbclsExtra = lpwcx->cbClsExtra;
896 Class->cbwndExtra = lpwcx->cbWndExtra;
897 Class->hModule = lpwcx->hInstance;
898 Class->hIcon = lpwcx->hIcon; /* FIXME */
899 Class->hIconSm = lpwcx->hIconSm; /* FIXME */
900 Class->hCursor = lpwcx->hCursor; /* FIXME */
901 Class->hbrBackground = lpwcx->hbrBackground;
902
903
904 /* make a copy of the string */
905 if (pszMenuNameBuffer != NULL)
906 {
907 Class->MenuNameIsString = TRUE;
908
909 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
910 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
911 MenuName->Buffer,
912 MenuName->Length);
913 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
914
915 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
916 }
917 else
918 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
919
920 /* save an ansi copy of the string */
921 if (pszMenuNameBuffer != NULL)
922 {
923 ANSI_STRING AnsiString;
924
925 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
926 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
927 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
928 Status = RtlUnicodeStringToAnsiString(&AnsiString,
929 MenuName,
930 FALSE);
931 if (!NT_SUCCESS(Status))
932 {
933 DPRINT1("Failed to convert unicode menu name to ansi!\n");
934
935 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
936 _SEH2_LEAVE;
937 }
938 }
939 else
940 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
941
942 /* Save kernel use menu name and ansi class name */
943 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // Fixme!
944 //Class->lpszAnsiClassName = Fixme!
945
946 if (!(dwFlags & CSF_ANSIPROC))
947 Class->Unicode = TRUE;
948
949 if (Class->style & CS_GLOBALCLASS)
950 Class->Global = TRUE;
951 }
952 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
953 {
954 Status = _SEH2_GetExceptionCode();
955 }
956 _SEH2_END;
957
958 if (!NT_SUCCESS(Status))
959 {
960 DPRINT1("Failed creating the class: 0x%x\n", Status);
961
962 SetLastNtError(Status);
963
964 if (pszMenuName != NULL)
965 UserHeapFree(pszMenuName);
966
967 DesktopHeapFree(Desktop,
968 Class);
969 Class = NULL;
970
971 IntDeregisterClassAtom(Atom);
972 }
973 }
974 else
975 {
976 NoMem:
977 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop);
978
979 if (pszMenuName != NULL)
980 UserHeapFree(pszMenuName);
981
982 IntDeregisterClassAtom(Atom);
983
984 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
985 }
986
987 return Class;
988 }
989
990 static PCLS
991 IntFindClass(IN RTL_ATOM Atom,
992 IN HINSTANCE hInstance,
993 IN PCLS *ClassList,
994 OUT PCLS **Link OPTIONAL)
995 {
996 PCLS Class, *PrevLink = ClassList;
997
998 Class = *PrevLink;
999 while (Class != NULL)
1000 {
1001 if (Class->atomClassName == Atom &&
1002 (hInstance == NULL || Class->hModule == hInstance) &&
1003 !Class->Destroying)
1004 {
1005 ASSERT(Class->pclsBase == Class);
1006
1007 if (Link != NULL)
1008 *Link = PrevLink;
1009 break;
1010 }
1011
1012 PrevLink = &Class->pclsNext;
1013 Class = Class->pclsNext;
1014 }
1015
1016 return Class;
1017 }
1018
1019 BOOL
1020 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
1021 OUT RTL_ATOM *Atom)
1022 {
1023 BOOL Ret = FALSE;
1024
1025 if (ClassName->Length != 0)
1026 {
1027 WCHAR szBuf[65];
1028 PWSTR AtomName;
1029 NTSTATUS Status;
1030
1031 /* NOTE: Caller has to protect the call with SEH! */
1032
1033 if (ClassName->Length != 0)
1034 {
1035 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1036 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
1037 {
1038 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1039 return (RTL_ATOM)0;
1040 }
1041
1042 /* We need to make a local copy of the class name! The caller could
1043 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1044 We're protected by SEH, but the ranges that might be accessed were
1045 not probed... */
1046 RtlCopyMemory(szBuf,
1047 ClassName->Buffer,
1048 ClassName->Length);
1049 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1050 AtomName = szBuf;
1051 }
1052 else
1053 AtomName = ClassName->Buffer;
1054
1055 /* lookup the atom */
1056 Status = RtlLookupAtomInAtomTable(gAtomTable,
1057 AtomName,
1058 Atom);
1059 if (NT_SUCCESS(Status))
1060 {
1061 Ret = TRUE;
1062 }
1063 else
1064 {
1065 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1066 {
1067 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
1068 }
1069 else
1070 {
1071 SetLastNtError(Status);
1072 }
1073 }
1074 }
1075 else
1076 {
1077 ASSERT(IS_ATOM(ClassName->Buffer));
1078 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1079 Ret = TRUE;
1080 }
1081
1082 return Ret;
1083 }
1084
1085 RTL_ATOM
1086 IntGetClassAtom(IN PUNICODE_STRING ClassName,
1087 IN HINSTANCE hInstance OPTIONAL,
1088 IN PPROCESSINFO pi OPTIONAL,
1089 OUT PCLS *BaseClass OPTIONAL,
1090 OUT PCLS **Link OPTIONAL)
1091 {
1092 RTL_ATOM Atom = (RTL_ATOM)0;
1093
1094 ASSERT(BaseClass != NULL);
1095
1096 if (IntGetAtomFromStringOrAtom(ClassName,
1097 &Atom) &&
1098 Atom != (RTL_ATOM)0)
1099 {
1100 PCLS Class;
1101
1102 /* attempt to locate the class object */
1103
1104 ASSERT(pi != NULL);
1105
1106 /* Step 1: try to find an exact match of locally registered classes */
1107 Class = IntFindClass(Atom,
1108 hInstance,
1109 &pi->pclsPrivateList,
1110 Link);
1111 if (Class != NULL)
1112 {
1113 goto FoundClass;
1114 }
1115
1116 /* Step 2: try to find any globally registered class. The hInstance
1117 is not relevant for global classes */
1118 Class = IntFindClass(Atom,
1119 NULL,
1120 &pi->pclsPublicList,
1121 Link);
1122 if (Class != NULL)
1123 {
1124 goto FoundClass;
1125 }
1126
1127 /* Step 3: try to find any local class registered by user32 */
1128 Class = IntFindClass(Atom,
1129 hModClient,
1130 &pi->pclsPrivateList,
1131 Link);
1132 if (Class != NULL)
1133 {
1134 goto FoundClass;
1135 }
1136
1137 /* Step 4: try to find any global class registered by user32 */
1138 Class = IntFindClass(Atom,
1139 hModClient,
1140 &pi->pclsPublicList,
1141 Link);
1142 if (Class != NULL)
1143 {
1144 goto FoundClass;
1145 }
1146
1147 /* Step 5: try to find a system class */
1148 Class = IntFindClass(Atom,
1149 NULL,
1150 &SystemClassList,
1151 Link);
1152 if (Class == NULL)
1153 {
1154 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
1155 return (RTL_ATOM)0;
1156 }
1157
1158 FoundClass:
1159 *BaseClass = Class;
1160 }
1161
1162 return Atom;
1163 }
1164
1165 RTL_ATOM
1166 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1167 IN PUNICODE_STRING ClassName,
1168 IN PUNICODE_STRING MenuName,
1169 IN WNDPROC wpExtra,
1170 IN DWORD fnID,
1171 IN DWORD dwFlags)
1172 {
1173 PTHREADINFO pti;
1174 PW32THREADINFO ti;
1175 PPROCESSINFO pi;
1176 PCLS Class;
1177 RTL_ATOM ClassAtom;
1178 RTL_ATOM Ret = (RTL_ATOM)0;
1179
1180 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1181
1182 pti = PsGetCurrentThreadWin32Thread();
1183 ti = GetW32ThreadInfo();
1184 if (ti == NULL || !RegisteredSysClasses)
1185 {
1186 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1187 return (RTL_ATOM)0;
1188 }
1189
1190 pi = ti->ppi;
1191
1192 /* try to find a previously registered class */
1193 ClassAtom = IntGetClassAtom(ClassName,
1194 lpwcx->hInstance,
1195 pi,
1196 &Class,
1197 NULL);
1198 if (ClassAtom != (RTL_ATOM)0)
1199 {
1200 if (lpwcx->style & CS_GLOBALCLASS)
1201 {
1202 // global classes shall not have same names as system classes
1203 if (Class->Global || Class->System)
1204 {
1205 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1206 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1207 return (RTL_ATOM)0;
1208 }
1209 }
1210 else if ( !Class->Global && !Class->System)
1211 {
1212 // local class already exists
1213 DPRINT("Class 0x%p does already exist!\n", ClassAtom);
1214 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1215 return (RTL_ATOM)0;
1216 }
1217 }
1218
1219 Class = IntCreateClass(lpwcx,
1220 ClassName,
1221 MenuName,
1222 wpExtra,
1223 fnID,
1224 dwFlags,
1225 pti->Desktop,
1226 pi);
1227
1228 if (Class != NULL)
1229 {
1230 PCLS *List;
1231
1232 /* Register the class */
1233 if (Class->System)
1234 List = &SystemClassList;
1235 else if (Class->Global)
1236 List = &pi->pclsPublicList;
1237 else
1238 List = &pi->pclsPrivateList;
1239
1240 Class->pclsNext = *List;
1241 (void)InterlockedExchangePointer((PVOID*)List,
1242 Class);
1243
1244 Ret = Class->atomClassName;
1245 }
1246
1247 return Ret;
1248 }
1249
1250 BOOL
1251 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1252 IN HINSTANCE hInstance)
1253 {
1254 PCLS *Link;
1255 PPROCESSINFO pi;
1256 RTL_ATOM ClassAtom;
1257 PCLS Class;
1258
1259 pi = GetW32ProcessInfo();
1260 if (pi == NULL)
1261 {
1262 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1263 return FALSE;
1264 }
1265
1266 TRACE("UserUnregisterClass(%wZ)\n", ClassName);
1267
1268 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1269 ClassAtom = IntGetClassAtom(ClassName,
1270 hInstance,
1271 pi,
1272 &Class,
1273 &Link);
1274 if (ClassAtom == (RTL_ATOM)0)
1275 {
1276 return FALSE;
1277 }
1278
1279 ASSERT(Class != NULL);
1280
1281 if (Class->cWndReferenceCount != 0 ||
1282 Class->pclsClone != NULL)
1283 {
1284 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
1285 return FALSE;
1286 }
1287
1288 /* must be a base class! */
1289 ASSERT(Class->pclsBase == Class);
1290
1291 /* unlink the class */
1292 *Link = Class->pclsNext;
1293
1294 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1295 {
1296 /* finally free the resources */
1297 IntDestroyClass(Class);
1298 return TRUE;
1299 }
1300 return FALSE;
1301 }
1302
1303 INT
1304 UserGetClassName(IN PCLS Class,
1305 IN OUT PUNICODE_STRING ClassName,
1306 IN BOOL Ansi)
1307 {
1308 NTSTATUS Status = STATUS_SUCCESS;
1309 WCHAR szStaticTemp[32];
1310 PWSTR szTemp = NULL;
1311 ULONG BufLen = sizeof(szStaticTemp);
1312 INT Ret = 0;
1313
1314 /* Note: Accessing the buffer in ClassName may raise an exception! */
1315
1316 _SEH2_TRY
1317 {
1318 if (Ansi)
1319 {
1320 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1321 UNICODE_STRING UnicodeClassName;
1322
1323 /* limit the size of the static buffer on the stack to the
1324 size of the buffer provided by the caller */
1325 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1326 {
1327 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1328 }
1329
1330 /* find out how big the buffer needs to be */
1331 Status = RtlQueryAtomInAtomTable(gAtomTable,
1332 Class->atomClassName,
1333 NULL,
1334 NULL,
1335 szStaticTemp,
1336 &BufLen);
1337 if (Status == STATUS_BUFFER_TOO_SMALL)
1338 {
1339 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1340 {
1341 /* the buffer required exceeds the ansi buffer provided,
1342 pretend like we're using the ansi buffer and limit the
1343 size to the buffer size provided */
1344 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1345 }
1346
1347 /* allocate a temporary buffer that can hold the unicode class name */
1348 szTemp = ExAllocatePool(PagedPool,
1349 BufLen);
1350 if (szTemp == NULL)
1351 {
1352 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1353 _SEH2_LEAVE;
1354 }
1355
1356 /* query the class name */
1357 Status = RtlQueryAtomInAtomTable(gAtomTable,
1358 Class->atomClassName,
1359 NULL,
1360 NULL,
1361 szTemp,
1362 &BufLen);
1363 }
1364 else
1365 szTemp = szStaticTemp;
1366
1367 if (NT_SUCCESS(Status))
1368 {
1369 /* convert the atom name to ansi */
1370
1371 RtlInitUnicodeString(&UnicodeClassName,
1372 szTemp);
1373
1374 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1375 &UnicodeClassName,
1376 FALSE);
1377 if (!NT_SUCCESS(Status))
1378 {
1379 SetLastNtError(Status);
1380 _SEH2_LEAVE;
1381 }
1382 }
1383
1384 Ret = BufLen / sizeof(WCHAR);
1385 }
1386 else /* !Ansi */
1387 {
1388 BufLen = ClassName->MaximumLength;
1389
1390 /* query the atom name */
1391 Status = RtlQueryAtomInAtomTable(gAtomTable,
1392 Class->atomClassName,
1393 NULL,
1394 NULL,
1395 ClassName->Buffer,
1396 &BufLen);
1397
1398 if (!NT_SUCCESS(Status))
1399 {
1400 SetLastNtError(Status);
1401 _SEH2_LEAVE;
1402 }
1403
1404 Ret = BufLen / sizeof(WCHAR);
1405 }
1406 }
1407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1408 {
1409 SetLastNtError(_SEH2_GetExceptionCode());
1410 }
1411 _SEH2_END;
1412
1413 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1414 {
1415 ExFreePool(szTemp);
1416 }
1417
1418 return Ret;
1419 }
1420
1421 ULONG_PTR
1422 UserGetClassLongPtr(IN PCLS Class,
1423 IN INT Index,
1424 IN BOOL Ansi)
1425 {
1426 ULONG_PTR Ret = 0;
1427
1428 if (Index >= 0)
1429 {
1430 PULONG_PTR Data;
1431
1432 TRACE("GetClassLong(%d)\n", Index);
1433 if (Index + sizeof(ULONG_PTR) < Index ||
1434 Index + sizeof(ULONG_PTR) > Class->cbclsExtra)
1435 {
1436 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1437 return 0;
1438 }
1439
1440 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1441
1442 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1443 certain architectures, maybe using RtlCopyMemory is a
1444 better choice for those architectures! */
1445
1446 TRACE("Result: %x\n", Ret);
1447 return *Data;
1448 }
1449
1450 switch (Index)
1451 {
1452 case GCL_CBWNDEXTRA:
1453 Ret = (ULONG_PTR)Class->cbwndExtra;
1454 break;
1455
1456 case GCL_CBCLSEXTRA:
1457 Ret = (ULONG_PTR)Class->cbclsExtra;
1458 break;
1459
1460 case GCLP_HBRBACKGROUND:
1461 Ret = (ULONG_PTR)Class->hbrBackground;
1462 break;
1463
1464 case GCLP_HCURSOR:
1465 /* FIXME - get handle from pointer to CURSOR object */
1466 Ret = (ULONG_PTR)Class->hCursor;
1467 break;
1468
1469 case GCLP_HICON:
1470 /* FIXME - get handle from pointer to ICON object */
1471 Ret = (ULONG_PTR)Class->hIcon;
1472 break;
1473
1474 case GCLP_HICONSM:
1475 /* FIXME - get handle from pointer to ICON object */
1476 Ret = (ULONG_PTR)Class->hIconSm;
1477 break;
1478
1479 case GCLP_HMODULE:
1480 Ret = (ULONG_PTR)Class->hModule;
1481 break;
1482
1483 case GCLP_MENUNAME:
1484 /* NOTE: Returns pointer in kernel heap! */
1485 if (Ansi)
1486 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
1487 else
1488 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
1489 break;
1490
1491 case GCL_STYLE:
1492 Ret = (ULONG_PTR)Class->style;
1493 break;
1494
1495 case GCLP_WNDPROC:
1496 Ret = (ULONG_PTR)IntGetClassWndProc(Class,
1497 GetW32ProcessInfo(),
1498 Ansi);
1499 break;
1500
1501 case GCW_ATOM:
1502 Ret = (ULONG_PTR)Class->atomClassName;
1503 break;
1504
1505 default:
1506 SetLastWin32Error(ERROR_INVALID_INDEX);
1507 break;
1508 }
1509
1510 return Ret;
1511 }
1512
1513 static BOOL
1514 IntSetClassMenuName(IN PCLS Class,
1515 IN PUNICODE_STRING MenuName)
1516 {
1517 BOOL Ret = FALSE;
1518
1519 /* change the base class first */
1520 Class = Class->pclsBase;
1521
1522 if (MenuName->Length != 0)
1523 {
1524 ANSI_STRING AnsiString;
1525 PWSTR strBufW;
1526
1527 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
1528
1529 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1530 AnsiString.MaximumLength);
1531 if (strBufW != NULL)
1532 {
1533 _SEH2_TRY
1534 {
1535 NTSTATUS Status;
1536
1537 /* copy the unicode string */
1538 RtlCopyMemory(strBufW,
1539 MenuName->Buffer,
1540 MenuName->Length);
1541 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1542
1543 /* create an ansi copy of the string */
1544 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1545 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1546 MenuName,
1547 FALSE);
1548 if (!NT_SUCCESS(Status))
1549 {
1550 SetLastNtError(Status);
1551 _SEH2_LEAVE;
1552 }
1553
1554 Ret = TRUE;
1555 }
1556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1557 {
1558 SetLastNtError(_SEH2_GetExceptionCode());
1559 }
1560 _SEH2_END;
1561
1562 if (Ret)
1563 {
1564 /* update the base class */
1565 IntFreeClassMenuName(Class);
1566 Class->lpszClientUnicodeMenuName = strBufW;
1567 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1568 Class->MenuNameIsString = TRUE;
1569
1570 /* update the clones */
1571 Class = Class->pclsClone;
1572 while (Class != NULL)
1573 {
1574 Class->lpszClientUnicodeMenuName = strBufW;
1575 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1576 Class->MenuNameIsString = TRUE;
1577
1578 Class = Class->pclsNext;
1579 }
1580 }
1581 else
1582 {
1583 DPRINT1("Failed to copy class menu name!\n");
1584 UserHeapFree(strBufW);
1585 }
1586 }
1587 else
1588 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1589 }
1590 else
1591 {
1592 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1593
1594 /* update the base class */
1595 IntFreeClassMenuName(Class);
1596 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1597 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1598 Class->MenuNameIsString = FALSE;
1599
1600 /* update the clones */
1601 Class = Class->pclsClone;
1602 while (Class != NULL)
1603 {
1604 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1605 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1606 Class->MenuNameIsString = FALSE;
1607
1608 Class = Class->pclsNext;
1609 }
1610
1611 Ret = TRUE;
1612 }
1613
1614 return Ret;
1615 }
1616
1617 ULONG_PTR
1618 UserSetClassLongPtr(IN PCLS Class,
1619 IN INT Index,
1620 IN ULONG_PTR NewLong,
1621 IN BOOL Ansi)
1622 {
1623 ULONG_PTR Ret = 0;
1624
1625 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1626
1627 /* change the information in the base class first, then update the clones */
1628 Class = Class->pclsBase;
1629
1630 if (Index >= 0)
1631 {
1632 PULONG_PTR Data;
1633
1634 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1635
1636 if (Index + sizeof(ULONG_PTR) < Index ||
1637 Index + sizeof(ULONG_PTR) > Class->cbclsExtra)
1638 {
1639 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1640 return 0;
1641 }
1642
1643 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1644
1645 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1646 certain architectures, maybe using RtlCopyMemory is a
1647 better choice for those architectures! */
1648 Ret = *Data;
1649 *Data = NewLong;
1650
1651 /* update the clones */
1652 Class = Class->pclsClone;
1653 while (Class != NULL)
1654 {
1655 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1656 Class = Class->pclsNext;
1657 }
1658
1659 return Ret;
1660 }
1661
1662 switch (Index)
1663 {
1664 case GCL_CBWNDEXTRA:
1665 Ret = (ULONG_PTR)Class->cbwndExtra;
1666 Class->cbwndExtra = (INT)NewLong;
1667
1668 /* update the clones */
1669 Class = Class->pclsClone;
1670 while (Class != NULL)
1671 {
1672 Class->cbwndExtra = (INT)NewLong;
1673 Class = Class->pclsNext;
1674 }
1675
1676 break;
1677
1678 case GCL_CBCLSEXTRA:
1679 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1680 break;
1681
1682 case GCLP_HBRBACKGROUND:
1683 Ret = (ULONG_PTR)Class->hbrBackground;
1684 Class->hbrBackground = (HBRUSH)NewLong;
1685
1686 /* update the clones */
1687 Class = Class->pclsClone;
1688 while (Class != NULL)
1689 {
1690 Class->hbrBackground = (HBRUSH)NewLong;
1691 Class = Class->pclsNext;
1692 }
1693 break;
1694
1695 case GCLP_HCURSOR:
1696 /* FIXME - get handle from pointer to CURSOR object */
1697 Ret = (ULONG_PTR)Class->hCursor;
1698 Class->hCursor = (HANDLE)NewLong;
1699
1700 /* update the clones */
1701 Class = Class->pclsClone;
1702 while (Class != NULL)
1703 {
1704 Class->hCursor = (HANDLE)NewLong;
1705 Class = Class->pclsNext;
1706 }
1707 break;
1708
1709 case GCLP_HICON:
1710 /* FIXME - get handle from pointer to ICON object */
1711 Ret = (ULONG_PTR)Class->hIcon;
1712 Class->hIcon = (HANDLE)NewLong;
1713
1714 /* update the clones */
1715 Class = Class->pclsClone;
1716 while (Class != NULL)
1717 {
1718 Class->hIcon = (HANDLE)NewLong;
1719 Class = Class->pclsNext;
1720 }
1721 break;
1722
1723 case GCLP_HICONSM:
1724 /* FIXME - get handle from pointer to ICON object */
1725 Ret = (ULONG_PTR)Class->hIconSm;
1726 Class->hIconSm = (HANDLE)NewLong;
1727
1728 /* update the clones */
1729 Class = Class->pclsClone;
1730 while (Class != NULL)
1731 {
1732 Class->hIconSm = (HANDLE)NewLong;
1733 Class = Class->pclsNext;
1734 }
1735 break;
1736
1737 case GCLP_HMODULE:
1738 Ret = (ULONG_PTR)Class->hModule;
1739 Class->hModule = (HINSTANCE)NewLong;
1740
1741 /* update the clones */
1742 Class = Class->pclsClone;
1743 while (Class != NULL)
1744 {
1745 Class->hModule = (HINSTANCE)NewLong;
1746 Class = Class->pclsNext;
1747 }
1748 break;
1749
1750 case GCLP_MENUNAME:
1751 {
1752 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1753
1754 if (!IntSetClassMenuName(Class,
1755 Value))
1756 {
1757 DPRINT1("Setting the class menu name failed!\n");
1758 }
1759
1760 /* FIXME - really return NULL? Wine does so... */
1761 break;
1762 }
1763
1764 case GCL_STYLE:
1765 Ret = (ULONG_PTR)Class->style;
1766 Class->style = (UINT)NewLong;
1767
1768 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1769 move the class to the appropriate list? For now, we save
1770 the original value in Class->Global, so we can always
1771 locate the appropriate list */
1772
1773 /* update the clones */
1774 Class = Class->pclsClone;
1775 while (Class != NULL)
1776 {
1777 Class->style = (UINT)NewLong;
1778 Class = Class->pclsNext;
1779 }
1780 break;
1781
1782 case GCLP_WNDPROC:
1783 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1784 (WNDPROC)NewLong,
1785 Ansi);
1786 break;
1787
1788 case GCW_ATOM:
1789 {
1790 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1791
1792 Ret = (ULONG_PTR)Class->atomClassName;
1793 if (!IntSetClassAtom(Class,
1794 Value))
1795 {
1796 Ret = 0;
1797 }
1798 break;
1799 }
1800
1801 default:
1802 SetLastWin32Error(ERROR_INVALID_INDEX);
1803 break;
1804 }
1805
1806 return Ret;
1807 }
1808
1809 static BOOL
1810 UserGetClassInfo(IN PCLS Class,
1811 OUT PWNDCLASSEXW lpwcx,
1812 IN BOOL Ansi,
1813 HINSTANCE hInstance)
1814 {
1815 PPROCESSINFO pi;
1816
1817 lpwcx->style = Class->style;
1818
1819 pi = GetW32ProcessInfo();
1820 lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
1821 pi,
1822 Ansi);
1823
1824 lpwcx->cbClsExtra = Class->cbclsExtra;
1825 lpwcx->cbWndExtra = Class->cbwndExtra;
1826 lpwcx->hIcon = Class->hIcon; /* FIXME - get handle from pointer */
1827 lpwcx->hCursor = Class->hCursor; /* FIXME - get handle from pointer */
1828 lpwcx->hbrBackground = Class->hbrBackground;
1829 /*
1830 FIXME!
1831 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1832 lpszClientXxxMenuName should already be mapped to user space.
1833 */
1834 if (Ansi)
1835 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName;
1836 else
1837 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName;
1838
1839 if ( Class->lpszClientUnicodeMenuName != NULL &&
1840 Class->MenuNameIsString)
1841 {
1842 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ?
1843 (PVOID)Class->lpszClientAnsiMenuName :
1844 (PVOID)Class->lpszClientUnicodeMenuName);
1845 }
1846
1847 if (hInstance == hModClient)
1848 lpwcx->hInstance = NULL;
1849 else
1850 lpwcx->hInstance = hInstance;
1851
1852 /* FIXME - return the string? Okay! This is performed in User32!*/
1853 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
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 PCLS Class;
1870 BOOL Ret = TRUE;
1871
1872 if ( hModClient == NULL)
1873 return FALSE;
1874 /* Init System Classes once only*/
1875 if (RegisteredSysClasses)
1876 return TRUE;
1877
1878 RtlZeroMemory(&MenuName, sizeof(MenuName));
1879
1880 for (i = 0; i != Count; i++)
1881 {
1882 ClassName = ProbeForReadUnicodeString(&SystemClasses[i].ClassName);
1883 if (ClassName.Length != 0)
1884 {
1885 ProbeForRead(ClassName.Buffer,
1886 ClassName.Length,
1887 sizeof(WCHAR));
1888 }
1889
1890 wc.cbSize = sizeof(wc);
1891 wc.style = SystemClasses[i].Style;
1892 wc.lpfnWndProc = SystemClasses[i].ProcW;
1893 wc.cbClsExtra = 0;
1894 wc.cbWndExtra = SystemClasses[i].ExtraBytes;
1895 wc.hInstance = hModClient;
1896 wc.hIcon = NULL;
1897 wc.hCursor = SystemClasses[i].hCursor;
1898 wc.hbrBackground = SystemClasses[i].hBrush;
1899 wc.lpszMenuName = NULL;
1900 wc.lpszClassName = ClassName.Buffer;
1901 wc.hIconSm = NULL;
1902
1903 Class = IntCreateClass(&wc,
1904 &ClassName,
1905 &MenuName,
1906 SystemClasses[i].ProcA,
1907 SystemClasses[i].ClassId,
1908 CSF_SYSTEMCLASS,
1909 NULL,
1910 pi);
1911 if (Class != NULL)
1912 {
1913 ASSERT(Class->System);
1914 Class->pclsNext = SystemClassList;
1915 (void)InterlockedExchangePointer((PVOID*)&SystemClassList,
1916 Class);
1917 }
1918 else
1919 {
1920 WARN("!!! Registering system class failed!\n");
1921 Ret = FALSE;
1922 }
1923 }
1924
1925 if (Ret)
1926 RegisteredSysClasses = TRUE;
1927 return Ret;
1928 }
1929
1930 /* SYSCALLS *****************************************************************/
1931
1932 RTL_ATOM
1933 APIENTRY
1934 NtUserRegisterClassExWOW(
1935 WNDCLASSEXW* lpwcx,
1936 PUNICODE_STRING ClassName,
1937 PUNICODE_STRING ClsNVersion,
1938 PCLSMENUNAME pClassMenuName,
1939 DWORD fnID,
1940 DWORD Flags,
1941 LPDWORD pWow)
1942 /*
1943 * FUNCTION:
1944 * Registers a new class with the window manager
1945 * ARGUMENTS:
1946 * lpwcx = Win32 extended window class structure
1947 * bUnicodeClass = Whether to send ANSI or unicode strings
1948 * to window procedures
1949 * RETURNS:
1950 * Atom identifying the new class
1951 */
1952 {
1953 WNDCLASSEXW CapturedClassInfo = {0};
1954 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
1955 RTL_ATOM Ret = (RTL_ATOM)0;
1956 WNDPROC wpExtra = NULL;
1957
1958 if (Flags & ~(CSF_ANSIPROC))
1959 {
1960 SetLastWin32Error(ERROR_INVALID_FLAGS);
1961 return Ret;
1962 }
1963
1964 UserEnterExclusive();
1965
1966 _SEH2_TRY
1967 {
1968 /* Probe the parameters and basic parameter checks */
1969 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
1970 {
1971 goto InvalidParameter;
1972 }
1973
1974 ProbeForRead(lpwcx,
1975 sizeof(WNDCLASSEXW),
1976 sizeof(ULONG));
1977 RtlCopyMemory(&CapturedClassInfo,
1978 lpwcx,
1979 sizeof(WNDCLASSEXW));
1980
1981 CapturedName = ProbeForReadUnicodeString(ClassName);
1982
1983 ProbeForRead(pClassMenuName,
1984 sizeof(CLSMENUNAME),
1985 1);
1986
1987 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName);
1988
1989 if ( CapturedName.Length & 1 ||
1990 CapturedMenuName.Length & 1 ||
1991 CapturedClassInfo.cbClsExtra < 0 ||
1992 CapturedClassInfo.cbClsExtra +
1993 CapturedName.Length +
1994 CapturedMenuName.Length +
1995 sizeof(CLS) < CapturedClassInfo.cbClsExtra ||
1996 CapturedClassInfo.cbWndExtra < 0 ||
1997 CapturedClassInfo.hInstance == NULL)
1998 {
1999 goto InvalidParameter;
2000 }
2001
2002 if (CapturedName.Length != 0)
2003 {
2004 ProbeForRead(CapturedName.Buffer,
2005 CapturedName.Length,
2006 sizeof(WCHAR));
2007 }
2008 else
2009 {
2010 if (!IS_ATOM(CapturedName.Buffer))
2011 {
2012 goto InvalidParameter;
2013 }
2014 }
2015
2016 if (CapturedMenuName.Length != 0)
2017 {
2018 ProbeForRead(CapturedMenuName.Buffer,
2019 CapturedMenuName.Length,
2020 sizeof(WCHAR));
2021 }
2022 else if (CapturedMenuName.Buffer != NULL &&
2023 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2024 {
2025 InvalidParameter:
2026 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2027 _SEH2_LEAVE;
2028 }
2029 /* Register the class */
2030 Ret = UserRegisterClass(&CapturedClassInfo,
2031 &CapturedName,
2032 &CapturedMenuName,
2033 wpExtra,
2034 fnID,
2035 Flags);
2036 }
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2038 {
2039 SetLastNtError(_SEH2_GetExceptionCode());
2040 }
2041 _SEH2_END;
2042
2043 UserLeave();
2044
2045 return Ret;
2046 }
2047
2048 ULONG_PTR APIENTRY
2049 NtUserGetClassLong(IN HWND hWnd,
2050 IN INT Offset,
2051 IN BOOL Ansi)
2052 {
2053 PWINDOW_OBJECT Window;
2054 ULONG_PTR Ret = 0;
2055
2056 if (Offset != GCLP_WNDPROC)
2057 {
2058 UserEnterShared();
2059 }
2060 else
2061 {
2062 UserEnterExclusive();
2063 }
2064
2065 Window = UserGetWindowObject(hWnd);
2066 if (Window != NULL)
2067 {
2068 Ret = UserGetClassLongPtr(Window->Wnd->pcls,
2069 Offset,
2070 Ansi);
2071
2072 if (Ret != 0 && Offset == GCLP_MENUNAME && Window->Wnd->pcls->MenuNameIsString)
2073 {
2074 Ret = (ULONG_PTR)UserHeapAddressToUser((PVOID)Ret);
2075 }
2076 }
2077
2078 UserLeave();
2079
2080 return Ret;
2081 }
2082
2083
2084
2085 ULONG_PTR APIENTRY
2086 NtUserSetClassLong(HWND hWnd,
2087 INT Offset,
2088 ULONG_PTR dwNewLong,
2089 BOOL Ansi)
2090 {
2091 PPROCESSINFO pi;
2092 PWINDOW_OBJECT Window;
2093 ULONG_PTR Ret = 0;
2094
2095 UserEnterExclusive();
2096
2097 pi = GetW32ProcessInfo();
2098 if (pi == NULL)
2099 goto Cleanup;
2100
2101 Window = UserGetWindowObject(hWnd);
2102 if (Window != NULL)
2103 {
2104 if (Window->ti->ppi != pi)
2105 {
2106 SetLastWin32Error(ERROR_ACCESS_DENIED);
2107 goto Cleanup;
2108 }
2109
2110 _SEH2_TRY
2111 {
2112 UNICODE_STRING Value;
2113
2114 /* probe the parameters */
2115 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2116 {
2117 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2118 if (Value.Length & 1)
2119 {
2120 goto InvalidParameter;
2121 }
2122
2123 if (Value.Length != 0)
2124 {
2125 ProbeForRead(Value.Buffer,
2126 Value.Length,
2127 sizeof(WCHAR));
2128 }
2129 else
2130 {
2131 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2132 {
2133 goto InvalidParameter;
2134 }
2135 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2136 {
2137 InvalidParameter:
2138 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2139 _SEH2_LEAVE;
2140 }
2141 }
2142
2143 dwNewLong = (ULONG_PTR)&Value;
2144 }
2145
2146 Ret = UserSetClassLongPtr(Window->Wnd->pcls,
2147 Offset,
2148 dwNewLong,
2149 Ansi);
2150 }
2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2152 {
2153 SetLastNtError(_SEH2_GetExceptionCode());
2154 }
2155 _SEH2_END;
2156 }
2157
2158 Cleanup:
2159 UserLeave();
2160
2161 return Ret;
2162 }
2163
2164 WORD
2165 APIENTRY
2166 NtUserSetClassWord(
2167 HWND hWnd,
2168 INT nIndex,
2169 WORD wNewWord)
2170 {
2171 /*
2172 * NOTE: Obsoleted in 32-bit windows
2173 */
2174 return(0);
2175 }
2176
2177 BOOL APIENTRY
2178 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2179 IN HINSTANCE hInstance,
2180 OUT PCLSMENUNAME pClassMenuName)
2181 {
2182 UNICODE_STRING CapturedClassName;
2183 BOOL Ret = FALSE;
2184
2185 UserEnterExclusive();
2186
2187 _SEH2_TRY
2188 {
2189 /* probe the paramters */
2190 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2191 if (CapturedClassName.Length & 1)
2192 {
2193 goto InvalidParameter;
2194 }
2195
2196 if (CapturedClassName.Length != 0)
2197 {
2198 ProbeForRead(CapturedClassName.Buffer,
2199 CapturedClassName.Length,
2200 sizeof(WCHAR));
2201 }
2202 else
2203 {
2204 if (!IS_ATOM(CapturedClassName.Buffer))
2205 {
2206 InvalidParameter:
2207 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2208 _SEH2_LEAVE;
2209 }
2210 }
2211
2212 /* unregister the class */
2213 Ret = UserUnregisterClass(&CapturedClassName,
2214 hInstance);
2215 }
2216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2217 {
2218 SetLastNtError(_SEH2_GetExceptionCode());
2219 }
2220 _SEH2_END;
2221
2222 UserLeave();
2223 return Ret;
2224 }
2225
2226 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2227 BOOL APIENTRY
2228 NtUserGetClassInfo(
2229 HINSTANCE hInstance,
2230 PUNICODE_STRING ClassName,
2231 LPWNDCLASSEXW lpWndClassEx,
2232 LPWSTR *ppszMenuName,
2233 BOOL Ansi)
2234 {
2235 UNICODE_STRING CapturedClassName, SafeClassName;
2236 WNDCLASSEXW Safewcexw;
2237 PCLS Class;
2238 RTL_ATOM ClassAtom = 0;
2239 PPROCESSINFO pi;
2240 BOOL Ret = TRUE;
2241
2242 /* NOTE: need exclusive lock because getting the wndproc might require the
2243 creation of a call procedure handle */
2244 UserEnterExclusive();
2245
2246 pi = GetW32ProcessInfo();
2247 if (pi == NULL)
2248 {
2249 ERR("GetW32ProcessInfo() returned NULL!\n");
2250 goto Cleanup;
2251 }
2252
2253 _SEH2_TRY
2254 {
2255 /* probe the paramters */
2256 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2257
2258 if (CapturedClassName.Length == 0)
2259 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2260 else
2261 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2262
2263 if (CapturedClassName.Length & 1)
2264 {
2265 goto InvalidParameter;
2266 }
2267
2268 if (CapturedClassName.Length != 0)
2269 {
2270 ProbeForRead( CapturedClassName.Buffer,
2271 CapturedClassName.Length,
2272 sizeof(WCHAR));
2273
2274 RtlInitUnicodeString( &SafeClassName, CapturedClassName.Buffer);
2275
2276 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2277 SafeClassName.MaximumLength,
2278 TAG_STRING);
2279 RtlCopyMemory( SafeClassName.Buffer,
2280 CapturedClassName.Buffer,
2281 SafeClassName.MaximumLength);
2282 }
2283 else
2284 {
2285 if (!IS_ATOM(CapturedClassName.Buffer))
2286 {
2287 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2288 goto InvalidParameter;
2289 }
2290
2291 SafeClassName.Buffer = CapturedClassName.Buffer;
2292 SafeClassName.Length = 0;
2293 SafeClassName.MaximumLength = 0;
2294 }
2295
2296 if (ProbeForReadUint(&lpWndClassEx->cbSize) != sizeof(WNDCLASSEXW))
2297 {
2298 InvalidParameter:
2299 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2300 Ret = FALSE;
2301 _SEH2_LEAVE;
2302 }
2303
2304 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2305
2306 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2307 }
2308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2309 {
2310 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2311 Ret = FALSE;
2312 }
2313 _SEH2_END;
2314
2315 if (Ret)
2316 {
2317 ClassAtom = IntGetClassAtom( &SafeClassName,
2318 hInstance,
2319 pi,
2320 &Class,
2321 NULL);
2322 if (ClassAtom != (RTL_ATOM)0)
2323 {
2324 if (hInstance == NULL) hInstance = hModClient;
2325
2326 Ret = UserGetClassInfo( Class,
2327 &Safewcexw,
2328 Ansi,
2329 hInstance);
2330 }
2331 else
2332 {
2333 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2334 Ret = FALSE;
2335 }
2336 }
2337 _SEH2_TRY
2338 {
2339 if (Ret)
2340 {
2341 /* Emulate Function. */
2342 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2343
2344 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2345
2346 // From Wine:
2347 /* We must return the atom of the class here instead of just TRUE. */
2348 /* Undocumented behavior! Return the class atom as a BOOL! */
2349 Ret = (BOOL)ClassAtom;
2350 }
2351 }
2352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2353 {
2354 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2355 Ret = FALSE;
2356 }
2357 _SEH2_END;
2358
2359 Cleanup:
2360 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2361 UserLeave();
2362 return Ret;
2363 }
2364
2365
2366
2367 INT APIENTRY
2368 NtUserGetClassName (IN HWND hWnd,
2369 OUT PUNICODE_STRING ClassName,
2370 IN BOOL Ansi)
2371 {
2372 PWINDOW_OBJECT Window;
2373 UNICODE_STRING CapturedClassName;
2374 INT Ret = 0;
2375
2376 UserEnterShared();
2377
2378 Window = UserGetWindowObject(hWnd);
2379 if (Window != NULL)
2380 {
2381 _SEH2_TRY
2382 {
2383 ProbeForWriteUnicodeString(ClassName);
2384 CapturedClassName = *ClassName;
2385
2386 /* get the class name */
2387 Ret = UserGetClassName(Window->Wnd->pcls,
2388 &CapturedClassName,
2389 Ansi);
2390
2391 if (Ret != 0)
2392 {
2393 /* update the Length field */
2394 ClassName->Length = CapturedClassName.Length;
2395 }
2396 }
2397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2398 {
2399 SetLastNtError(_SEH2_GetExceptionCode());
2400 }
2401 _SEH2_END;
2402 }
2403
2404 UserLeave();
2405
2406 return Ret;
2407 }
2408
2409 /* Return Pointer to Class structure. */
2410 PCLS APIENTRY
2411 NtUserGetWOWClass(HINSTANCE hInstance,
2412 PUNICODE_STRING ClassName)
2413 {
2414 UNICODE_STRING SafeClassName;
2415 PPROCESSINFO pi;
2416 PCLS Class = NULL;
2417 RTL_ATOM ClassAtom = 0;
2418 BOOL Hit = FALSE;
2419
2420 UserEnterExclusive();
2421
2422 pi = GetW32ProcessInfo();
2423 if (pi == NULL)
2424 {
2425 ERR("GetW32ProcessInfo() returned NULL!\n");
2426 goto Cleanup;
2427 }
2428
2429 _SEH2_TRY
2430 {
2431 if (ClassName->Length != 0)
2432 {
2433 ProbeForRead( ClassName->Buffer,
2434 ClassName->Length,
2435 sizeof(WCHAR));
2436
2437 RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
2438
2439 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2440 SafeClassName.MaximumLength,
2441 TAG_STRING);
2442 RtlCopyMemory( SafeClassName.Buffer,
2443 ClassName->Buffer,
2444 SafeClassName.MaximumLength);
2445 }
2446 else
2447 {
2448 if (!IS_ATOM(ClassName->Buffer))
2449 {
2450 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2451 Hit = TRUE;
2452 }
2453 else
2454 {
2455 SafeClassName.Buffer = ClassName->Buffer;
2456 SafeClassName.Length = 0;
2457 SafeClassName.MaximumLength = 0;
2458 }
2459 }
2460 }
2461 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2462 {
2463 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2464 Hit = TRUE;
2465 }
2466 _SEH2_END;
2467
2468 if (!Hit)
2469 {
2470 ClassAtom = IntGetClassAtom( &SafeClassName,
2471 hInstance,
2472 pi,
2473 &Class,
2474 NULL);
2475 if (!ClassAtom)
2476 {
2477 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2478 }
2479 }
2480
2481 Cleanup:
2482 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2483 UserLeave();
2484 //
2485 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2486 //
2487 return Class;
2488 }
2489
2490 /* EOF */