ReactOS 0.4.15-dev-5893-g1bb4167
class.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: win32ss/user/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
7 */
8
9#include <win32k.h>
11
13{
14 L"Button",
15 L"Edit",
16 L"Static",
17 L"ListBox",
18 L"ScrollBar",
19 L"ComboBox",
20 L"MDIClient",
21 L"ComboLBox",
22 L"DDEMLEvent",
23 L"DDEMLMom",
24 L"DMGClass",
25 L"DDEMLAnsiClient",
26 L"DDEMLUnicodeClient",
27 L"DDEMLAnsiServer",
28 L"DDEMLUnicodeServer",
29 L"IME",
30 L"Ghost",
31};
32
34
36{
37 { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
39 NULL, // Use User32 procs
40 sizeof(ULONG)*2,
42 (HBRUSH)(COLOR_BACKGROUND),
45 },
46 { ((PWSTR)((ULONG_PTR)(WORD)(0x8003))),
48 NULL, // Use User32 procs
49 sizeof(LONG),
51 NULL,
54 },
55 { ((PWSTR)((ULONG_PTR)(WORD)(0x8000))),
57 NULL, // Use User32 procs
58 sizeof(LONG),
60 (HBRUSH)(COLOR_MENU + 1),
63 },
64 { L"ScrollBar",
66 NULL, // Use User32 procs
67 sizeof(SBWND)-sizeof(WND),
69 NULL,
72 },
73#if 0
74 { ((PWSTR)((ULONG_PTR)(WORD)(0x8006))), // Tooltips
76 NULL, // Use User32 procs
77 0,
79 0,
82 },
83#endif
84 { ((PWSTR)((ULONG_PTR)(WORD)(0x8004))), // IconTitle is here for now...
85 0,
86 NULL, // Use User32 procs
87 0,
89 0,
92 },
93 { L"Message",
95 NULL, // Use User32 procs
96 0,
98 NULL,
100 ICLS_HWNDMESSAGE
101 }
102};
103
104static struct
105{
106 int FnId;
107 int ClsId;
108} FnidToiCls[] =
109{ /* Function Ids to Class indexes. */
115 { FNID_MESSAGEWND, ICLS_HWNDMESSAGE},
124 { FNID_IME, ICLS_IME},
128
129BOOL
131LookupFnIdToiCls(int FnId, int *iCls )
132{
133 int i;
134
135 for ( i = 0; i < ARRAYSIZE(FnidToiCls); i++)
136 {
137 if (FnidToiCls[i].FnId == FnId)
138 {
139 if (iCls) *iCls = FnidToiCls[i].ClsId;
140 return TRUE;
141 }
142 }
143 if (iCls) *iCls = 0;
144 return FALSE;
145}
146
149NTAPI
151 _Out_ _When_(return>=0, _At_(pustrOut->Buffer, _Post_ _Notnull_)) PUNICODE_STRING pustrOut,
152 __in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe)
153{
155
156 /* Default to NULL */
157 pustrOut->Buffer = NULL;
158
160 {
161 ProbeForRead(pustrUnsafe, sizeof(UNICODE_STRING), 1);
162
163 /* Validate the string */
164 if ((pustrUnsafe->Length & 1) || (pustrUnsafe->Buffer == NULL))
165 {
166 /* This is not legal */
168 }
169
170 /* Check if this is an atom */
171 if (IS_ATOM(pustrUnsafe->Buffer))
172 {
173 /* Copy the atom, length is 0 */
174 pustrOut->MaximumLength = pustrOut->Length = 0;
175 pustrOut->Buffer = pustrUnsafe->Buffer;
176 }
177 else
178 {
179 /* Get the length, maximum length includes zero termination */
180 pustrOut->Length = pustrUnsafe->Length;
181 pustrOut->MaximumLength = pustrOut->Length + sizeof(WCHAR);
182
183 /* Allocate a buffer */
184 pustrOut->Buffer = ExAllocatePoolWithTag(PagedPool,
185 pustrOut->MaximumLength,
186 TAG_STRING);
187 if (!pustrOut->Buffer)
188 {
190 }
191
192 /* Copy the string and zero terminate it */
193 ProbeForRead(pustrUnsafe->Buffer, pustrOut->Length, 1);
194 RtlCopyMemory(pustrOut->Buffer, pustrUnsafe->Buffer, pustrOut->Length);
195 pustrOut->Buffer[pustrOut->Length / sizeof(WCHAR)] = L'\0';
196 }
197 }
199 {
200 /* Check if we already allocated a buffer */
201 if (pustrOut->Buffer)
202 {
203 /* Free the buffer */
204 ExFreePoolWithTag(pustrOut->Buffer, TAG_STRING);
206 }
207 }
208 _SEH2_END;
209
210 return Status;
211}
212
213/* WINDOWCLASS ***************************************************************/
214
215static VOID
217{
218 /* Free the menu name, if it was changed and allocated */
219 if (Class->lpszClientUnicodeMenuName != NULL && Class->MenuNameIsString)
220 {
221 UserHeapFree(Class->lpszClientUnicodeMenuName);
222 Class->lpszClientUnicodeMenuName = NULL;
223 Class->lpszClientAnsiMenuName = NULL;
224 }
225}
226
227static VOID
229{
230 PDESKTOP pDesk;
231
232 /* There shouldn't be any clones anymore */
233 ASSERT(Class->cWndReferenceCount == 0);
234 ASSERT(Class->pclsClone == NULL);
235
236 if (Class->pclsBase == Class)
237 {
238 PCALLPROCDATA CallProc, NextCallProc;
239
240 /* Destroy allocated callproc handles */
241 CallProc = Class->spcpdFirst;
242 while (CallProc != NULL)
243 {
244 NextCallProc = CallProc->spcpdNext;
245
246 CallProc->spcpdNext = NULL;
247 DestroyCallProc(CallProc);
248
249 CallProc = NextCallProc;
250 }
251
252 // Fixes running the static test then run class test issue.
253 // Some applications do not use UnregisterClass before exiting.
254 // Keep from reusing the same atom with case insensitive
255 // comparisons, remove registration of the atom if not zeroed.
256 if (Class->atomClassName)
257 IntDeregisterClassAtom(Class->atomClassName);
258 // Dereference non-versioned class name
259 if (Class->atomNVClassName)
260 IntDeregisterClassAtom(Class->atomNVClassName);
261
262 if (Class->pdce)
263 {
264 DceFreeClassDCE(Class->pdce);
265 Class->pdce = NULL;
266 }
267
269 }
270
271 if (Class->spicn)
273 if (Class->spcur)
275 if (Class->spicnSm)
276 {
278 /* Destroy the icon if we own it */
279 if ((Class->CSF_flags & CSF_CACHEDSMICON)
282 }
283
284 pDesk = Class->rpdeskParent;
285 Class->rpdeskParent = NULL;
286
287 /* Free the structure */
288 if (pDesk != NULL)
289 {
290 DesktopHeapFree(pDesk, Class);
291 }
292 else
293 {
295 }
296}
297
298
299/* Clean all process classes. all process windows must cleaned first!! */
301{
302 PCLS Class;
304
305 if (pi != NULL)
306 {
307 /* Free all local classes */
308 Class = pi->pclsPrivateList;
309 while (Class != NULL)
310 {
311 pi->pclsPrivateList = Class->pclsNext;
312
313 ASSERT(Class->pclsBase == Class);
315
316 Class = pi->pclsPrivateList;
317 }
318
319 /* Free all global classes */
320 Class = pi->pclsPublicList;
321 while (Class != NULL)
322 {
323 pi->pclsPublicList = Class->pclsNext;
324
325 ASSERT(Class->pclsBase == Class);
327
328 Class = pi->pclsPublicList;
329 }
330 }
331}
332
333static BOOL
335 OUT RTL_ATOM *pAtom)
336{
337 WCHAR szBuf[65];
338 PWSTR AtomName = szBuf;
340
341 if (ClassName->Length != 0)
342 {
343 if (ClassName->Length + sizeof(UNICODE_NULL) > sizeof(szBuf))
344 {
346 ClassName->Length + sizeof(UNICODE_NULL),
347 TAG_USTR);
348
349 if (AtomName == NULL)
350 {
352 return FALSE;
353 }
354 }
355
357 {
358 RtlCopyMemory(AtomName,
359 ClassName->Buffer,
360 ClassName->Length);
361 }
363 {
364 if (AtomName != szBuf)
365 ExFreePoolWithTag(AtomName, TAG_USTR);
367 _SEH2_YIELD(return FALSE);
368 }
369 _SEH2_END;
370 AtomName[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
371 }
372 else
373 {
374 ASSERT(IS_ATOM(ClassName->Buffer));
375 AtomName = ClassName->Buffer;
376 }
377
379 AtomName,
380 pAtom);
381
382 if (AtomName != ClassName->Buffer && AtomName != szBuf)
383 ExFreePoolWithTag(AtomName, TAG_USTR);
384
385
386 if (!NT_SUCCESS(Status))
387 {
389 return FALSE;
390 }
391
392 return TRUE;
393}
394
397{
399 UNICODE_STRING ClassName;
400 INT i = 0;
401
402 while ( i < ICLS_DESKTOP)
403 {
404 RtlInitUnicodeString(&ClassName, ControlsList[i]);
405 if (IntRegisterClassAtom(&ClassName, &Atom))
406 {
408 TRACE("Reg Control Atom %ls: 0x%x\n", ControlsList[i], Atom);
409 }
410 i++;
411 }
412 return TRUE;
413}
414
415static NTSTATUS
417{
419 Atom);
420}
421
422VOID
424 IN PCALLPROCDATA CallProc)
425{
426 PCLS BaseClass;
427
428 ASSERT(CallProc->spcpdNext == NULL);
429
430 BaseClass = Class->pclsBase;
431 ASSERT(CallProc->spcpdNext == NULL);
432 CallProc->spcpdNext = BaseClass->spcpdFirst;
433 BaseClass->spcpdFirst = CallProc;
434
435 /* Update all clones */
436 Class = Class->pclsClone;
437 while (Class != NULL)
438 {
439 Class->spcpdFirst = BaseClass->spcpdFirst;
440 Class = Class->pclsNext;
441 }
442}
443
444static BOOL
446 IN PUNICODE_STRING ClassName)
447{
449
450 /* Update the base class first */
451 Class = Class->pclsBase;
452 if (ClassName->Length > 0)
453 {
454 if (!IntRegisterClassAtom(ClassName,
455 &Atom))
456 {
457 ERR("RegisterClassAtom failed ! %x\n", EngGetLastError());
458 return FALSE;
459 }
460 }
461 else
462 {
463 if (IS_ATOM(ClassName->Buffer))
464 {
465 Atom = (ATOM)((ULONG_PTR)ClassName->Buffer & 0xffff); // XXX: are we missing refcount here ?
466 }
467 else
468 {
470 return FALSE;
471 }
472 }
473
474 IntDeregisterClassAtom(Class->atomNVClassName);
475
476 Class->atomNVClassName = Atom;
477
478 /* Update the clones */
479 Class = Class->pclsClone;
480 while (Class != NULL)
481 {
482 Class->atomNVClassName = Atom;
483
484 Class = Class->pclsNext;
485 }
486
487 return TRUE;
488}
489
490//
491// Same as User32:IntGetClsWndProc.
492//
495{
496 INT i;
497 WNDPROC gcpd = NULL, Ret = NULL;
498
499 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
500 {
501 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
502 {
503 if (GETPFNSERVER(i) == Class->lpfnWndProc)
504 {
505 if (Ansi)
506 Ret = GETPFNCLIENTA(i);
507 else
508 Ret = GETPFNCLIENTW(i);
509 }
510 }
511 return Ret;
512 }
513 Ret = Class->lpfnWndProc;
514
515 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
516 {
517 if (Ansi)
518 {
519 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
520 Ret = GETPFNCLIENTA(Class->fnid);
521 }
522 else
523 {
524 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
525 Ret = GETPFNCLIENTW(Class->fnid);
526 }
527 }
528
529 if ( Ret != Class->lpfnWndProc ||
530 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
531 return Ret;
532
533 gcpd = (WNDPROC)UserGetCPD( Class,
535 (ULONG_PTR)Ret);
536
537 return (gcpd ? gcpd : Ret);
538}
539
540
541static
545 IN BOOL Ansi)
546{
547 INT i;
548 PCALLPROCDATA pcpd;
549 WNDPROC Ret, chWndProc;
550
551 Ret = IntGetClassWndProc(Class, Ansi);
552
553 // If Server Side, downgrade to Client Side.
554 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
555 {
556 if (Ansi) Class->CSF_flags |= CSF_ANSIPROC;
557 Class->CSF_flags &= ~CSF_SERVERSIDEPROC;
558 Class->Unicode = !Ansi;
559 }
560
561 if (!WndProc) WndProc = Class->lpfnWndProc;
562
563 chWndProc = WndProc;
564
565 // Check if CallProc handle and retrieve previous call proc address and set.
567 {
569 if (pcpd) chWndProc = pcpd->pfnClientPrevious;
570 }
571
572 Class->lpfnWndProc = chWndProc;
573
574 // Clear test proc.
575 chWndProc = NULL;
576
577 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
578 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
579 {
580 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
581 {
582 chWndProc = GETPFNSERVER(i);
583 break;
584 }
585 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
586 {
587 chWndProc = GETPFNSERVER(i);
588 break;
589 }
590 }
591 // If match, set/reset to Server Side and clear ansi.
592 if (chWndProc)
593 {
594 Class->lpfnWndProc = chWndProc;
595 Class->Unicode = TRUE;
596 Class->CSF_flags &= ~CSF_ANSIPROC;
597 Class->CSF_flags |= CSF_SERVERSIDEPROC;
598 }
599 else
600 {
601 Class->Unicode = !Ansi;
602
603 if (Ansi)
604 Class->CSF_flags |= CSF_ANSIPROC;
605 else
606 Class->CSF_flags &= ~CSF_ANSIPROC;
607 }
608
609 /* Update the clones */
610 chWndProc = Class->lpfnWndProc;
611
612 Class = Class->pclsClone;
613 while (Class != NULL)
614 {
615 Class->Unicode = !Ansi;
616 Class->lpfnWndProc = chWndProc;
617
618 Class = Class->pclsNext;
619 }
620
621 return Ret;
622}
623
624static PCLS
626 IN OUT PCLS *ClassLink,
628{
629 SIZE_T ClassSize;
630 PCLS Class;
631
632 ASSERT(Desktop != NULL);
633 ASSERT(BaseClass->pclsBase == BaseClass);
634
635 if (BaseClass->rpdeskParent == Desktop)
636 {
637 /* It is most likely that a window is created on the same
638 desktop as the window class. */
639
640 return BaseClass;
641 }
642
643 if (BaseClass->rpdeskParent == NULL)
644 {
645 ASSERT(BaseClass->cWndReferenceCount == 0);
646 ASSERT(BaseClass->pclsClone == NULL);
647
648 /* Classes are also located in the shared heap when the class
649 was created before the thread attached to a desktop. As soon
650 as a window is created for such a class located on the shared
651 heap, the class is cloned into the desktop heap on which the
652 window is created. */
653 Class = NULL;
654 }
655 else
656 {
657 /* The user is asking for a class object on a different desktop,
658 try to find one! */
659 Class = BaseClass->pclsClone;
660 while (Class != NULL)
661 {
662 if (Class->rpdeskParent == Desktop)
663 {
664 ASSERT(Class->pclsBase == BaseClass);
665 ASSERT(Class->pclsClone == NULL);
666 break;
667 }
668
669 Class = Class->pclsNext;
670 }
671 }
672
673 if (Class == NULL)
674 {
675 /* The window is created on a different desktop, we need to
676 clone the class object to the desktop heap of the window! */
677 ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->cbclsExtra;
678
680 ClassSize);
681
682 if (Class != NULL)
683 {
684 /* Simply clone the class */
685 RtlCopyMemory( Class, BaseClass, ClassSize);
686
687 /* Reference our objects */
688 if (Class->spcur)
690 if (Class->spicn)
692 if (Class->spicnSm)
693 UserReferenceObject(Class->spicnSm);
694
695 TRACE("Clone Class 0x%p hM 0x%p\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
696
697 /* Restore module address if default user class Ref: Bug 4778 */
698 if ( Class->hModule != hModClient &&
699 Class->fnid <= FNID_GHOST &&
700 Class->fnid >= FNID_BUTTON )
701 {
702 Class->hModule = hModClient;
703 TRACE("Clone Class 0x%p Reset hM 0x%p\n",Class, Class->hModule);
704 }
705
706 /* Update some pointers and link the class */
707 Class->rpdeskParent = Desktop;
708 Class->cWndReferenceCount = 0;
709
710 if (BaseClass->rpdeskParent == NULL)
711 {
712 /* We don't really need the base class on the shared
713 heap anymore, delete it so the only class left is
714 the clone we just created, which now serves as the
715 new base class */
716 ASSERT(BaseClass->pclsClone == NULL);
717 ASSERT(Class->pclsClone == NULL);
718 Class->pclsBase = Class;
719 Class->pclsNext = BaseClass->pclsNext;
720
721 /* Replace the base class */
723 Class);
724
725 /* Destroy the obsolete copy on the shared heap */
726 BaseClass->pclsBase = NULL;
727 BaseClass->pclsClone = NULL;
728 IntDestroyClass(BaseClass);
729 }
730 else
731 {
732 /* Link in the clone */
733 Class->pclsClone = NULL;
734 Class->pclsBase = BaseClass;
735 Class->pclsNext = BaseClass->pclsClone;
736 (void)InterlockedExchangePointer((PVOID*)&BaseClass->pclsClone,
737 Class);
738 }
739 }
740 else
741 {
743 }
744 }
745 return Class;
746}
747
748PCLS
750 IN OUT PCLS *ClassLink,
752{
753 PCLS Class;
754 ASSERT(BaseClass->pclsBase == BaseClass);
755
756 if (Desktop != NULL)
757 {
758 Class = IntGetClassForDesktop(BaseClass,
759 ClassLink,
760 Desktop);
761 }
762 else
763 {
764 Class = BaseClass;
765 }
766
767 if (Class != NULL)
768 {
769 Class->cWndReferenceCount++;
770 }
771
772 return Class;
773}
774
775static
776VOID
778 IN OUT PCLS *BaseClassLink,
779 IN OUT PCLS *CloneLink)
780{
781 PCLS Clone;
782
783 ASSERT(Class->pclsBase != Class);
784 ASSERT(Class->pclsBase->pclsClone != NULL);
785 ASSERT(Class->rpdeskParent != NULL);
786 ASSERT(Class->cWndReferenceCount != 0);
787 ASSERT(Class->pclsBase->rpdeskParent != NULL);
788 ASSERT(Class->pclsBase->cWndReferenceCount == 0);
789
790 /* Unlink the clone */
791 *CloneLink = Class->pclsNext;
792 Class->pclsClone = Class->pclsBase->pclsClone;
793
794 /* Update the class information to make it a base class */
795 Class->pclsBase = Class;
796 Class->pclsNext = (*BaseClassLink)->pclsNext;
797
798 /* Update all clones */
799 Clone = Class->pclsClone;
800 while (Clone != NULL)
801 {
802 ASSERT(Clone->pclsClone == NULL);
803 Clone->pclsBase = Class;
804
805 Clone = Clone->pclsNext;
806 }
807
808 /* Link in the new base class */
809 (void)InterlockedExchangePointer((PVOID*)BaseClassLink,
810 Class);
811}
812
813
814VOID
818{
819 PCLS *PrevLink, BaseClass, CurrentClass;
820
821 ASSERT(Class->cWndReferenceCount >= 1);
822
823 BaseClass = Class->pclsBase;
824
825 if (--Class->cWndReferenceCount == 0)
826 {
827 if (BaseClass == Class)
828 {
829 ASSERT(Class->pclsBase == Class);
830
831 TRACE("IntDereferenceClass 0x%p\n", Class);
832 /* Check if there are clones of the class on other desktops,
833 link the first clone in if possible. If there are no clones
834 then leave the class on the desktop heap. It will get moved
835 to the shared heap when the thread detaches. */
836 if (BaseClass->pclsClone != NULL)
837 {
838 if (BaseClass->Global)
839 PrevLink = &pi->pclsPublicList;
840 else
841 PrevLink = &pi->pclsPrivateList;
842
843 CurrentClass = *PrevLink;
844 while (CurrentClass != BaseClass)
845 {
846 ASSERT(CurrentClass != NULL);
847
848 PrevLink = &CurrentClass->pclsNext;
849 CurrentClass = CurrentClass->pclsNext;
850 }
851
852 ASSERT(*PrevLink == BaseClass);
853
854 /* Make the first clone become the new base class */
856 PrevLink,
857 &BaseClass->pclsClone);
858
859 /* Destroy the class, there's still another clone of the class
860 that now serves as a base class. Make sure we don't destruct
861 resources shared by all classes (Base = NULL)! */
862 BaseClass->pclsBase = NULL;
863 BaseClass->pclsClone = NULL;
864 IntDestroyClass(BaseClass);
865 }
866 }
867 else
868 {
869 TRACE("IntDereferenceClass1 0x%p\n", Class);
870
871 /* Locate the cloned class and unlink it */
872 PrevLink = &BaseClass->pclsClone;
873 CurrentClass = BaseClass->pclsClone;
874 while (CurrentClass != Class)
875 {
876 ASSERT(CurrentClass != NULL);
877
878 PrevLink = &CurrentClass->pclsNext;
879 CurrentClass = CurrentClass->pclsNext;
880 }
881
882 ASSERT(CurrentClass == Class);
883
885 Class->pclsNext);
886
887 ASSERT(Class->pclsBase == BaseClass);
888 ASSERT(Class->pclsClone == NULL);
889
890 /* The class was just a clone, we don't need it anymore */
892 }
893 }
894}
895
896static BOOL
898 IN OUT PCLS **ClassLinkPtr)
899{
900 PCLS NewClass;
901 SIZE_T ClassSize;
902
903 ASSERT(Class->pclsBase == Class);
904 ASSERT(Class->rpdeskParent != NULL);
905 ASSERT(Class->cWndReferenceCount == 0);
906 ASSERT(Class->pclsClone == NULL);
907
908 ClassSize = sizeof(*Class) + (SIZE_T)Class->cbclsExtra;
909
910 /* Allocate the new base class on the shared heap */
911 NewClass = UserHeapAlloc(ClassSize);
912 if (NewClass != NULL)
913 {
914 RtlCopyMemory(NewClass,
915 Class,
916 ClassSize);
917
918 NewClass->rpdeskParent = NULL;
919 NewClass->pclsBase = NewClass;
920
921 if (NewClass->spcur)
922 UserReferenceObject(NewClass->spcur);
923 if (NewClass->spicn)
924 UserReferenceObject(NewClass->spicn);
925 if (NewClass->spicnSm)
926 UserReferenceObject(NewClass->spicnSm);
927
928 /* Replace the class in the list */
929 (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
930 NewClass);
931 *ClassLinkPtr = &NewClass->pclsNext;
932
933 /* Free the obsolete class on the desktop heap */
934 Class->pclsBase = NULL;
936 return TRUE;
937 }
938
939 return FALSE;
940}
941
942static VOID
944 IN OUT PCLS *ClassList,
945 IN BOOL FreeOnFailure,
946 OUT BOOL *Ret)
947{
948 PCLS Class, NextClass, *Link;
949
950 /* NOTE: We only need to check base classes! When classes are no longer needed
951 on a desktop, the clones will be freed automatically as soon as possible.
952 However, we need to move base classes to the shared heap, as soon as
953 the last desktop heap where a class is allocated on is about to be destroyed.
954 If we didn't move the class to the shared heap, the class would become
955 inaccessible! */
956
957 ASSERT(Desktop != NULL);
958
959 Link = ClassList;
960 Class = *Link;
961 while (Class != NULL)
962 {
963 NextClass = Class->pclsNext;
964
965 ASSERT(Class->pclsBase == Class);
966
967 if (Class->rpdeskParent == Desktop &&
968 Class->cWndReferenceCount == 0)
969 {
970 /* There shouldn't be any clones around anymore! */
971 ASSERT(Class->pclsClone == NULL);
972
973 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
974 /* FIXME: We could move the class to another desktop heap if there's still desktops
975 mapped into the process... */
976
977 /* Move the class to the shared heap */
979 &Link))
980 {
981 ASSERT(*Link == NextClass);
982 }
983 else
984 {
985 ASSERT(NextClass == Class->pclsNext);
986
987 if (FreeOnFailure)
988 {
989 /* Unlink the base class */
991 Class->pclsNext);
992
993 /* We can free the old base class now */
994 Class->pclsBase = NULL;
996 }
997 else
998 {
999 Link = &Class->pclsNext;
1000 *Ret = FALSE;
1001 }
1002 }
1003 }
1004 else
1005 Link = &Class->pclsNext;
1006
1007 Class = NextClass;
1008 }
1009}
1010
1011BOOL
1013 IN BOOL FreeOnFailure)
1014{
1016 BOOL Ret = TRUE;
1017
1019
1020 /* Check all local classes */
1022 &pi->pclsPrivateList,
1023 FreeOnFailure,
1024 &Ret);
1025
1026 /* Check all global classes */
1028 &pi->pclsPublicList,
1029 FreeOnFailure,
1030 &Ret);
1031 if (!Ret)
1032 {
1033 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
1035 }
1036
1037 return Ret;
1038}
1039
1040PCLS
1043 IN PUNICODE_STRING ClassName,
1044 IN PUNICODE_STRING ClassVersion,
1045 IN PUNICODE_STRING MenuName,
1046 IN DWORD fnID,
1050{
1051 SIZE_T ClassSize;
1052 PCLS Class = NULL;
1053 RTL_ATOM Atom, verAtom;
1055 PWSTR pszMenuName = NULL;
1057
1058 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
1059 lpwcx, ClassName, MenuName, dwFlags, Desktop, pi);
1060
1061 if (!IntRegisterClassAtom(ClassName,
1062 &Atom))
1063 {
1064 ERR("Failed to register class atom!\n");
1065 return NULL;
1066 }
1067
1068 if (!IntRegisterClassAtom(ClassVersion,
1069 &verAtom))
1070 {
1071 ERR("Failed to register version class atom!\n");
1073 return NULL;
1074 }
1075
1076 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
1077 if (MenuName->Length != 0)
1078 {
1079 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1080 RtlUnicodeStringToAnsiSize(MenuName));
1081 if (pszMenuName == NULL)
1082 goto NoMem;
1083 }
1084
1085 if (Desktop != NULL)
1086 {
1088 ClassSize);
1089 }
1090 else
1091 {
1092 /* FIXME: The class was created before being connected
1093 to a desktop. It is possible for the desktop window,
1094 but should it be allowed for any other case? */
1095 TRACE("This CLASS has no Desktop to heap from! Atom %u\n",Atom);
1096 Class = UserHeapAlloc(ClassSize);
1097 }
1098
1099 if (Class != NULL)
1100 {
1101 int iCls = 0;
1102
1103 RtlZeroMemory(Class, ClassSize);
1104
1105 Class->rpdeskParent = Desktop;
1106 Class->pclsBase = Class;
1107 Class->atomClassName = verAtom;
1108 Class->atomNVClassName = Atom;
1109 Class->fnid = fnID;
1110 Class->CSF_flags = dwFlags;
1111
1112 if (LookupFnIdToiCls(Class->fnid, &iCls) && gpsi->atomSysClass[iCls] == 0)
1113 {
1114 gpsi->atomSysClass[iCls] = Class->atomClassName;
1115 }
1116
1117 _SEH2_TRY
1118 {
1119 PWSTR pszMenuNameBuffer = pszMenuName;
1120
1121 /* Need to protect with SEH since accessing the WNDCLASSEX structure
1122 and string buffers might raise an exception! We don't want to
1123 leak memory... */
1124 // What?! If the user interface was written correctly this would not be an issue!
1125 Class->lpfnWndProc = lpwcx->lpfnWndProc;
1126 Class->style = lpwcx->style;
1127 Class->cbclsExtra = lpwcx->cbClsExtra;
1128 Class->cbwndExtra = lpwcx->cbWndExtra;
1129 Class->hModule = lpwcx->hInstance;
1130 Class->spicn = lpwcx->hIcon ? UserGetCurIconObject(lpwcx->hIcon) : NULL;
1131 Class->spcur = lpwcx->hCursor ? UserGetCurIconObject(lpwcx->hCursor) : NULL;
1132 Class->spicnSm = lpwcx->hIconSm ? UserGetCurIconObject(lpwcx->hIconSm) : NULL;
1134 Class->hbrBackground = lpwcx->hbrBackground;
1135
1136 /* Make a copy of the string */
1137 if (pszMenuNameBuffer != NULL)
1138 {
1139 Class->MenuNameIsString = TRUE;
1140
1141 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
1142 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
1143 MenuName->Buffer,
1144 MenuName->Length);
1145 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1146
1147 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
1148 }
1149 else
1150 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1151
1152 /* Save an ANSI copy of the string */
1153 if (pszMenuNameBuffer != NULL)
1154 {
1156
1157 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
1158 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName);
1159 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
1161 MenuName,
1162 FALSE);
1163 if (!NT_SUCCESS(Status))
1164 {
1165 ERR("Failed to convert unicode menu name to ansi!\n");
1166
1167 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1169 }
1170 }
1171 else
1172 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1173
1174 /* Save kernel use menu name and ansi class name */
1175 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // FIXME!
1176 //Class->lpszAnsiClassName = FIXME
1177
1178 /* Server Side overrides class calling type (A/W)!
1179 User32 whine test_builtinproc: "deftest"
1180 built-in winproc - window A/W type automatically detected */
1181 if (!(Class->CSF_flags & CSF_SERVERSIDEPROC))
1182 {
1183 int i;
1184 WndProc = NULL;
1185 /* Due to the wine class "deftest" and most likely no FNID to reference
1186 from, sort through the Server Side list and compare proc addresses
1187 for match. This method will be used in related code.
1188 */
1189 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
1190 { // Open ANSI or Unicode, just match, set and break.
1191 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
1192 {
1194 break;
1195 }
1196 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
1197 {
1199 break;
1200 }
1201 }
1202 if (WndProc)
1203 { // If a hit, we are Server Side so set the right flags and proc.
1204 Class->CSF_flags |= CSF_SERVERSIDEPROC;
1205 Class->CSF_flags &= ~CSF_ANSIPROC;
1206 Class->lpfnWndProc = WndProc;
1207 }
1208 }
1209
1210 if (!(Class->CSF_flags & CSF_ANSIPROC))
1211 Class->Unicode = TRUE;
1212
1213 if (Class->style & CS_GLOBALCLASS)
1214 Class->Global = TRUE;
1215 }
1217 {
1219 }
1220 _SEH2_END;
1221
1222 if (!NT_SUCCESS(Status))
1223 {
1224 ERR("Failed creating the class: 0x%x\n", Status);
1225
1227
1228 if (pszMenuName != NULL)
1229 UserHeapFree(pszMenuName);
1230
1232 Class);
1233 Class = NULL;
1234
1235 IntDeregisterClassAtom(verAtom);
1237 }
1238 }
1239 else
1240 {
1241NoMem:
1242 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop);
1243
1244 if (pszMenuName != NULL)
1245 UserHeapFree(pszMenuName);
1246
1248 IntDeregisterClassAtom(verAtom);
1249
1251 }
1252
1253 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and version atom 0x%x and hInstance 0x%p, global %u\n",
1254 Class, ClassName, Class ? Class->lpfnWndProc : NULL, Atom, verAtom,
1255 Class ? Class->hModule : NULL , Class ? Class->Global : 0);
1256
1257 return Class;
1258}
1259
1260static PCLS
1263 IN PCLS *ClassList,
1265{
1266 PCLS Class, *PrevLink = ClassList;
1267
1268 Class = *PrevLink;
1269 while (Class != NULL)
1270 {
1271 if (Class->atomClassName == Atom &&
1272 (hInstance == NULL || Class->hModule == hInstance) &&
1273 !(Class->CSF_flags & CSF_WOWDEFERDESTROY))
1274 {
1275 ASSERT(Class->pclsBase == Class);
1276
1277 if (Link != NULL)
1278 *Link = PrevLink;
1279 break;
1280 }
1281
1282 PrevLink = &Class->pclsNext;
1283 Class = Class->pclsNext;
1284 }
1285
1286 return Class;
1287}
1288
1290BOOL
1291NTAPI
1292IntGetAtomFromStringOrAtom(
1293 _In_ PUNICODE_STRING ClassName,
1295{
1296 BOOL Ret = FALSE;
1297
1298 if (ClassName->Length != 0)
1299 {
1300 WCHAR szBuf[65];
1301 PWSTR AtomName = szBuf;
1303
1304 *Atom = 0;
1305
1306 /* NOTE: Caller has to protect the call with SEH! */
1307 if (ClassName->Length + sizeof(UNICODE_NULL) > sizeof(szBuf))
1308 {
1310 ClassName->Length + sizeof(UNICODE_NULL),
1311 TAG_USTR);
1312 if (AtomName == NULL)
1313 {
1315 return FALSE;
1316 }
1317 }
1318
1319 _SEH2_TRY
1320 {
1321 RtlCopyMemory(AtomName,
1322 ClassName->Buffer,
1323 ClassName->Length);
1324 }
1326 {
1327 if (AtomName != szBuf)
1328 ExFreePoolWithTag(AtomName, TAG_USTR);
1330 _SEH2_YIELD(return FALSE);
1331 }
1332 _SEH2_END;
1333 AtomName[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1334
1335 /* Lookup the atom */
1337
1338 if (AtomName != szBuf)
1339 ExFreePoolWithTag(AtomName, TAG_USTR);
1340
1341 if (NT_SUCCESS(Status))
1342 {
1343 Ret = TRUE;
1344 }
1345 else
1346 {
1348 {
1350 }
1351 }
1352 }
1353 else
1354 {
1355 ASSERT(IS_ATOM(ClassName->Buffer));
1356 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1357 Ret = TRUE;
1358 }
1359
1360 return Ret;
1361}
1362
1365 _In_ PUNICODE_STRING ClassName,
1368 OUT PCLS *BaseClass OPTIONAL,
1370{
1371 RTL_ATOM Atom = (RTL_ATOM)0;
1372
1373 ASSERT(BaseClass != NULL);
1374
1375 if (IntGetAtomFromStringOrAtom(ClassName, &Atom) &&
1376 Atom != (RTL_ATOM)0)
1377 {
1378 PCLS Class;
1379
1380 /* Attempt to locate the class object */
1381
1382 ASSERT(pi != NULL);
1383
1384 /* Step 1: Try to find an exact match of locally registered classes */
1386 hInstance,
1387 &pi->pclsPrivateList,
1388 Link);
1389 if (Class != NULL)
1390 { TRACE("Step 1: 0x%p\n",Class );
1391 goto FoundClass;
1392 }
1393
1394 /* Step 2: Try to find any globally registered class. The hInstance
1395 is not relevant for global classes */
1397 NULL,
1398 &pi->pclsPublicList,
1399 Link);
1400 if (Class != NULL)
1401 { TRACE("Step 2: 0x%p 0x%p\n",Class, Class->hModule);
1402 goto FoundClass;
1403 }
1404
1405 /* Step 3: Try to find any local class registered by user32 */
1407 hModClient,
1408 &pi->pclsPrivateList,
1409 Link);
1410 if (Class != NULL)
1411 { TRACE("Step 3: 0x%p\n",Class );
1412 goto FoundClass;
1413 }
1414
1415 /* Step 4: Try to find any global class registered by user32 */
1417 hModClient,
1418 &pi->pclsPublicList,
1419 Link);
1420 if (Class == NULL)
1421 {
1422 return (RTL_ATOM)0;
1423 }else{TRACE("Step 4: 0x%p\n",Class );}
1424
1425FoundClass:
1426 *BaseClass = Class;
1427 }
1428 else
1429 {
1430 Atom = 0;
1431 }
1432
1433 return Atom;
1434}
1435
1436PCLS
1438{
1439 PCLS *ClassLink, Class = NULL;
1440 RTL_ATOM ClassAtom;
1441 PTHREADINFO pti;
1442
1443 if (bDesktopThread)
1444 pti = gptiDesktopThread;
1445 else
1447
1448 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1449 {
1451 }
1452
1453 /* Check the class. */
1454
1455 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName, hInstance);
1456
1457 ClassAtom = IntGetClassAtom(ClassName,
1458 hInstance,
1459 pti->ppi,
1460 &Class,
1461 &ClassLink);
1462
1463 if (ClassAtom == (RTL_ATOM)0)
1464 {
1465 if (IS_ATOM(ClassName->Buffer))
1466 {
1467 ERR("Class 0x%p not found\n", ClassName->Buffer);
1468 }
1469 else
1470 {
1471 ERR("Class \"%wZ\" not found\n", ClassName);
1472 }
1473
1474 return NULL;
1475 }
1476
1477 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class, ClassAtom);
1479 ClassLink,
1480 pti->rpdesk);
1481 if (Class == NULL)
1482 {
1483 ERR("Failed to reference window class!\n");
1484 return NULL;
1485 }
1486
1487 return Class;
1488}
1489
1492 IN PUNICODE_STRING ClassName,
1493 IN PUNICODE_STRING ClassVersion,
1494 IN PUNICODE_STRING MenuName,
1495 IN DWORD fnID,
1497{
1498 PTHREADINFO pti;
1500 PCLS Class;
1501 RTL_ATOM ClassAtom;
1502 RTL_ATOM Ret = (RTL_ATOM)0;
1503
1504 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1505
1506 pti = GetW32ThreadInfo();
1507
1508 pi = pti->ppi;
1509
1510 // Need only to test for two conditions not four....... Fix more whine tests....
1511 if ( IntGetAtomFromStringOrAtom( ClassVersion, &ClassAtom) &&
1512 ClassAtom != (RTL_ATOM)0 &&
1513 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
1514 {
1515 Class = IntFindClass( ClassAtom,
1516 lpwcx->hInstance,
1517 &pi->pclsPrivateList,
1518 NULL);
1519
1520 if (Class != NULL && !Class->Global)
1521 {
1522 // Local class already exists
1523 TRACE("Local Class 0x%x does already exist!\n", ClassAtom);
1525 return (RTL_ATOM)0;
1526 }
1527
1528 if (lpwcx->style & CS_GLOBALCLASS)
1529 {
1530 Class = IntFindClass( ClassAtom,
1531 NULL,
1532 &pi->pclsPublicList,
1533 NULL);
1534
1535 if (Class != NULL && Class->Global)
1536 {
1537 TRACE("Global Class 0x%x does already exist!\n", ClassAtom);
1539 return (RTL_ATOM)0;
1540 }
1541 }
1542 }
1543
1544 Class = IntCreateClass(lpwcx,
1545 ClassName,
1546 ClassVersion,
1547 MenuName,
1548 fnID,
1549 dwFlags,
1550 pti->rpdesk,
1551 pi);
1552
1553 if (Class != NULL)
1554 {
1555 PCLS *List;
1556
1557 /* Register the class */
1558 if (Class->Global)
1559 List = &pi->pclsPublicList;
1560 else
1561 List = &pi->pclsPrivateList;
1562
1563 Class->pclsNext = *List;
1565 Class);
1566
1567 Ret = Class->atomNVClassName;
1568 }
1569 else
1570 {
1571 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1572 }
1573
1574 return Ret;
1575}
1576
1577BOOL
1580 OUT PCLSMENUNAME pClassMenuName)
1581{
1582 PCLS *Link;
1584 RTL_ATOM ClassAtom;
1585 PCLS Class;
1586
1588
1589 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName, hInstance);
1590
1591 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1592 ClassAtom = IntGetClassAtom(ClassName,
1593 hInstance,
1594 pi,
1595 &Class,
1596 &Link);
1597 if (ClassAtom == (RTL_ATOM)0)
1598 {
1600 TRACE("UserUnregisterClass: No Class found.\n");
1601 return FALSE;
1602 }
1603
1604 ASSERT(Class != NULL);
1605
1606 if (Class->cWndReferenceCount != 0 ||
1607 Class->pclsClone != NULL)
1608 {
1609 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class->cWndReferenceCount, Class->pclsClone);
1611 return FALSE;
1612 }
1613
1614 /* Must be a base class! */
1615 ASSERT(Class->pclsBase == Class);
1616
1617 /* Unlink the class */
1618 *Link = Class->pclsNext;
1619
1620 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1621 {
1622 TRACE("Class 0x%p\n", Class);
1623 TRACE("UserUnregisterClass: Good Exit!\n");
1624 Class->atomClassName = 0; // Don't let it linger...
1625 /* Finally free the resources */
1627 return TRUE;
1628 }
1629 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1630 return FALSE;
1631}
1632
1633INT
1635 IN OUT PUNICODE_STRING ClassName,
1637 IN BOOL Ansi)
1638{
1640 WCHAR szStaticTemp[32];
1641 PWSTR szTemp = NULL;
1642 ULONG BufLen = sizeof(szStaticTemp);
1643 INT Ret = 0;
1644
1645 /* Note: Accessing the buffer in ClassName may raise an exception! */
1646
1647 _SEH2_TRY
1648 {
1649 if (Ansi)
1650 {
1651 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1652 UNICODE_STRING UnicodeClassName;
1653
1654 /* Limit the size of the static buffer on the stack to the
1655 size of the buffer provided by the caller */
1656 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1657 {
1658 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1659 }
1660
1661 /* Find out how big the buffer needs to be */
1663 Class->atomClassName,
1664 NULL,
1665 NULL,
1666 szStaticTemp,
1667 &BufLen);
1669 {
1670 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1671 {
1672 /* The buffer required exceeds the ansi buffer provided,
1673 pretend like we're using the ansi buffer and limit the
1674 size to the buffer size provided */
1675 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1676 }
1677
1678 /* Allocate a temporary buffer that can hold the unicode class name */
1680 BufLen,
1682 if (szTemp == NULL)
1683 {
1686 }
1687
1688 /* Query the class name */
1690 Atom ? Atom : Class->atomNVClassName,
1691 NULL,
1692 NULL,
1693 szTemp,
1694 &BufLen);
1695 }
1696 else
1697 szTemp = szStaticTemp;
1698
1699 if (NT_SUCCESS(Status))
1700 {
1701 /* Convert the atom name to ansi */
1702
1703 RtlInitUnicodeString(&UnicodeClassName,
1704 szTemp);
1705
1706 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1707 &UnicodeClassName,
1708 FALSE);
1709 if (!NT_SUCCESS(Status))
1710 {
1713 }
1714 }
1715
1716 Ret = BufLen / sizeof(WCHAR);
1717 }
1718 else /* !ANSI */
1719 {
1720 BufLen = ClassName->MaximumLength;
1721
1722 /* Query the atom name */
1724 Atom ? Atom : Class->atomNVClassName,
1725 NULL,
1726 NULL,
1727 ClassName->Buffer,
1728 &BufLen);
1729
1730 if (!NT_SUCCESS(Status))
1731 {
1734 }
1735
1736 Ret = BufLen / sizeof(WCHAR);
1737 }
1738 }
1740 {
1742 }
1743 _SEH2_END;
1744
1745 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1746 {
1748 }
1749
1750 return Ret;
1751}
1752
1753static BOOL
1755 IN PUNICODE_STRING MenuName)
1756{
1757 BOOL Ret = FALSE;
1758
1759 /* Change the base class first */
1760 Class = Class->pclsBase;
1761
1762 if (MenuName->Length != 0)
1763 {
1765 PWSTR strBufW;
1766
1767 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName);
1768
1769 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1770 AnsiString.MaximumLength);
1771 if (strBufW != NULL)
1772 {
1773 _SEH2_TRY
1774 {
1776
1777 /* Copy the unicode string */
1778 RtlCopyMemory(strBufW,
1779 MenuName->Buffer,
1780 MenuName->Length);
1781 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1782
1783 /* Create an ANSI copy of the string */
1784 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1786 MenuName,
1787 FALSE);
1788 if (!NT_SUCCESS(Status))
1789 {
1792 }
1793
1794 Ret = TRUE;
1795 }
1797 {
1799 }
1800 _SEH2_END;
1801
1802 if (Ret)
1803 {
1804 /* Update the base class */
1806 Class->lpszClientUnicodeMenuName = strBufW;
1807 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1808 Class->MenuNameIsString = TRUE;
1809
1810 /* Update the clones */
1811 Class = Class->pclsClone;
1812 while (Class != NULL)
1813 {
1814 Class->lpszClientUnicodeMenuName = strBufW;
1815 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1816 Class->MenuNameIsString = TRUE;
1817
1818 Class = Class->pclsNext;
1819 }
1820 }
1821 else
1822 {
1823 ERR("Failed to copy class menu name!\n");
1824 UserHeapFree(strBufW);
1825 }
1826 }
1827 else
1829 }
1830 else
1831 {
1832 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1833
1834 /* Update the base class */
1836 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1837 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1838 Class->MenuNameIsString = FALSE;
1839
1840 /* Update the clones */
1841 Class = Class->pclsClone;
1842 while (Class != NULL)
1843 {
1844 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1845 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1846 Class->MenuNameIsString = FALSE;
1847
1848 Class = Class->pclsNext;
1849 }
1850
1851 Ret = TRUE;
1852 }
1853
1854 return Ret;
1855}
1856
1859 IN INT Index,
1860 IN ULONG_PTR NewLong,
1861 IN BOOL Ansi)
1862{
1863 ULONG_PTR Ret = 0;
1864
1865 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1866
1867 /* Change the information in the base class first, then update the clones */
1868 Class = Class->pclsBase;
1869
1870 if (Index >= 0)
1871 {
1873
1874 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1875
1876 if (((ULONG)Index + sizeof(ULONG_PTR)) < (ULONG)Index ||
1877 ((ULONG)Index + sizeof(ULONG_PTR)) > (ULONG)Class->cbclsExtra)
1878 {
1880 return 0;
1881 }
1882
1883 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1884
1885 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1886 certain architectures, maybe using RtlCopyMemory is a
1887 better choice for those architectures! */
1888 Ret = *Data;
1889 *Data = NewLong;
1890
1891 /* Update the clones */
1892 Class = Class->pclsClone;
1893 while (Class != NULL)
1894 {
1895 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1896 Class = Class->pclsNext;
1897 }
1898
1899 return Ret;
1900 }
1901
1902 switch (Index)
1903 {
1904 case GCL_CBWNDEXTRA:
1905 Ret = (ULONG_PTR)Class->cbwndExtra;
1906 Class->cbwndExtra = (INT)NewLong;
1907
1908 /* Update the clones */
1909 Class = Class->pclsClone;
1910 while (Class != NULL)
1911 {
1912 Class->cbwndExtra = (INT)NewLong;
1913 Class = Class->pclsNext;
1914 }
1915
1916 break;
1917
1918 case GCL_CBCLSEXTRA:
1920 break;
1921
1922 case GCLP_HBRBACKGROUND:
1923 Ret = (ULONG_PTR)Class->hbrBackground;
1924 Class->hbrBackground = (HBRUSH)NewLong;
1925
1926 /* Update the clones */
1927 Class = Class->pclsClone;
1928 while (Class != NULL)
1929 {
1930 Class->hbrBackground = (HBRUSH)NewLong;
1931 Class = Class->pclsNext;
1932 }
1933 break;
1934
1935 case GCLP_HCURSOR:
1936 {
1937 PCURICON_OBJECT NewCursor = NULL;
1938
1939 if (NewLong)
1940 {
1941 NewCursor = UserGetCurIconObject((HCURSOR)NewLong);
1942 if (!NewCursor)
1943 {
1945 return 0;
1946 }
1947 }
1948
1949 if (Class->spcur)
1950 {
1951 Ret = (ULONG_PTR)UserHMGetHandle(Class->spcur);
1953 }
1954 else
1955 {
1956 Ret = 0;
1957 }
1958
1959 if (Ret == NewLong)
1960 {
1961 /* It's a nop */
1962 return Ret;
1963 }
1964
1965 Class->spcur = NewCursor;
1966
1967 /* Update the clones */
1968 Class = Class->pclsClone;
1969 while (Class != NULL)
1970 {
1971 if (Class->spcur)
1973 if (NewCursor)
1974 UserReferenceObject(NewCursor);
1975 Class->spcur = NewCursor;
1976 Class = Class->pclsNext;
1977 }
1978
1979 break;
1980 }
1981
1982 // MSDN:
1983 // hIconSm, A handle to a small icon that is associated with the window class.
1984 // If this member is NULL, the system searches the icon resource specified by
1985 // the hIcon member for an icon of the appropriate size to use as the small icon.
1986 //
1987 case GCLP_HICON:
1988 {
1989 PCURICON_OBJECT NewIcon = NULL;
1990 PCURICON_OBJECT NewSmallIcon = NULL;
1991
1992 if (NewLong)
1993 {
1994 NewIcon = UserGetCurIconObject((HCURSOR)NewLong);
1995 if (!NewIcon)
1996 {
1998 return 0;
1999 }
2000 }
2001
2002 if (Class->spicn)
2003 {
2004 Ret = (ULONG_PTR)UserHMGetHandle(Class->spicn);
2006 }
2007 else
2008 {
2009 Ret = 0;
2010 }
2011
2012 if (Ret == NewLong)
2013 {
2014 /* It's a nop */
2015 return Ret;
2016 }
2017
2018 if (Ret && (Class->CSF_flags & CSF_CACHEDSMICON))
2019 {
2020 /* We will change the small icon */
2021 UserDereferenceObject(Class->spicnSm);
2023 Class->spicnSm = NULL;
2024 Class->CSF_flags &= ~CSF_CACHEDSMICON;
2025 }
2026
2027 if (NewLong && !Class->spicnSm)
2028 {
2029 /* Create the new small icon from the new large(?) one */
2030 HICON SmallIconHandle = NULL;
2033 {
2034 SmallIconHandle = co_IntCopyImage(
2035 (HICON)NewLong,
2036 IMAGE_ICON,
2040 }
2041 if (!SmallIconHandle)
2042 {
2043 /* Retry without copying from resource */
2044 SmallIconHandle = co_IntCopyImage(
2045 (HICON)NewLong,
2046 IMAGE_ICON,
2049 0);
2050 }
2051 if (SmallIconHandle)
2052 {
2053 /* So use it */
2054 NewSmallIcon = Class->spicnSm = UserGetCurIconObject(SmallIconHandle);
2055 Class->CSF_flags |= CSF_CACHEDSMICON;
2056 }
2057 }
2058
2059 Class->spicn = NewIcon;
2060
2061 /* Update the clones */
2062 Class = Class->pclsClone;
2063 while (Class != NULL)
2064 {
2065 if (Class->spicn)
2067 if (NewIcon)
2068 UserReferenceObject(NewIcon);
2069 Class->spicn = NewIcon;
2070 if (NewSmallIcon)
2071 {
2072 if (Class->spicnSm)
2073 UserDereferenceObject(Class->spicnSm);
2074 UserReferenceObject(NewSmallIcon);
2075 Class->spicnSm = NewSmallIcon;
2076 Class->CSF_flags |= CSF_CACHEDSMICON;
2077 }
2078 Class = Class->pclsNext;
2079 }
2080 break;
2081 }
2082
2083 case GCLP_HICONSM:
2084 {
2085 PCURICON_OBJECT NewSmallIcon = NULL;
2086 BOOLEAN NewIconFromCache = FALSE;
2087
2088 if (NewLong)
2089 {
2090 NewSmallIcon = UserGetCurIconObject((HCURSOR)NewLong);
2091 if (!NewSmallIcon)
2092 {
2094 return 0;
2095 }
2096 }
2097 else
2098 {
2099 /* Create the new small icon from the large one */
2100 HICON SmallIconHandle = NULL;
2101 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
2103 {
2104 SmallIconHandle = co_IntCopyImage(
2105 UserHMGetHandle(Class->spicn),
2106 IMAGE_ICON,
2110 }
2111 if (!SmallIconHandle)
2112 {
2113 /* Retry without copying from resource */
2114 SmallIconHandle = co_IntCopyImage(
2115 UserHMGetHandle(Class->spicn),
2116 IMAGE_ICON,
2119 0);
2120 }
2121 if (SmallIconHandle)
2122 {
2123 /* So use it */
2124 NewSmallIcon = UserGetCurIconObject(SmallIconHandle);
2125 NewIconFromCache = TRUE;
2126 }
2127 else
2128 {
2129 ERR("Failed getting a small icon for the class.\n");
2130 }
2131 }
2132
2133 if (Class->spicnSm)
2134 {
2135 if (Class->CSF_flags & CSF_CACHEDSMICON)
2136 {
2137 /* We must destroy the icon if we own it */
2139 Ret = 0;
2140 }
2141 else
2142 {
2143 Ret = (ULONG_PTR)UserHMGetHandle(Class->spicnSm);
2144 }
2145 UserDereferenceObject(Class->spicnSm);
2146 }
2147 else
2148 {
2149 Ret = 0;
2150 }
2151
2152 if (NewIconFromCache)
2153 Class->CSF_flags |= CSF_CACHEDSMICON;
2154 else
2155 Class->CSF_flags &= ~CSF_CACHEDSMICON;
2156 Class->spicnSm = NewSmallIcon;
2157
2158 /* Update the clones */
2159 Class = Class->pclsClone;
2160 while (Class != NULL)
2161 {
2162 if (Class->spicnSm)
2163 UserDereferenceObject(Class->spicnSm);
2164 if (NewSmallIcon)
2165 UserReferenceObject(NewSmallIcon);
2166 if (NewIconFromCache)
2167 Class->CSF_flags |= CSF_CACHEDSMICON;
2168 else
2169 Class->CSF_flags &= ~CSF_CACHEDSMICON;
2170 Class->spicnSm = NewSmallIcon;
2171 Class = Class->pclsNext;
2172 }
2173 }
2174 break;
2175
2176 case GCLP_HMODULE:
2177 Ret = (ULONG_PTR)Class->hModule;
2178 Class->hModule = (HINSTANCE)NewLong;
2179
2180 /* Update the clones */
2181 Class = Class->pclsClone;
2182 while (Class != NULL)
2183 {
2184 Class->hModule = (HINSTANCE)NewLong;
2185 Class = Class->pclsNext;
2186 }
2187 break;
2188
2189 case GCLP_MENUNAME:
2190 {
2192
2194 Value))
2195 {
2196 ERR("Setting the class menu name failed!\n");
2197 }
2198
2199 /* FIXME: Really return NULL? Wine does so... */
2200 break;
2201 }
2202
2203 case GCL_STYLE:
2204 Ret = (ULONG_PTR)Class->style;
2205 Class->style = (UINT)NewLong;
2206
2207 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
2208 move the class to the appropriate list? For now, we save
2209 the original value in Class->Global, so we can always
2210 locate the appropriate list */
2211
2212 /* Update the clones */
2213 Class = Class->pclsClone;
2214 while (Class != NULL)
2215 {
2216 Class->style = (UINT)NewLong;
2217 Class = Class->pclsNext;
2218 }
2219 break;
2220
2221 case GCLP_WNDPROC:
2223 (WNDPROC)NewLong,
2224 Ansi);
2225 break;
2226
2227 case GCW_ATOM:
2228 {
2230
2231 Ret = (ULONG_PTR)Class->atomNVClassName;
2233 Value))
2234 {
2235 Ret = 0;
2236 }
2237 break;
2238 }
2239
2240 default:
2242 break;
2243 }
2244
2245 return Ret;
2246}
2247
2248static BOOL
2250 OUT PWNDCLASSEXW lpwcx,
2251 IN BOOL Ansi,
2253{
2254 if (!Class) return FALSE;
2255
2256 lpwcx->style = Class->style;
2257
2258 // If fnId is set, clear the global bit. See wine class test check_style.
2259 if (Class->fnid)
2260 lpwcx->style &= ~CS_GLOBALCLASS;
2261
2262 lpwcx->lpfnWndProc = IntGetClassWndProc(Class, Ansi);
2263
2264 lpwcx->cbClsExtra = Class->cbclsExtra;
2265 lpwcx->cbWndExtra = Class->cbwndExtra;
2266 lpwcx->hIcon = Class->spicn ? UserHMGetHandle(Class->spicn) : NULL;
2267 lpwcx->hCursor = Class->spcur ? UserHMGetHandle(Class->spcur) : NULL;
2268 lpwcx->hIconSm = Class->spicnSm ? UserHMGetHandle(Class->spicnSm) : NULL;
2269 lpwcx->hbrBackground = Class->hbrBackground;
2270
2271 /* Copy non-string to user first. */
2272 if (Ansi)
2273 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName;
2274 else
2275 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName;
2276/*
2277 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2278 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2279 * lpszClientXxxMenuName should already be mapped to user space.
2280 */
2281 /* Copy string ptr to user. */
2282 if ( Class->lpszClientUnicodeMenuName != NULL &&
2283 Class->MenuNameIsString)
2284 {
2285 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ?
2286 (PVOID)Class->lpszClientAnsiMenuName :
2287 (PVOID)Class->lpszClientUnicodeMenuName);
2288 }
2289
2290 if (hInstance == hModClient)
2291 lpwcx->hInstance = NULL;
2292 else
2293 lpwcx->hInstance = hInstance;
2294
2295 /* FIXME: Return the string? Okay! This is performed in User32! */
2296 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2297
2298 return TRUE;
2299}
2300
2301//
2302// Register System Classes....
2303//
2304BOOL
2307{
2308 UINT i;
2309 UNICODE_STRING ClassName, MenuName;
2311 WNDCLASSEXW wc;
2312 PCLS Class;
2313 BOOL Ret = TRUE;
2314 HBRUSH hBrush;
2315 DWORD Flags = 0;
2316
2317 if (ppi->W32PF_flags & W32PF_CLASSESREGISTERED)
2318 return TRUE;
2319
2320 if ( hModClient == NULL)
2321 return FALSE;
2322
2323 RtlZeroMemory(&ClassName, sizeof(ClassName));
2324 RtlZeroMemory(&MenuName, sizeof(MenuName));
2325
2326 for (i = 0; i != ARRAYSIZE(DefaultServerClasses); i++)
2327 {
2328 if (!IS_ATOM(DefaultServerClasses[i].ClassName))
2329 {
2330 RtlInitUnicodeString(&ClassName, DefaultServerClasses[i].ClassName);
2331 }
2332 else
2333 {
2334 ClassName.Buffer = DefaultServerClasses[i].ClassName;
2335 ClassName.Length = 0;
2336 ClassName.MaximumLength = 0;
2337 }
2338
2339 wc.cbSize = sizeof(wc);
2341
2343
2344 if (DefaultServerClasses[i].ProcW)
2345 {
2347 wc.hInstance = hModuleWin;
2348 }
2349 else
2350 {
2352 wc.hInstance = hModClient;
2353 }
2354
2355 wc.cbClsExtra = 0;
2357 wc.hIcon = NULL;
2358
2360 wc.hCursor = NULL;
2361 if (DefaultServerClasses[i].hCursor == (HICON)OCR_NORMAL)
2362 {
2363 if (SYSTEMCUR(ARROW) == NULL)
2364 {
2365 ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n");
2366 }
2367 else
2368 {
2369 wc.hCursor = UserHMGetHandle(SYSTEMCUR(ARROW));
2370 }
2371 }
2372
2373 hBrush = DefaultServerClasses[i].hBrush;
2374 if (hBrush <= (HBRUSH)COLOR_MENUBAR)
2375 {
2376 hBrush = IntGetSysColorBrush(HandleToUlong(hBrush));
2377 }
2378 wc.hbrBackground = hBrush;
2379 wc.lpszMenuName = NULL;
2380 wc.lpszClassName = ClassName.Buffer;
2381 wc.hIconSm = NULL;
2382
2383 Class = IntCreateClass( &wc,
2384 &ClassName,
2385 &ClassName,
2386 &MenuName,
2387 DefaultServerClasses[i].fiId,
2388 Flags,
2389 NULL,
2390 ppi);
2391 if (Class != NULL)
2392 {
2393 Class->pclsNext = ppi->pclsPublicList;
2395 Class);
2396
2398 }
2399 else
2400 {
2401 ERR("!!! Registering system class failed!\n");
2402 Ret = FALSE;
2403 }
2404 }
2405 if (Ret) ppi->W32PF_flags |= W32PF_CLASSESREGISTERED;
2406 return Ret;
2407}
2408
2409/* SYSCALLS *****************************************************************/
2410
2414 WNDCLASSEXW* lpwcx,
2415 PUNICODE_STRING ClassName,
2416 PUNICODE_STRING ClsVersion,
2417 PCLSMENUNAME pClassMenuName,
2418 DWORD fnID,
2419 DWORD Flags,
2420 LPDWORD pWow)
2421/*
2422 * FUNCTION:
2423 * Registers a new class with the window manager
2424 * ARGUMENTS:
2425 * lpwcx = Win32 extended window class structure
2426 * bUnicodeClass = Whether to send ANSI or unicode strings
2427 * to window procedures
2428 * RETURNS:
2429 * Atom identifying the new class
2430 */
2431{
2432 WNDCLASSEXW CapturedClassInfo = {0};
2433 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0}, CapturedVersion = {0};
2434 RTL_ATOM Ret = (RTL_ATOM)0;
2436 BOOL Exception = FALSE;
2437
2438 if (Flags & ~(CSF_ANSIPROC))
2439 {
2440 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2442 return Ret;
2443 }
2444
2446
2447 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName);
2448
2449 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2450 {
2452 }
2453
2454 _SEH2_TRY
2455 {
2456 /* Probe the parameters and basic parameter checks */
2457 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2458 {
2459 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2460 goto InvalidParameter;
2461 }
2462
2463 ProbeForRead(lpwcx,
2464 sizeof(WNDCLASSEXW),
2465 sizeof(ULONG));
2466 RtlCopyMemory(&CapturedClassInfo,
2467 lpwcx,
2468 sizeof(WNDCLASSEXW));
2469
2470 CapturedName = ProbeForReadUnicodeString(ClassName);
2471 CapturedVersion = ProbeForReadUnicodeString(ClsVersion);
2472
2473 ProbeForRead(pClassMenuName,
2474 sizeof(CLSMENUNAME),
2475 1);
2476
2477 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName);
2478
2479 if ( (CapturedName.Length & 1) ||
2480 (CapturedMenuName.Length & 1) ||
2481 (CapturedClassInfo.cbClsExtra < 0) ||
2482 ((CapturedClassInfo.cbClsExtra + CapturedName.Length +
2483 CapturedMenuName.Length + sizeof(CLS))
2484 < (ULONG)CapturedClassInfo.cbClsExtra) ||
2485 (CapturedClassInfo.cbWndExtra < 0) ||
2486 (CapturedClassInfo.hInstance == NULL) )
2487 {
2488 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2489 goto InvalidParameter;
2490 }
2491
2492 if (CapturedName.Length != 0)
2493 {
2494 ProbeForRead(CapturedName.Buffer,
2495 CapturedName.Length,
2496 sizeof(WCHAR));
2497 }
2498 else
2499 {
2500 if (!IS_ATOM(CapturedName.Buffer))
2501 {
2502 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2503 goto InvalidParameter;
2504 }
2505 }
2506
2507 if (CapturedVersion.Length != 0)
2508 {
2509 ProbeForRead(CapturedVersion.Buffer,
2510 CapturedVersion.Length,
2511 sizeof(WCHAR));
2512 }
2513 else
2514 {
2515 if (!IS_ATOM(CapturedVersion.Buffer))
2516 {
2517 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2518 goto InvalidParameter;
2519 }
2520 }
2521
2522 if (CapturedMenuName.Length != 0)
2523 {
2524 ProbeForRead(CapturedMenuName.Buffer,
2525 CapturedMenuName.Length,
2526 sizeof(WCHAR));
2527 }
2528 else if (CapturedMenuName.Buffer != NULL &&
2529 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2530 {
2531 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2535 }
2536
2537 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2538 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2539 // If this pops up we know what todo!
2540 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2541 }
2542
2543 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2544 }
2546 {
2547 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2549 Exception = TRUE;
2550 }
2551 _SEH2_END;
2552
2553 if (!Exception)
2554 {
2555 /* Register the class */
2556 Ret = UserRegisterClass(&CapturedClassInfo,
2557 &CapturedName,
2558 &CapturedVersion,
2559 &CapturedMenuName,
2560 fnID,
2561 Flags);
2562 }
2563
2564 if (!Ret)
2565 {
2566 TRACE("NtUserRegisterClassExWOW Null Return!\n");
2567 }
2568
2569 UserLeave();
2570
2571 return Ret;
2572}
2573
2576 INT Offset,
2577 ULONG_PTR dwNewLong,
2578 BOOL Ansi)
2579{
2581 PWND Window;
2582 ULONG_PTR Ret = 0;
2583
2585
2587
2589 if (Window != NULL)
2590 {
2591 if (Window->head.pti->ppi != pi)
2592 {
2594 goto Cleanup;
2595 }
2596
2597 _SEH2_TRY
2598 {
2600
2601 /* Probe the parameters */
2602 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2603 {
2604 /* FIXME: Resource ID can be passed directly without UNICODE_STRING ? */
2605 if (IS_ATOM(dwNewLong))
2606 {
2607 Value.MaximumLength = 0;
2608 Value.Length = 0;
2609 Value.Buffer = (PWSTR)dwNewLong;
2610 }
2611 else
2612 {
2614 }
2615
2616 if (Value.Length & 1)
2617 {
2618 goto InvalidParameter;
2619 }
2620
2621 if (Value.Length != 0)
2622 {
2623 ProbeForRead(Value.Buffer,
2624 Value.Length,
2625 sizeof(WCHAR));
2626 }
2627 else
2628 {
2629 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2630 {
2631 goto InvalidParameter;
2632 }
2633 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2634 {
2638 }
2639 }
2640
2641 dwNewLong = (ULONG_PTR)&Value;
2642 }
2643
2644 Ret = UserSetClassLongPtr(Window->pcls,
2645 Offset,
2646 dwNewLong,
2647 Ansi);
2648 switch(Offset)
2649 {
2650 case GCLP_HICONSM:
2651 case GCLP_HICON:
2652 {
2653 if (Ret && Ret != dwNewLong)
2655 }
2656 }
2657 }
2659 {
2661 }
2662 _SEH2_END;
2663 }
2664
2665Cleanup:
2666 UserLeave();
2667
2668 return Ret;
2669}
2670
2671WORD
2674 HWND hWnd,
2675 INT nIndex,
2676 WORD wNewWord)
2677{
2678/*
2679 * NOTE: Obsoleted in 32-bit windows
2680 */
2681 return(0);
2682}
2683
2684BOOL
2687 IN PUNICODE_STRING ClassNameOrAtom,
2689 OUT PCLSMENUNAME pClassMenuName)
2690{
2691 UNICODE_STRING SafeClassName;
2693 BOOL Ret;
2694
2695 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom);
2696 if (!NT_SUCCESS(Status))
2697 {
2698 ERR("Error capturing the class name\n");
2700 return FALSE;
2701 }
2702
2704
2705 /* Unregister the class */
2706 Ret = UserUnregisterClass(&SafeClassName, hInstance, NULL); // Null for now~
2707
2708 UserLeave();
2709
2710 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
2711 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2712
2713 return Ret;
2714}
2715
2716
2717/* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2718BOOL
2722 PUNICODE_STRING ClassName,
2723 LPWNDCLASSEXW lpWndClassEx,
2724 LPWSTR *ppszMenuName,
2725 BOOL bAnsi)
2726{
2727 UNICODE_STRING SafeClassName;
2728 WNDCLASSEXW Safewcexw;
2729 PCLS Class;
2730 RTL_ATOM ClassAtom = 0;
2731 PPROCESSINFO ppi;
2732 BOOL Ret = TRUE;
2734
2735 _SEH2_TRY
2736 {
2737 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2738 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2739 if (ppszMenuName)
2740 {
2741 ProbeForWrite(ppszMenuName, sizeof(*ppszMenuName), sizeof(PVOID));
2742 }
2743 }
2745 {
2747 _SEH2_YIELD(return FALSE);
2748 }
2749 _SEH2_END;
2750
2751 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
2752 if (!NT_SUCCESS(Status))
2753 {
2754 ERR("Error capturing the class name\n");
2756 return FALSE;
2757 }
2758
2759 // If null instance use client.
2761
2762 TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName, hInstance);
2763
2764 /* NOTE: Need exclusive lock because getting the wndproc might require the
2765 creation of a call procedure handle */
2767
2768 ppi = GetW32ProcessInfo();
2769 if (!(ppi->W32PF_flags & W32PF_CLASSESREGISTERED))
2770 {
2772 }
2773
2774 ClassAtom = IntGetClassAtom(&SafeClassName,
2775 hInstance,
2776 ppi,
2777 &Class,
2778 NULL);
2779 if (ClassAtom != (RTL_ATOM)0)
2780 {
2781 ClassAtom = Class->atomNVClassName;
2782 Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance);
2783 }
2784 else
2785 {
2787 Ret = FALSE;
2788 }
2789
2790 UserLeave();
2791
2792 if (Ret)
2793 {
2794 _SEH2_TRY
2795 {
2796 /* Emulate Function. */
2797 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2798
2799 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2800
2801 // From Wine:
2802 /* We must return the atom of the class here instead of just TRUE. */
2803 /* Undocumented behavior! Return the class atom as a BOOL! */
2804 Ret = (BOOL)ClassAtom;
2805 }
2807 {
2809 Ret = FALSE;
2810 }
2811 _SEH2_END;
2812 }
2813
2814 if (!IS_ATOM(SafeClassName.Buffer))
2815 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2816
2817 return Ret;
2818}
2819
2820
2823 IN BOOL Real,
2824 OUT PUNICODE_STRING ClassName)
2825{
2826 PWND Window;
2827 UNICODE_STRING CapturedClassName;
2828 INT iCls, Ret = 0;
2829 RTL_ATOM Atom = 0;
2830
2832
2834 if (Window != NULL)
2835 {
2836 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY))
2837 {
2838 if (LookupFnIdToiCls(Window->fnid, &iCls))
2839 {
2840 Atom = gpsi->atomSysClass[iCls];
2841 }
2842 }
2843
2844 _SEH2_TRY
2845 {
2846 ProbeForWriteUnicodeString(ClassName);
2847 CapturedClassName = *ClassName;
2848 if (CapturedClassName.Length != 0)
2849 {
2850 ProbeForRead(CapturedClassName.Buffer,
2851 CapturedClassName.Length,
2852 sizeof(WCHAR));
2853 }
2854
2855 /* Get the class name */
2856 Ret = UserGetClassName(Window->pcls,
2857 &CapturedClassName,
2858 Atom,
2859 FALSE);
2860
2861 if (Ret != 0)
2862 {
2863 /* Update the Length field */
2864 ClassName->Length = CapturedClassName.Length;
2865 }
2866 }
2868 {
2870 }
2871 _SEH2_END;
2872 }
2873
2874 UserLeave();
2875
2876 return Ret;
2877}
2878
2879/* Return Pointer to Class structure. */
2880PCLS
2884 PUNICODE_STRING ClassName)
2885{
2886 UNICODE_STRING SafeClassName;
2888 PCLS Class = NULL;
2889 RTL_ATOM ClassAtom = 0;
2891
2892 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
2893 if (!NT_SUCCESS(Status))
2894 {
2895 ERR("Error capturing the class name\n");
2897 return FALSE;
2898 }
2899
2901
2903
2904 ClassAtom = IntGetClassAtom(&SafeClassName,
2905 hInstance,
2906 pi,
2907 &Class,
2908 NULL);
2909 if (!ClassAtom)
2910 {
2912 }
2913
2914
2915 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
2916 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2917
2918 UserLeave();
2919//
2920// Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2921//
2922 return Class;
2923}
2924
2925/* EOF */
unsigned char BOOLEAN
HWND hWnd
Definition: settings.c:17
LONG NTSTATUS
Definition: precomp.h:26
#define HandleToUlong(h)
Definition: basetsd.h:79
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
ULONG_PTR FASTCALL UserGetCPD(PVOID pvClsWnd, GETCPD Flags, ULONG_PTR ProcIn)
Definition: callproc.c:107
BOOLEAN DestroyCallProc(_Inout_ PVOID Object)
Definition: callproc.c:22
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
HINSTANCE hInstance
Definition: charmap.c:19
static __inline BOOL IsCallProcHandle(IN WNDPROC lpWndProc)
Definition: class.h:13
_Out_ RTL_ATOM * Atom
Definition: class.h:54
#define IS_ATOM(x)
Definition: class.h:3
#define SYSTEMCUR(func)
Definition: cursoricon.h:129
void FASTCALL DceFreeClassDCE(PDCE)
Definition: windc.c:762
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
float Real
Definition: definitions.h:36
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
WORD ATOM
Definition: dimm.idl:113
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define APIENTRY
Definition: api.h:79
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
PSERVERINFO gpsi
Definition: imm.c:18
static const WCHAR Cleanup[]
Definition: register.c:80
@ AnsiString
Definition: dnslib.h:19
#define ULONG_PTR
Definition: config.h:101
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
ANSI_STRING * PANSI_STRING
Definition: env_spec_w32.h:380
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define BufLen
Definition: fatfs.h:167
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define _SEH2_LEAVE
Definition: filesup.c:20
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
@ InvalidParameter
Definition: gdiplustypes.h:28
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define ICLS_IME
Definition: ntuser.h:922
#define ICLS_DIALOG
Definition: ntuser.h:925
#define ICLS_LISTBOX
Definition: ntuser.h:910
#define ICLASS_TO_MASK(iCls)
Definition: ntuser.h:897
#define ICLS_EDIT
Definition: ntuser.h:908
#define ICLS_GHOST
Definition: ntuser.h:923
struct _PROCESSINFO * GetW32ProcessInfo(VOID)
Definition: misc.c:795
#define CURSORF_LRSHARED
Definition: ntuser.h:1196
#define FNID_SWITCH
Definition: ntuser.h:860
#define ICLS_COMBOBOX
Definition: ntuser.h:912
#define ICLS_STATIC
Definition: ntuser.h:909
#define FNID_SCROLLBAR
Definition: ntuser.h:854
#define GETPFNCLIENTW(fnid)
Definition: ntuser.h:901
#define FNID_ICONTITLE
Definition: ntuser.h:855
#define GETPFNCLIENTA(fnid)
Definition: ntuser.h:899
#define FNID_DESTROY
Definition: ntuser.h:893
#define CSF_ANSIPROC
Definition: ntuser.h:552
#define FNID_DESKTOP
Definition: ntuser.h:857
#define FNID_LISTBOX
Definition: ntuser.h:866
#define FNID_FIRST
Definition: ntuser.h:853
#define ICLS_ICONTITLE
Definition: ntuser.h:928
#define UserHMGetHandle(obj)
Definition: ntuser.h:230
#define FNID_BUTTON
Definition: ntuser.h:861
@ UserGetCPDClass
Definition: ntuser.h:537
@ UserGetCPDU2A
Definition: ntuser.h:536
@ UserGetCPDA2U
Definition: ntuser.h:535
#define FNID_COMBOBOX
Definition: ntuser.h:862
#define ICLS_SCROLLBAR
Definition: ntuser.h:911
#define CSF_CACHEDSMICON
Definition: ntuser.h:557
struct _THREADINFO * GetW32ThreadInfo(VOID)
Definition: misc.c:801
#define FNID_DIALOG
Definition: ntuser.h:864
#define ICLS_MENU
Definition: ntuser.h:926
#define ICLS_COMBOLBOX
Definition: ntuser.h:914
#define ICLS_SWITCH
Definition: ntuser.h:927
#define GETPFNSERVER(fnid)
Definition: ntuser.h:904
#define FNID_STATIC
Definition: ntuser.h:868
#define FNID_EDIT
Definition: ntuser.h:865
#define ICLS_BUTTON
Definition: ntuser.h:907
@ TYPE_CALLPROC
Definition: ntuser.h:47
#define ICLS_DESKTOP
Definition: ntuser.h:924
#define FNID_IME
Definition: ntuser.h:869
#define CURSORF_FROMRESOURCE
Definition: ntuser.h:1194
#define CSF_SERVERSIDEPROC
Definition: ntuser.h:551
#define FNID_GHOST
Definition: ntuser.h:870
#define FNID_MENU
Definition: ntuser.h:856
#define ICLS_TOOLTIPS
Definition: ntuser.h:929
#define CSF_WOWDEFERDESTROY
Definition: ntuser.h:553
struct _SBWND SBWND
#define ICLS_MDICLIENT
Definition: ntuser.h:913
#define FNID_MESSAGEWND
Definition: ntuser.h:859
#define FNID_COMBOLBOX
Definition: ntuser.h:863
#define FNID_TOOLTIPS
Definition: ntuser.h:883
#define FNID_MDICLIENT
Definition: ntuser.h:867
HGDIOBJ FASTCALL IntGetSysColorBrush(INT Object)
Definition: stockobj.c:317
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
static HICON
Definition: imagelist.c:84
unsigned short RTL_ATOM
Definition: atom.c:42
static refpint_t pi[]
Definition: server.c:96
#define _Success_(expr)
Definition: ms_sal.h:259
#define _Notnull_
Definition: ms_sal.h:658
#define _Post_
Definition: ms_sal.h:620
#define _At_(target, annos)
Definition: ms_sal.h:244
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define _Out_
Definition: ms_sal.h:345
#define _When_(expr, annos)
Definition: ms_sal.h:254
#define _In_
Definition: ms_sal.h:308
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI NTSTATUS NTAPI RtlAddAtomToAtomTable(_In_ PRTL_ATOM_TABLE AtomTable, _In_ PWSTR AtomName, _Out_ PRTL_ATOM Atom)
NTSYSAPI NTSTATUS NTAPI RtlLookupAtomInAtomTable(_In_ PRTL_ATOM_TABLE AtomTable, _In_ PWSTR AtomName, _Out_ PRTL_ATOM Atom)
NTSYSAPI NTSTATUS NTAPI RtlDeleteAtomFromAtomTable(_In_ PRTL_ATOM_TABLE AtomTable, _In_ RTL_ATOM Atom)
NTSYSAPI NTSTATUS NTAPI RtlQueryAtomInAtomTable(_In_ PRTL_ATOM_TABLE AtomTable, _In_ RTL_ATOM Atom, _Out_opt_ PULONG RefCount, _Out_opt_ PULONG PinCount, _Out_opt_z_bytecap_(*NameLength) PWSTR AtomName, _Inout_opt_ PULONG NameLength)
#define BOOL
Definition: nt_native.h:43
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToAnsiString(PANSI_STRING DestinationString, PUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define FASTCALL
Definition: nt_native.h:50
#define UNICODE_NULL
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
PVOID NTAPI PsGetCurrentThreadWin32Thread(VOID)
Definition: thread.c:805
BOOL UserPaintCaption(PWND pWnd, INT Flags)
Definition: defwnd.c:399
HINSTANCE hModClient
Definition: ntuser.c:25
VOID FASTCALL UserLeave(VOID)
Definition: ntuser.c:254
VOID FASTCALL UserEnterShared(VOID)
Definition: ntuser.c:238
VOID FASTCALL UserEnterExclusive(VOID)
Definition: ntuser.c:245
#define L(x)
Definition: ntvdm.h:50
struct _PROCESSINFO * PPROCESSINFO
Definition: ntwin32.h:5
#define TAG_STRING
Definition: oslist.h:22
#define CONST
Definition: pedump.c:81
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define INT
Definition: polytest.cpp:20
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForWriteUnicodeString(Ptr)
Definition: probe.h:48
#define ProbeForReadUint(Ptr)
Definition: probe.h:67
#define ProbeForReadUnicodeString(Ptr)
Definition: probe.h:77
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define TRACE(s)
Definition: solgame.cpp:4
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
Definition: solitaire.cpp:613
#define __in_data_source(src_sym)
Definition: specstrings.h:348
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: window.c:28
USHORT MaximumLength
Definition: env_spec_w32.h:377
WNDPROC pfnClientPrevious
Definition: ntuser.h:547
struct _CALLPROCDATA * spcpdNext
Definition: ntuser.h:546
PUNICODE_STRING pusMenuName
Definition: ntuser.h:495
Definition: ntuser.h:561
struct _CURICON_OBJECT * spcur
Definition: ntuser.h:581
struct _DESKTOP * rpdeskParent
Definition: ntuser.h:566
struct _CLS * pclsBase
Definition: ntuser.h:572
UINT Global
Definition: ntuser.h:588
struct _CURICON_OBJECT * spicn
Definition: ntuser.h:580
PCALLPROCDATA spcpdFirst
Definition: ntuser.h:571
struct _CURICON_OBJECT * spicnSm
Definition: ntuser.h:585
struct _CLS * pclsClone
Definition: ntuser.h:573
struct _CLS * pclsNext
Definition: ntuser.h:562
ULONG CURSORF_flags
Definition: cursoricon.h:16
DWORD dwRegisteredClasses
Definition: win32.h:280
struct _CLS * pclsPublicList
Definition: win32.h:260
WNDPROC ProcW
Definition: ntuser.h:483
PPROCESSINFO ppi
Definition: win32.h:88
struct _DESKTOP * rpdesk
Definition: win32.h:92
USHORT MaximumLength
Definition: env_spec_w32.h:370
LPCWSTR lpszClassName
Definition: winuser.h:3216
LPCWSTR lpszMenuName
Definition: winuser.h:3215
HBRUSH hbrBackground
Definition: winuser.h:3214
WNDPROC lpfnWndProc
Definition: winuser.h:3208
UINT cbSize
Definition: winuser.h:3206
int cbWndExtra
Definition: winuser.h:3210
HCURSOR hCursor
Definition: winuser.h:3213
HICON hIconSm
Definition: winuser.h:3217
HINSTANCE hInstance
Definition: winuser.h:3211
UINT style
Definition: winuser.h:3207
int cbClsExtra
Definition: winuser.h:3209
HICON hIcon
Definition: winuser.h:3212
Definition: ntuser.h:689
ATOM atomSysClass[ICLS_NOTUSED+1]
Definition: ntuser.h:1055
#define TAG_USTR
Definition: tag.h:145
HANDLE HINSTANCE
Definition: typedefs.h:77
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG_PTR
Definition: typedefs.h:65
char * PSTR
Definition: typedefs.h:51
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t * LPDWORD
Definition: typedefs.h:59
int32_t INT
Definition: typedefs.h:58
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
PWND FASTCALL UserGetWindowObject(HWND hWnd)
Definition: window.c:122
static __inline PVOID UserHeapAlloc(SIZE_T Bytes)
Definition: usrheap.h:34
static __inline PVOID UserHeapAddressToUser(PVOID lpMem)
Definition: usrheap.h:99
static __inline BOOL UserHeapFree(PVOID lpMem)
Definition: usrheap.h:44
static int Link(const char **args)
Definition: vfdcmd.c:2414
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
#define W32PF_CLASSESREGISTERED
Definition: win32.h:17
VOID FASTCALL SetLastNtError(NTSTATUS Status)
Definition: error.c:37
HANDLE FASTCALL co_IntCopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
Definition: callback.c:985
int FnId
Definition: class.c:106
static VOID IntFreeClassMenuName(IN OUT PCLS Class)
Definition: class.c:216
INT UserGetClassName(IN PCLS Class, IN OUT PUNICODE_STRING ClassName, IN RTL_ATOM Atom, IN BOOL Ansi)
Definition: class.c:1634
ULONG_PTR UserSetClassLongPtr(IN PCLS Class, IN INT Index, IN ULONG_PTR NewLong, IN BOOL Ansi)
Definition: class.c:1858
static struct @4913 FnidToiCls[]
static VOID IntMakeCloneBaseClass(IN OUT PCLS Class, IN OUT PCLS *BaseClassLink, IN OUT PCLS *CloneLink)
Definition: class.c:777
static BOOL IntMoveClassToSharedHeap(IN OUT PCLS Class, IN OUT PCLS **ClassLinkPtr)
Definition: class.c:897
static PCLS IntFindClass(IN RTL_ATOM Atom, IN HINSTANCE hInstance, IN PCLS *ClassList, OUT PCLS **Link OPTIONAL)
Definition: class.c:1261
RTL_ATOM UserRegisterClass(IN CONST WNDCLASSEXW *lpwcx, IN PUNICODE_STRING ClassName, IN PUNICODE_STRING ClassVersion, IN PUNICODE_STRING MenuName, IN DWORD fnID, IN DWORD dwFlags)
Definition: class.c:1491
REGISTER_SYSCLASS DefaultServerClasses[]
Definition: class.c:35
INT APIENTRY NtUserGetClassName(IN HWND hWnd, IN BOOL Real, OUT PUNICODE_STRING ClassName)
Definition: class.c:2822
VOID UserAddCallProcToClass(IN OUT PCLS Class, IN PCALLPROCDATA CallProc)
Definition: class.c:423
WORD APIENTRY NtUserSetClassWord(HWND hWnd, INT nIndex, WORD wNewWord)
Definition: class.c:2673
PCLS IntReferenceClass(IN OUT PCLS BaseClass, IN OUT PCLS *ClassLink, IN PDESKTOP Desktop)
Definition: class.c:749
static PCLS IntGetClassForDesktop(IN OUT PCLS BaseClass, IN OUT PCLS *ClassLink, IN PDESKTOP Desktop)
Definition: class.c:625
BOOL IntCheckProcessDesktopClasses(IN PDESKTOP Desktop, IN BOOL FreeOnFailure)
Definition: class.c:1012
BOOL FASTCALL RegisterControlAtoms(VOID)
Definition: class.c:396
void FASTCALL DestroyProcessClasses(PPROCESSINFO Process)
Definition: class.c:300
VOID IntDereferenceClass(IN OUT PCLS Class, IN PDESKTOPINFO Desktop, IN PPROCESSINFO pi)
Definition: class.c:815
static BOOL UserGetClassInfo(IN PCLS Class, OUT PWNDCLASSEXW lpwcx, IN BOOL Ansi, HINSTANCE hInstance)
Definition: class.c:2249
static PWSTR ControlsList[]
Definition: class.c:12
static BOOL IntRegisterClassAtom(IN PUNICODE_STRING ClassName, OUT RTL_ATOM *pAtom)
Definition: class.c:334
PCLS APIENTRY NtUserGetWOWClass(HINSTANCE hInstance, PUNICODE_STRING ClassName)
Definition: class.c:2882
RTL_ATOM IntGetClassAtom(_In_ PUNICODE_STRING ClassName, IN HINSTANCE hInstance OPTIONAL, IN PPROCESSINFO pi OPTIONAL, OUT PCLS *BaseClass OPTIONAL, OUT PCLS **Link OPTIONAL)
Definition: class.c:1364
static BOOL IntSetClassMenuName(IN PCLS Class, IN PUNICODE_STRING MenuName)
Definition: class.c:1754
_Must_inspect_result_ NTSTATUS NTAPI ProbeAndCaptureUnicodeStringOrAtom(_Out_ _When_(return >=0, _At_(pustrOut->Buffer, _Post_ _Notnull_)) PUNICODE_STRING pustrOut, __in_data_source(USER_MODE) _In_ PUNICODE_STRING pustrUnsafe)
Definition: class.c:150
WNDPROC FASTCALL IntGetClassWndProc(PCLS Class, BOOL Ansi)
Definition: class.c:494
BOOL APIENTRY NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom, IN HINSTANCE hInstance, OUT PCLSMENUNAME pClassMenuName)
Definition: class.c:2686
PCLS IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance, BOOL bDesktopThread)
Definition: class.c:1437
static BOOL IntSetClassAtom(IN OUT PCLS Class, IN PUNICODE_STRING ClassName)
Definition: class.c:445
static VOID IntCheckDesktopClasses(IN PDESKTOP Desktop, IN OUT PCLS *ClassList, IN BOOL FreeOnFailure, OUT BOOL *Ret)
Definition: class.c:943
PCLS FASTCALL IntCreateClass(IN CONST WNDCLASSEXW *lpwcx, IN PUNICODE_STRING ClassName, IN PUNICODE_STRING ClassVersion, IN PUNICODE_STRING MenuName, IN DWORD fnID, IN DWORD dwFlags, IN PDESKTOP Desktop, IN PPROCESSINFO pi)
Definition: class.c:1042
RTL_ATOM APIENTRY NtUserRegisterClassExWOW(WNDCLASSEXW *lpwcx, PUNICODE_STRING ClassName, PUNICODE_STRING ClsVersion, PCLSMENUNAME pClassMenuName, DWORD fnID, DWORD Flags, LPDWORD pWow)
Definition: class.c:2413
BOOL FASTCALL UserRegisterSystemClasses(VOID)
Definition: class.c:2306
BOOL UserUnregisterClass(IN PUNICODE_STRING ClassName, IN HINSTANCE hInstance, OUT PCLSMENUNAME pClassMenuName)
Definition: class.c:1578
static NTSTATUS IntDeregisterClassAtom(IN RTL_ATOM Atom)
Definition: class.c:416
ULONG_PTR APIENTRY NtUserSetClassLong(HWND hWnd, INT Offset, ULONG_PTR dwNewLong, BOOL Ansi)
Definition: class.c:2575
static VOID IntDestroyClass(IN OUT PCLS Class)
Definition: class.c:228
BOOL APIENTRY NtUserGetClassInfo(HINSTANCE hInstance, PUNICODE_STRING ClassName, LPWNDCLASSEXW lpWndClassEx, LPWSTR *ppszMenuName, BOOL bAnsi)
Definition: class.c:2720
BOOL FASTCALL LookupFnIdToiCls(int FnId, int *iCls)
Definition: class.c:131
int ClsId
Definition: class.c:107
static WNDPROC FASTCALL IntSetClassWndProc(IN OUT PCLS Class, IN WNDPROC WndProc, IN BOOL Ansi)
Definition: class.c:543
PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
Definition: cursoricon.c:200
BOOLEAN IntDestroyCurIconObject(_In_ PVOID Object)
Definition: cursoricon.c:313
PTHREADINFO gptiDesktopThread
Definition: desktop.c:37
static __inline PVOID DesktopHeapAlloc(IN PDESKTOP Desktop, IN SIZE_T Bytes)
Definition: desktop.h:204
static __inline BOOL DesktopHeapFree(IN PDESKTOP Desktop, IN PVOID lpMem)
Definition: desktop.h:215
HANDLE hModuleWin
Definition: main.c:16
LONG NTAPI UserGetSystemMetrics(ULONG Index)
Definition: metric.c:208
PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type)
Definition: object.c:495
BOOL FASTCALL UserDereferenceObject(PVOID Object)
Definition: object.c:644
PUSER_HANDLE_TABLE gHandleTable
Definition: object.c:13
BOOL FASTCALL UserObjectInDestroy(HANDLE h)
Definition: object.c:703
VOID FASTCALL UserReferenceObject(PVOID obj)
Definition: object.c:731
PRTL_ATOM_TABLE gAtomTable
Definition: session.c:13
#define USERTAG_CLASS
Definition: tags.h:204
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
ENGAPI ULONG APIENTRY EngGetLastError(VOID)
Definition: error.c:12
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:28
HICON HCURSOR
Definition: windef.h:299
#define ERROR_CLASS_HAS_WINDOWS
Definition: winerror.h:893
#define ERROR_CLASS_ALREADY_EXISTS
Definition: winerror.h:891
#define ERROR_INVALID_INDEX
Definition: winerror.h:894
#define ERROR_INVALID_CURSOR_HANDLE
Definition: winerror.h:883
#define ERROR_CLASS_DOES_NOT_EXIST
Definition: winerror.h:892
#define ERROR_INVALID_FLAGS
Definition: winerror.h:583
#define ERROR_INVALID_ICON_HANDLE
Definition: winerror.h:895
#define CS_DROPSHADOW
Definition: winuser.h:655
#define CS_VREDRAW
Definition: winuser.h:653
#define GCLP_MENUNAME
Definition: winuser.h:672
#define GCLP_HICONSM
Definition: winuser.h:670
#define COLOR_MENU
Definition: winuser.h:911
#define GCLP_HMODULE
Definition: winuser.h:671
#define IMAGE_ICON
Definition: winuser.h:212
#define GCLP_HICON
Definition: winuser.h:669
#define LR_COPYFROMRESOURCE
Definition: winuser.h:1093
#define CS_HREDRAW
Definition: winuser.h:648
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
#define GCLP_WNDPROC
Definition: winuser.h:673
#define SM_CYSMICON
Definition: winuser.h:1007
#define CS_DBLCLKS
Definition: winuser.h:646
#define GCLP_HCURSOR
Definition: winuser.h:668
#define GCL_CBWNDEXTRA
Definition: winuser.h:658
#define SM_CXSMICON
Definition: winuser.h:1006
#define CS_GLOBALCLASS
Definition: winuser.h:647
#define CS_SAVEBITS
Definition: winuser.h:652
struct _WNDCLASSEXA * PWNDCLASSEXA
#define DC_ICON
Definition: winuser.h:429
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2896
#define CS_PARENTDC
Definition: winuser.h:651
#define GCLP_HBRBACKGROUND
Definition: winuser.h:667
#define OCR_NORMAL
Definition: winuser.h:1136
#define COLOR_BACKGROUND
Definition: winuser.h:907
#define GCW_ATOM
Definition: winuser.h:656
#define GCL_STYLE
Definition: winuser.h:665
#define GCL_CBCLSEXTRA
Definition: winuser.h:657
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define RtlUnicodeStringToAnsiSize(String)
Definition: rtlfuncs.h:1005
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184