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