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