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