892f66ce1c551d4183ef3d2b2c0a7610435880e1
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / class.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10 /* INCLUDES ******************************************************************/
11
12 #include <win32k.h>
13
14 DBG_DEFAULT_CHANNEL(UserClass);
15
16 REGISTER_SYSCLASS DefaultServerClasses[] =
17 {
18 { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
19 CS_GLOBALCLASS|CS_DBLCLKS,
20 NULL,
21 0,
22 IDC_ARROW,
23 (HBRUSH)(COLOR_BACKGROUND + 1),
24 FNID_DESKTOP,
25 ICLS_DESKTOP
26 },
27 { ((PWSTR)((ULONG_PTR)(WORD)(0x8003))),
28 CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS,
29 NULL, // Use User32 procs
30 sizeof(LONG),
31 IDC_ARROW,
32 NULL,
33 FNID_SWITCH,
34 ICLS_SWITCH
35 },
36 { ((PWSTR)((ULONG_PTR)(WORD)(0x8000))),
37 CS_DBLCLKS|CS_SAVEBITS,
38 NULL, // Use User32 procs
39 sizeof(LONG),
40 IDC_ARROW,
41 (HBRUSH)(COLOR_MENU + 1),
42 FNID_MENU,
43 ICLS_MENU
44 },
45 { L"ScrollBar",
46 CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW|CS_PARENTDC,
47 NULL, // Use User32 procs
48 0,
49 IDC_ARROW,
50 NULL,
51 FNID_SCROLLBAR,
52 ICLS_SCROLLBAR
53 },
54 { ((PWSTR)((ULONG_PTR)(WORD)(0x8004))), // IconTitle is here for now...
55 0,
56 NULL, // Use User32 procs
57 0,
58 IDC_ARROW,
59 0,
60 FNID_ICONTITLE,
61 ICLS_ICONTITLE
62 },
63 { L"Message",
64 CS_GLOBALCLASS,
65 NULL, // Use User32 procs
66 0,
67 IDC_ARROW,
68 NULL,
69 FNID_MESSAGEWND,
70 ICLS_HWNDMESSAGE
71 }
72 };
73
74 static struct
75 {
76 int FnId;
77 int ClsId;
78 } FnidToiCls[] =
79 { /* Function Ids to Class indexes. */
80 { FNID_SCROLLBAR, ICLS_SCROLLBAR},
81 { FNID_ICONTITLE, ICLS_ICONTITLE},
82 { FNID_MENU, ICLS_MENU},
83 { FNID_DESKTOP, ICLS_DESKTOP},
84 { FNID_SWITCH, ICLS_SWITCH},
85 { FNID_MESSAGEWND, ICLS_HWNDMESSAGE},
86 { FNID_BUTTON, ICLS_BUTTON},
87 { FNID_COMBOBOX, ICLS_COMBOBOX},
88 { FNID_COMBOLBOX, ICLS_COMBOLBOX},
89 { FNID_DIALOG, ICLS_DIALOG},
90 { FNID_EDIT, ICLS_EDIT},
91 { FNID_LISTBOX, ICLS_LISTBOX},
92 { FNID_MDICLIENT, ICLS_MDICLIENT},
93 { FNID_STATIC, ICLS_STATIC},
94 { FNID_IME, ICLS_IME},
95 { FNID_GHOST, ICLS_GHOST},
96 { FNID_TOOLTIPS, ICLS_TOOLTIPS}
97 };
98
99 BOOL
100 FASTCALL
101 LookupFnIdToiCls(int FnId, int *iCls )
102 {
103 int i;
104
105 for ( i = 0; i < ARRAYSIZE(FnidToiCls); i++)
106 {
107 if (FnidToiCls[i].FnId == FnId)
108 {
109 if (iCls) *iCls = FnidToiCls[i].ClsId;
110 return TRUE;
111 }
112 }
113 if (iCls) *iCls = 0;
114 return FALSE;
115 }
116
117 /* WINDOWCLASS ***************************************************************/
118
119 static VOID
120 IntFreeClassMenuName(IN OUT PCLS Class)
121 {
122 /* free the menu name, if it was changed and allocated */
123 if (Class->lpszClientUnicodeMenuName != NULL && Class->MenuNameIsString)
124 {
125 UserHeapFree(Class->lpszClientUnicodeMenuName);
126 Class->lpszClientUnicodeMenuName = NULL;
127 Class->lpszClientAnsiMenuName = NULL;
128 }
129 }
130
131 static VOID
132 IntDestroyClass(IN OUT PCLS Class)
133 {
134 PDESKTOP pDesk;
135 /* there shouldn't be any clones anymore */
136 ASSERT(Class->cWndReferenceCount == 0);
137 ASSERT(Class->pclsClone == NULL);
138
139 if (Class->pclsBase == Class)
140 {
141 PCALLPROCDATA CallProc, NextCallProc;
142
143 /* Destroy allocated callproc handles */
144 CallProc = Class->spcpdFirst;
145 while (CallProc != NULL)
146 {
147 NextCallProc = CallProc->spcpdNext;
148
149 CallProc->spcpdNext = NULL;
150 DestroyCallProc(NULL,
151 CallProc);
152
153 CallProc = NextCallProc;
154 }
155
156 if (Class->pdce)
157 {
158 DceFreeClassDCE(((PDCE)Class->pdce)->hDC);
159 Class->pdce = NULL;
160 }
161
162 IntFreeClassMenuName(Class);
163 }
164
165 pDesk = Class->rpdeskParent;
166 Class->rpdeskParent = NULL;
167
168 /* free the structure */
169 if (pDesk != NULL)
170 {
171 DesktopHeapFree(pDesk, Class);
172 }
173 else
174 {
175 UserHeapFree(Class);
176 }
177 }
178
179
180 /* clean all process classes. all process windows must cleaned first!! */
181 void FASTCALL DestroyProcessClasses(PPROCESSINFO Process )
182 {
183 PCLS Class;
184 PPROCESSINFO pi = (PPROCESSINFO)Process;
185
186 if (pi != NULL)
187 {
188 /* free all local classes */
189 Class = pi->pclsPrivateList;
190 while (Class != NULL)
191 {
192 pi->pclsPrivateList = Class->pclsNext;
193
194 ASSERT(Class->pclsBase == Class);
195 IntDestroyClass(Class);
196
197 Class = pi->pclsPrivateList;
198 }
199
200 /* free all global classes */
201 Class = pi->pclsPublicList;
202 while (Class != NULL)
203 {
204 pi->pclsPublicList = Class->pclsNext;
205
206 ASSERT(Class->pclsBase == Class);
207 IntDestroyClass(Class);
208
209 Class = pi->pclsPublicList;
210 }
211 }
212 }
213
214 static BOOL
215 IntRegisterClassAtom(IN PUNICODE_STRING ClassName,
216 OUT RTL_ATOM *pAtom)
217 {
218 WCHAR szBuf[65];
219 PWSTR AtomName;
220 NTSTATUS Status;
221
222 if (ClassName->Length != 0)
223 {
224 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
225 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
226 {
227 EngSetLastError(ERROR_INVALID_PARAMETER);
228 return (RTL_ATOM)0;
229 }
230
231 RtlCopyMemory(szBuf,
232 ClassName->Buffer,
233 ClassName->Length);
234 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
235 AtomName = szBuf;
236 }
237 else
238 AtomName = ClassName->Buffer;
239
240 Status = RtlAddAtomToAtomTable(gAtomTable,
241 AtomName,
242 pAtom);
243
244 if (!NT_SUCCESS(Status))
245 {
246 SetLastNtError(Status);
247 return FALSE;
248 }
249
250 return TRUE;
251 }
252
253 static NTSTATUS
254 IntDeregisterClassAtom(IN RTL_ATOM Atom)
255 {
256 return RtlDeleteAtomFromAtomTable(gAtomTable,
257 Atom);
258 }
259
260 VOID
261 UserAddCallProcToClass(IN OUT PCLS Class,
262 IN PCALLPROCDATA CallProc)
263 {
264 PCLS BaseClass;
265
266 ASSERT(CallProc->spcpdNext == NULL);
267
268 BaseClass = Class->pclsBase;
269 ASSERT(CallProc->spcpdNext == NULL);
270 CallProc->spcpdNext = BaseClass->spcpdFirst;
271 BaseClass->spcpdFirst = CallProc;
272
273 /* Update all clones */
274 Class = Class->pclsClone;
275 while (Class != NULL)
276 {
277 Class->spcpdFirst = BaseClass->spcpdFirst;
278 Class = Class->pclsNext;
279 }
280 }
281
282 static BOOL
283 IntSetClassAtom(IN OUT PCLS Class,
284 IN PUNICODE_STRING ClassName)
285 {
286 RTL_ATOM Atom = (RTL_ATOM)0;
287
288 /* update the base class first */
289 Class = Class->pclsBase;
290
291 if (!IntRegisterClassAtom(ClassName,
292 &Atom))
293 {
294 return FALSE;
295 }
296
297 IntDeregisterClassAtom(Class->atomClassName);
298
299 Class->atomClassName = Atom;
300
301 /* update the clones */
302 Class = Class->pclsClone;
303 while (Class != NULL)
304 {
305 Class->atomClassName = Atom;
306
307 Class = Class->pclsNext;
308 }
309
310 return TRUE;
311 }
312
313 //
314 // Same as User32:IntGetClsWndProc.
315 //
316 WNDPROC FASTCALL
317 IntGetClassWndProc(PCLS Class, BOOL Ansi)
318 {
319 INT i;
320 WNDPROC gcpd = NULL, Ret = NULL;
321
322 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
323 {
324 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
325 {
326 if (GETPFNSERVER(i) == Class->lpfnWndProc)
327 {
328 if (Ansi)
329 Ret = GETPFNCLIENTA(i);
330 else
331 Ret = GETPFNCLIENTW(i);
332 }
333 }
334 return Ret;
335 }
336 Ret = Class->lpfnWndProc;
337
338 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
339 {
340 if (Ansi)
341 {
342 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
343 Ret = GETPFNCLIENTA(Class->fnid);
344 }
345 else
346 {
347 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
348 Ret = GETPFNCLIENTW(Class->fnid);
349 }
350 }
351
352 if ( Ret != Class->lpfnWndProc ||
353 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
354 return Ret;
355
356 gcpd = (WNDPROC)UserGetCPD( Class,
357 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDClass,
358 (ULONG_PTR)Ret);
359
360 return (gcpd ? gcpd : Ret);
361 }
362
363
364 static
365 WNDPROC FASTCALL
366 IntSetClassWndProc(IN OUT PCLS Class,
367 IN WNDPROC WndProc,
368 IN BOOL Ansi)
369 {
370 INT i;
371 PCALLPROCDATA pcpd;
372 WNDPROC Ret, chWndProc;
373
374 Ret = IntGetClassWndProc(Class, Ansi);
375
376 // If Server Side, downgrade to Client Side.
377 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
378 {
379 if (Ansi) Class->CSF_flags |= CSF_ANSIPROC;
380 Class->CSF_flags &= ~CSF_SERVERSIDEPROC;
381 Class->Unicode = !Ansi;
382 }
383
384 if (!WndProc) WndProc = Class->lpfnWndProc;
385
386 chWndProc = WndProc;
387
388 // Check if CallProc handle and retrieve previous call proc address and set.
389 if (IsCallProcHandle(WndProc))
390 {
391 pcpd = UserGetObject(gHandleTable, WndProc, otCallProc);
392 if (pcpd) chWndProc = pcpd->pfnClientPrevious;
393 }
394
395 Class->lpfnWndProc = chWndProc;
396
397 // Clear test proc.
398 chWndProc = NULL;
399
400 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
401 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
402 {
403 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
404 {
405 chWndProc = GETPFNSERVER(i);
406 break;
407 }
408 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
409 {
410 chWndProc = GETPFNSERVER(i);
411 break;
412 }
413 }
414 // If match, set/reset to Server Side and clear ansi.
415 if (chWndProc)
416 {
417 Class->lpfnWndProc = chWndProc;
418 Class->Unicode = TRUE;
419 Class->CSF_flags &= ~CSF_ANSIPROC;
420 Class->CSF_flags |= CSF_SERVERSIDEPROC;
421 }
422 else
423 {
424 Class->Unicode = !Ansi;
425
426 if (Ansi)
427 Class->CSF_flags |= CSF_ANSIPROC;
428 else
429 Class->CSF_flags &= ~CSF_ANSIPROC;
430 }
431
432 /* update the clones */
433 chWndProc = Class->lpfnWndProc;
434
435 Class = Class->pclsClone;
436 while (Class != NULL)
437 {
438 Class->Unicode = !Ansi;
439 Class->lpfnWndProc = chWndProc;
440
441 Class = Class->pclsNext;
442 }
443
444 return Ret;
445 }
446
447 static PCLS
448 IntGetClassForDesktop(IN OUT PCLS BaseClass,
449 IN OUT PCLS *ClassLink,
450 IN PDESKTOP Desktop)
451 {
452 SIZE_T ClassSize;
453 PCLS Class;
454
455 ASSERT(Desktop != NULL);
456 ASSERT(BaseClass->pclsBase == BaseClass);
457
458 if (BaseClass->rpdeskParent == Desktop)
459 {
460 /* it is most likely that a window is created on the same
461 desktop as the window class. */
462
463 return BaseClass;
464 }
465
466 if (BaseClass->rpdeskParent == NULL)
467 {
468 ASSERT(BaseClass->cWndReferenceCount == 0);
469 ASSERT(BaseClass->pclsClone == NULL);
470
471 /* Classes are also located in the shared heap when the class
472 was created before the thread attached to a desktop. As soon
473 as a window is created for such a class located on the shared
474 heap, the class is cloned into the desktop heap on which the
475 window is created. */
476 Class = NULL;
477 }
478 else
479 {
480 /* The user is asking for a class object on a different desktop,
481 try to find one! */
482 Class = BaseClass->pclsClone;
483 while (Class != NULL)
484 {
485 if (Class->rpdeskParent == Desktop)
486 {
487 ASSERT(Class->pclsBase == BaseClass);
488 ASSERT(Class->pclsClone == NULL);
489 break;
490 }
491
492 Class = Class->pclsNext;
493 }
494 }
495
496 if (Class == NULL)
497 {
498 /* The window is created on a different desktop, we need to
499 clone the class object to the desktop heap of the window! */
500 ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->cbclsExtra;
501
502 Class = DesktopHeapAlloc(Desktop,
503 ClassSize);
504 if (Class != NULL)
505 {
506 /* simply clone the class */
507 RtlCopyMemory( Class, BaseClass, ClassSize);
508
509 TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
510
511 /* restore module address if default user class Ref: Bug 4778 */
512 if ( Class->hModule != hModClient &&
513 Class->fnid <= FNID_GHOST &&
514 Class->fnid >= FNID_BUTTON )
515 {
516 Class->hModule = hModClient;
517 TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class, Class->hModule);
518 }
519
520 /* update some pointers and link the class */
521 Class->rpdeskParent = Desktop;
522 Class->cWndReferenceCount = 0;
523
524 if (BaseClass->rpdeskParent == NULL)
525 {
526 /* we don't really need the base class on the shared
527 heap anymore, delete it so the only class left is
528 the clone we just created, which now serves as the
529 new base class */
530 ASSERT(BaseClass->pclsClone == NULL);
531 ASSERT(Class->pclsClone == NULL);
532 Class->pclsBase = Class;
533 Class->pclsNext = BaseClass->pclsNext;
534
535 /* replace the base class */
536 (void)InterlockedExchangePointer((PVOID*)ClassLink,
537 Class);
538
539 /* destroy the obsolete copy on the shared heap */
540 BaseClass->pclsBase = NULL;
541 BaseClass->pclsClone = NULL;
542 IntDestroyClass(BaseClass);
543 }
544 else
545 {
546 /* link in the clone */
547 Class->pclsClone = NULL;
548 Class->pclsBase = BaseClass;
549 Class->pclsNext = BaseClass->pclsClone;
550 (void)InterlockedExchangePointer((PVOID*)&BaseClass->pclsClone,
551 Class);
552 }
553 }
554 else
555 {
556 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
557 }
558 }
559 return Class;
560 }
561
562 PCLS
563 IntReferenceClass(IN OUT PCLS BaseClass,
564 IN OUT PCLS *ClassLink,
565 IN PDESKTOP Desktop)
566 {
567 PCLS Class;
568 ASSERT(BaseClass->pclsBase == BaseClass);
569
570 Class = IntGetClassForDesktop(BaseClass,
571 ClassLink,
572 Desktop);
573 if (Class != NULL)
574 {
575 Class->cWndReferenceCount++;
576 }
577
578 return Class;
579 }
580
581 static
582 VOID
583 IntMakeCloneBaseClass(IN OUT PCLS Class,
584 IN OUT PCLS *BaseClassLink,
585 IN OUT PCLS *CloneLink)
586 {
587 PCLS Clone;
588
589 ASSERT(Class->pclsBase != Class);
590 ASSERT(Class->pclsBase->pclsClone != NULL);
591 ASSERT(Class->rpdeskParent != NULL);
592 ASSERT(Class->cWndReferenceCount != 0);
593 ASSERT(Class->pclsBase->rpdeskParent != NULL);
594 ASSERT(Class->pclsBase->cWndReferenceCount == 0);
595
596 /* unlink the clone */
597 *CloneLink = Class->pclsNext;
598 Class->pclsClone = Class->pclsBase->pclsClone;
599
600 /* update the class information to make it a base class */
601 Class->pclsBase = Class;
602 Class->pclsNext = (*BaseClassLink)->pclsNext;
603
604 /* update all clones */
605 Clone = Class->pclsClone;
606 while (Clone != NULL)
607 {
608 ASSERT(Clone->pclsClone == NULL);
609 Clone->pclsBase = Class;
610
611 Clone = Clone->pclsNext;
612 }
613
614 /* link in the new base class */
615 (void)InterlockedExchangePointer((PVOID*)BaseClassLink,
616 Class);
617 }
618
619
620 VOID
621 IntDereferenceClass(IN OUT PCLS Class,
622 IN PDESKTOPINFO Desktop,
623 IN PPROCESSINFO pi)
624 {
625 PCLS *PrevLink, BaseClass, CurrentClass;
626
627 BaseClass = Class->pclsBase;
628
629 if (--Class->cWndReferenceCount <= 0)
630 {
631 if (BaseClass == Class)
632 {
633 ASSERT(Class->pclsBase == Class);
634
635 TRACE("IntDereferenceClass 0x%x\n", Class);
636 /* check if there are clones of the class on other desktops,
637 link the first clone in if possible. If there are no clones
638 then leave the class on the desktop heap. It will get moved
639 to the shared heap when the thread detaches. */
640 if (BaseClass->pclsClone != NULL)
641 {
642 if (BaseClass->Global)
643 PrevLink = &pi->pclsPublicList;
644 else
645 PrevLink = &pi->pclsPrivateList;
646
647 CurrentClass = *PrevLink;
648 while (CurrentClass != BaseClass)
649 {
650 ASSERT(CurrentClass != NULL);
651
652 PrevLink = &CurrentClass->pclsNext;
653 CurrentClass = CurrentClass->pclsNext;
654 }
655
656 ASSERT(*PrevLink == BaseClass);
657
658 /* make the first clone become the new base class */
659 IntMakeCloneBaseClass(BaseClass->pclsClone,
660 PrevLink,
661 &BaseClass->pclsClone);
662
663 /* destroy the class, there's still another clone of the class
664 that now serves as a base class. Make sure we don't destruct
665 resources shared by all classes (Base = NULL)! */
666 BaseClass->pclsBase = NULL;
667 BaseClass->pclsClone = NULL;
668 IntDestroyClass(BaseClass);
669 }
670 }
671 else
672 {
673 TRACE("IntDereferenceClass1 0x%x\n", Class);
674
675 /* locate the cloned class and unlink it */
676 PrevLink = &BaseClass->pclsClone;
677 CurrentClass = BaseClass->pclsClone;
678 while (CurrentClass != Class)
679 {
680 ASSERT(CurrentClass != NULL);
681
682 PrevLink = &CurrentClass->pclsNext;
683 CurrentClass = CurrentClass->pclsNext;
684 }
685
686 ASSERT(CurrentClass == Class);
687
688 (void)InterlockedExchangePointer((PVOID*)PrevLink,
689 Class->pclsNext);
690
691 ASSERT(Class->pclsBase == BaseClass);
692 ASSERT(Class->pclsClone == NULL);
693
694 /* the class was just a clone, we don't need it anymore */
695 IntDestroyClass(Class);
696 }
697 }
698 }
699
700 static BOOL
701 IntMoveClassToSharedHeap(IN OUT PCLS Class,
702 IN OUT PCLS **ClassLinkPtr)
703 {
704 PCLS NewClass;
705 SIZE_T ClassSize;
706
707 ASSERT(Class->pclsBase == Class);
708 ASSERT(Class->rpdeskParent != NULL);
709 ASSERT(Class->cWndReferenceCount == 0);
710 ASSERT(Class->pclsClone == NULL);
711
712 ClassSize = sizeof(*Class) + (SIZE_T)Class->cbclsExtra;
713
714 /* allocate the new base class on the shared heap */
715 NewClass = UserHeapAlloc(ClassSize);
716 if (NewClass != NULL)
717 {
718 RtlCopyMemory(NewClass,
719 Class,
720 ClassSize);
721
722 NewClass->rpdeskParent = NULL;
723 NewClass->pclsBase = NewClass;
724
725 /* replace the class in the list */
726 (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
727 NewClass);
728 *ClassLinkPtr = &NewClass->pclsNext;
729
730 /* free the obsolete class on the desktop heap */
731 Class->pclsBase = NULL;
732 IntDestroyClass(Class);
733 return TRUE;
734 }
735
736 return FALSE;
737 }
738
739 static VOID
740 IntCheckDesktopClasses(IN PDESKTOP Desktop,
741 IN OUT PCLS *ClassList,
742 IN BOOL FreeOnFailure,
743 OUT BOOL *Ret)
744 {
745 PCLS Class, NextClass, *Link;
746
747 /* NOTE: We only need to check base classes! When classes are no longer needed
748 on a desktop, the clones will be freed automatically as soon as possible.
749 However, we need to move base classes to the shared heap, as soon as
750 the last desktop heap where a class is allocated on is about to be destroyed.
751 If we didn't move the class to the shared heap, the class would become
752 inaccessible! */
753
754 ASSERT(Desktop != NULL);
755
756 Link = ClassList;
757 Class = *Link;
758 while (Class != NULL)
759 {
760 NextClass = Class->pclsNext;
761
762 ASSERT(Class->pclsBase == Class);
763
764 if (Class->rpdeskParent == Desktop &&
765 Class->cWndReferenceCount == 0)
766 {
767 /* there shouldn't be any clones around anymore! */
768 ASSERT(Class->pclsClone == NULL);
769
770 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
771 /* FIXME - We could move the class to another desktop heap if there's still desktops
772 mapped into the process... */
773
774 /* move the class to the shared heap */
775 if (IntMoveClassToSharedHeap(Class,
776 &Link))
777 {
778 ASSERT(*Link == NextClass);
779 }
780 else
781 {
782 ASSERT(NextClass == Class->pclsNext);
783
784 if (FreeOnFailure)
785 {
786 /* unlink the base class */
787 (void)InterlockedExchangePointer((PVOID*)Link,
788 Class->pclsNext);
789
790 /* we can free the old base class now */
791 Class->pclsBase = NULL;
792 IntDestroyClass(Class);
793 }
794 else
795 {
796 Link = &Class->pclsNext;
797 *Ret = FALSE;
798 }
799 }
800 }
801 else
802 Link = &Class->pclsNext;
803
804 Class = NextClass;
805 }
806 }
807
808 BOOL
809 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
810 IN BOOL FreeOnFailure)
811 {
812 PPROCESSINFO pi;
813 BOOL Ret = TRUE;
814
815 pi = GetW32ProcessInfo();
816
817 /* check all local classes */
818 IntCheckDesktopClasses(Desktop,
819 &pi->pclsPrivateList,
820 FreeOnFailure,
821 &Ret);
822
823 /* check all global classes */
824 IntCheckDesktopClasses(Desktop,
825 &pi->pclsPublicList,
826 FreeOnFailure,
827 &Ret);
828 if (!Ret)
829 {
830 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
831 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
832 }
833
834 return Ret;
835 }
836
837 PCLS
838 FASTCALL
839 IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
840 IN PUNICODE_STRING ClassName,
841 IN PUNICODE_STRING MenuName,
842 IN DWORD fnID,
843 IN DWORD dwFlags,
844 IN PDESKTOP Desktop,
845 IN PPROCESSINFO pi)
846 {
847 SIZE_T ClassSize;
848 PCLS Class = NULL;
849 RTL_ATOM Atom;
850 WNDPROC WndProc;
851 PWSTR pszMenuName = NULL;
852 NTSTATUS Status = STATUS_SUCCESS;
853
854 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
855 lpwcx, ClassName, MenuName, dwFlags, Desktop, pi);
856
857 if (!IntRegisterClassAtom(ClassName,
858 &Atom))
859 {
860 ERR("Failed to register class atom!\n");
861 return NULL;
862 }
863
864 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
865 if (MenuName->Length != 0)
866 {
867 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
868 RtlUnicodeStringToAnsiSize(MenuName));
869 if (pszMenuName == NULL)
870 goto NoMem;
871 }
872
873 if (Desktop != NULL)
874 {
875 Class = DesktopHeapAlloc(Desktop,
876 ClassSize);
877 }
878 else
879 {
880 /* FIXME - the class was created before being connected
881 to a desktop. It is possible for the desktop window,
882 but should it be allowed for any other case? */
883 Class = UserHeapAlloc(ClassSize);
884 }
885
886 if (Class != NULL)
887 {
888 int iCls = 0;
889
890 RtlZeroMemory(Class, ClassSize);
891
892 Class->rpdeskParent = Desktop;
893 Class->pclsBase = Class;
894 Class->atomClassName = Atom;
895 Class->fnid = fnID;
896 Class->CSF_flags = dwFlags;
897
898 if (LookupFnIdToiCls(Class->fnid, &iCls))
899 {
900 gpsi->atomSysClass[iCls] = Class->atomClassName;
901 }
902
903 _SEH2_TRY
904 {
905 PWSTR pszMenuNameBuffer = pszMenuName;
906
907 /* need to protect with SEH since accessing the WNDCLASSEX structure
908 and string buffers might raise an exception! We don't want to
909 leak memory... */
910 // What?! If the user interface was written correctly this would not be an issue!
911 Class->lpfnWndProc = lpwcx->lpfnWndProc;
912 Class->style = lpwcx->style;
913 Class->cbclsExtra = lpwcx->cbClsExtra;
914 Class->cbwndExtra = lpwcx->cbWndExtra;
915 Class->hModule = lpwcx->hInstance;
916 Class->hIcon = lpwcx->hIcon; /* FIXME */
917 Class->hIconSm = lpwcx->hIconSm; /* FIXME */
918 Class->hCursor = lpwcx->hCursor; /* FIXME */
919 Class->hbrBackground = lpwcx->hbrBackground;
920
921 /* make a copy of the string */
922 if (pszMenuNameBuffer != NULL)
923 {
924 Class->MenuNameIsString = TRUE;
925
926 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
927 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
928 MenuName->Buffer,
929 MenuName->Length);
930 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
931
932 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
933 }
934 else
935 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
936
937 /* save an ansi copy of the string */
938 if (pszMenuNameBuffer != NULL)
939 {
940 ANSI_STRING AnsiString;
941
942 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
943 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
944 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
945 Status = RtlUnicodeStringToAnsiString(&AnsiString,
946 MenuName,
947 FALSE);
948 if (!NT_SUCCESS(Status))
949 {
950 ERR("Failed to convert unicode menu name to ansi!\n");
951
952 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
953 _SEH2_LEAVE;
954 }
955 }
956 else
957 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
958
959 /* Save kernel use menu name and ansi class name */
960 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // Fixme!
961 //Class->lpszAnsiClassName = Fixme!
962
963 /* Server Side overrides class calling type (A/W)!
964 User32 whine test_builtinproc: "deftest"
965 built-in winproc - window A/W type automatically detected */
966 if (!(Class->CSF_flags & CSF_SERVERSIDEPROC))
967 {
968 int i;
969 WndProc = NULL;
970 /* Due to the wine class "deftest" and most likely no FNID to reference
971 from, sort through the Server Side list and compare proc addresses
972 for match. This method will be used in related code.
973 */
974 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
975 { // Open Ansi or Unicode, just match, set and break.
976 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
977 {
978 WndProc = GETPFNSERVER(i);
979 break;
980 }
981 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
982 {
983 WndProc = GETPFNSERVER(i);
984 break;
985 }
986 }
987 if (WndProc)
988 { // If a hit, we are Server Side so set the right flags and proc.
989 Class->CSF_flags |= CSF_SERVERSIDEPROC;
990 Class->CSF_flags &= ~CSF_ANSIPROC;
991 Class->lpfnWndProc = WndProc;
992 }
993 }
994
995 if (!(Class->CSF_flags & CSF_ANSIPROC))
996 Class->Unicode = TRUE;
997
998 if (Class->style & CS_GLOBALCLASS)
999 Class->Global = TRUE;
1000 }
1001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1002 {
1003 Status = _SEH2_GetExceptionCode();
1004 }
1005 _SEH2_END;
1006
1007 if (!NT_SUCCESS(Status))
1008 {
1009 ERR("Failed creating the class: 0x%x\n", Status);
1010
1011 SetLastNtError(Status);
1012
1013 if (pszMenuName != NULL)
1014 UserHeapFree(pszMenuName);
1015
1016 DesktopHeapFree(Desktop,
1017 Class);
1018 Class = NULL;
1019
1020 IntDeregisterClassAtom(Atom);
1021 }
1022 }
1023 else
1024 {
1025 NoMem:
1026 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop);
1027
1028 if (pszMenuName != NULL)
1029 UserHeapFree(pszMenuName);
1030
1031 IntDeregisterClassAtom(Atom);
1032
1033 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1034 }
1035
1036 TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
1037 Class, ClassName, Class->lpfnWndProc, Atom, Class->hModule, Class->Global);
1038
1039 return Class;
1040 }
1041
1042 static PCLS
1043 IntFindClass(IN RTL_ATOM Atom,
1044 IN HINSTANCE hInstance,
1045 IN PCLS *ClassList,
1046 OUT PCLS **Link OPTIONAL)
1047 {
1048 PCLS Class, *PrevLink = ClassList;
1049
1050 Class = *PrevLink;
1051 while (Class != NULL)
1052 {
1053 if (Class->atomClassName == Atom &&
1054 (hInstance == NULL || Class->hModule == hInstance) &&
1055 !(Class->CSF_flags & CSF_WOWDEFERDESTROY))
1056 {
1057 ASSERT(Class->pclsBase == Class);
1058
1059 if (Link != NULL)
1060 *Link = PrevLink;
1061 break;
1062 }
1063
1064 PrevLink = &Class->pclsNext;
1065 Class = Class->pclsNext;
1066 }
1067
1068 return Class;
1069 }
1070
1071 BOOL
1072 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
1073 OUT RTL_ATOM *Atom)
1074 {
1075 BOOL Ret = FALSE;
1076
1077 if (ClassName->Length != 0)
1078 {
1079 WCHAR szBuf[65];
1080 PWSTR AtomName;
1081 NTSTATUS Status;
1082
1083 /* NOTE: Caller has to protect the call with SEH! */
1084
1085 if (ClassName->Length != 0)
1086 {
1087 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1088 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
1089 {
1090 EngSetLastError(ERROR_INVALID_PARAMETER);
1091 return (RTL_ATOM)0;
1092 }
1093
1094 /* We need to make a local copy of the class name! The caller could
1095 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1096 We're protected by SEH, but the ranges that might be accessed were
1097 not probed... */
1098 RtlCopyMemory(szBuf,
1099 ClassName->Buffer,
1100 ClassName->Length);
1101 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1102 AtomName = szBuf;
1103 }
1104 else
1105 AtomName = ClassName->Buffer;
1106
1107 /* lookup the atom */
1108 Status = RtlLookupAtomInAtomTable(gAtomTable,
1109 AtomName,
1110 Atom);
1111 if (NT_SUCCESS(Status))
1112 {
1113 Ret = TRUE;
1114 }
1115 else
1116 {
1117 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1118 {
1119 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1120 }
1121 else
1122 {
1123 SetLastNtError(Status);
1124 }
1125 }
1126 }
1127 else
1128 {
1129 ASSERT(IS_ATOM(ClassName->Buffer));
1130 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1131 Ret = TRUE;
1132 }
1133
1134 return Ret;
1135 }
1136
1137 RTL_ATOM
1138 IntGetClassAtom(IN PUNICODE_STRING ClassName,
1139 IN HINSTANCE hInstance OPTIONAL,
1140 IN PPROCESSINFO pi OPTIONAL,
1141 OUT PCLS *BaseClass OPTIONAL,
1142 OUT PCLS **Link OPTIONAL)
1143 {
1144 RTL_ATOM Atom = (RTL_ATOM)0;
1145
1146 ASSERT(BaseClass != NULL);
1147
1148 if (IntGetAtomFromStringOrAtom(ClassName,
1149 &Atom) &&
1150 Atom != (RTL_ATOM)0)
1151 {
1152 PCLS Class;
1153
1154 /* attempt to locate the class object */
1155
1156 ASSERT(pi != NULL);
1157
1158 /* Step 1: try to find an exact match of locally registered classes */
1159 Class = IntFindClass(Atom,
1160 hInstance,
1161 &pi->pclsPrivateList,
1162 Link);
1163 if (Class != NULL)
1164 { TRACE("Step 1: 0x%x\n",Class );
1165 goto FoundClass;
1166 }
1167
1168 /* Step 2: try to find any globally registered class. The hInstance
1169 is not relevant for global classes */
1170 Class = IntFindClass(Atom,
1171 NULL,
1172 &pi->pclsPublicList,
1173 Link);
1174 if (Class != NULL)
1175 { TRACE("Step 2: 0x%x 0x%x\n",Class, Class->hModule);
1176 goto FoundClass;
1177 }
1178
1179 /* Step 3: try to find any local class registered by user32 */
1180 Class = IntFindClass(Atom,
1181 hModClient,
1182 &pi->pclsPrivateList,
1183 Link);
1184 if (Class != NULL)
1185 { TRACE("Step 3: 0x%x\n",Class );
1186 goto FoundClass;
1187 }
1188
1189 /* Step 4: try to find any global class registered by user32 */
1190 Class = IntFindClass(Atom,
1191 hModClient,
1192 &pi->pclsPublicList,
1193 Link);
1194 if (Class == NULL)
1195 {
1196 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1197 return (RTL_ATOM)0;
1198 }else{TRACE("Step 4: 0x%x\n",Class );}
1199
1200 FoundClass:
1201 *BaseClass = Class;
1202 }
1203
1204 return Atom;
1205 }
1206
1207 PCLS
1208 IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance)
1209 {
1210 PCLS *ClassLink, Class = NULL;
1211 RTL_ATOM ClassAtom;
1212 PTHREADINFO pti;
1213
1214 pti = PsGetCurrentThreadWin32Thread();
1215
1216 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1217 {
1218 UserRegisterSystemClasses();
1219 }
1220
1221 /* Check the class. */
1222
1223 TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName, hInstance);
1224
1225 ClassAtom = IntGetClassAtom(ClassName,
1226 hInstance,
1227 pti->ppi,
1228 &Class,
1229 &ClassLink);
1230
1231 if (ClassAtom == (RTL_ATOM)0)
1232 {
1233 if (IS_ATOM(ClassName->Buffer))
1234 {
1235 ERR("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
1236 }
1237 else
1238 {
1239 ERR("Class \"%wZ\" not found\n", ClassName);
1240 }
1241
1242 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
1243 return NULL;
1244 }
1245
1246 TRACE("Referencing Class 0x%x with atom 0x%x\n", Class, ClassAtom);
1247 Class = IntReferenceClass(Class,
1248 ClassLink,
1249 pti->rpdesk);
1250 if (Class == NULL)
1251 {
1252 ERR("Failed to reference window class!\n");
1253 return NULL;
1254 }
1255
1256 return Class;
1257 }
1258
1259 RTL_ATOM
1260 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1261 IN PUNICODE_STRING ClassName,
1262 IN PUNICODE_STRING MenuName,
1263 IN DWORD fnID,
1264 IN DWORD dwFlags)
1265 {
1266 PTHREADINFO pti;
1267 PPROCESSINFO pi;
1268 PCLS Class;
1269 RTL_ATOM ClassAtom;
1270 RTL_ATOM Ret = (RTL_ATOM)0;
1271
1272 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1273
1274 pti = GetW32ThreadInfo();
1275
1276 pi = pti->ppi;
1277
1278 // Need only to test for two conditions not four....... Fix more whine tests....
1279 if ( IntGetAtomFromStringOrAtom( ClassName, &ClassAtom) &&
1280 ClassAtom != (RTL_ATOM)0 &&
1281 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
1282 {
1283 Class = IntFindClass( ClassAtom,
1284 lpwcx->hInstance,
1285 &pi->pclsPrivateList,
1286 NULL);
1287
1288 if (Class != NULL && !Class->Global)
1289 {
1290 // local class already exists
1291 TRACE("Local Class 0x%p does already exist!\n", ClassAtom);
1292 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1293 return (RTL_ATOM)0;
1294 }
1295
1296 if (lpwcx->style & CS_GLOBALCLASS)
1297 {
1298 /* HACK: allow global classes to be re-registered*/
1299 Class = IntFindClass( ClassAtom,
1300 lpwcx->hInstance,
1301 &pi->pclsPublicList,
1302 NULL);
1303
1304 if (Class != NULL && Class->Global)
1305 {
1306 TRACE("Global Class 0x%p does already exist!\n", ClassAtom);
1307 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1308 return (RTL_ATOM)0;
1309 }
1310 }
1311 }
1312
1313 Class = IntCreateClass(lpwcx,
1314 ClassName,
1315 MenuName,
1316 fnID,
1317 dwFlags,
1318 pti->rpdesk,
1319 pi);
1320
1321 if (Class != NULL)
1322 {
1323 PCLS *List;
1324
1325 /* Register the class */
1326 if (Class->Global)
1327 List = &pi->pclsPublicList;
1328 else
1329 List = &pi->pclsPrivateList;
1330
1331 Class->pclsNext = *List;
1332 (void)InterlockedExchangePointer((PVOID*)List,
1333 Class);
1334
1335 Ret = Class->atomClassName;
1336 }
1337 else
1338 {
1339 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1340 }
1341
1342 return Ret;
1343 }
1344
1345 BOOL
1346 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1347 IN HINSTANCE hInstance,
1348 OUT PCLSMENUNAME pClassMenuName)
1349 {
1350 PCLS *Link;
1351 PPROCESSINFO pi;
1352 RTL_ATOM ClassAtom;
1353 PCLS Class;
1354
1355 pi = GetW32ProcessInfo();
1356
1357 TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName, hInstance);
1358
1359 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1360 ClassAtom = IntGetClassAtom(ClassName,
1361 hInstance,
1362 pi,
1363 &Class,
1364 &Link);
1365 if (ClassAtom == (RTL_ATOM)0)
1366 {
1367 TRACE("UserUnregisterClass: No Class found.\n");
1368 return FALSE;
1369 }
1370
1371 ASSERT(Class != NULL);
1372
1373 if (Class->cWndReferenceCount != 0 ||
1374 Class->pclsClone != NULL)
1375 {
1376 TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class->cWndReferenceCount, Class->pclsClone);
1377 EngSetLastError(ERROR_CLASS_HAS_WINDOWS);
1378 return FALSE;
1379 }
1380
1381 /* must be a base class! */
1382 ASSERT(Class->pclsBase == Class);
1383
1384 /* unlink the class */
1385 *Link = Class->pclsNext;
1386
1387 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1388 {
1389 TRACE("Class 0x%x\n", Class);
1390 TRACE("UserUnregisterClass: Good Exit!\n");
1391 /* finally free the resources */
1392 IntDestroyClass(Class);
1393 return TRUE;
1394 }
1395 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1396 return FALSE;
1397 }
1398
1399 INT
1400 UserGetClassName(IN PCLS Class,
1401 IN OUT PUNICODE_STRING ClassName,
1402 IN RTL_ATOM Atom,
1403 IN BOOL Ansi)
1404 {
1405 NTSTATUS Status = STATUS_SUCCESS;
1406 WCHAR szStaticTemp[32];
1407 PWSTR szTemp = NULL;
1408 ULONG BufLen = sizeof(szStaticTemp);
1409 INT Ret = 0;
1410
1411 /* Note: Accessing the buffer in ClassName may raise an exception! */
1412
1413 _SEH2_TRY
1414 {
1415 if (Ansi)
1416 {
1417 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1418 UNICODE_STRING UnicodeClassName;
1419
1420 /* limit the size of the static buffer on the stack to the
1421 size of the buffer provided by the caller */
1422 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1423 {
1424 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1425 }
1426
1427 /* find out how big the buffer needs to be */
1428 Status = RtlQueryAtomInAtomTable(gAtomTable,
1429 Class->atomClassName,
1430 NULL,
1431 NULL,
1432 szStaticTemp,
1433 &BufLen);
1434 if (Status == STATUS_BUFFER_TOO_SMALL)
1435 {
1436 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1437 {
1438 /* the buffer required exceeds the ansi buffer provided,
1439 pretend like we're using the ansi buffer and limit the
1440 size to the buffer size provided */
1441 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1442 }
1443
1444 /* allocate a temporary buffer that can hold the unicode class name */
1445 szTemp = ExAllocatePoolWithTag(PagedPool,
1446 BufLen,
1447 USERTAG_CLASS);
1448 if (szTemp == NULL)
1449 {
1450 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1451 _SEH2_LEAVE;
1452 }
1453
1454 /* query the class name */
1455 Status = RtlQueryAtomInAtomTable(gAtomTable,
1456 Atom ? Atom : Class->atomClassName,
1457 NULL,
1458 NULL,
1459 szTemp,
1460 &BufLen);
1461 }
1462 else
1463 szTemp = szStaticTemp;
1464
1465 if (NT_SUCCESS(Status))
1466 {
1467 /* convert the atom name to ansi */
1468
1469 RtlInitUnicodeString(&UnicodeClassName,
1470 szTemp);
1471
1472 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1473 &UnicodeClassName,
1474 FALSE);
1475 if (!NT_SUCCESS(Status))
1476 {
1477 SetLastNtError(Status);
1478 _SEH2_LEAVE;
1479 }
1480 }
1481
1482 Ret = BufLen / sizeof(WCHAR);
1483 }
1484 else /* !Ansi */
1485 {
1486 BufLen = ClassName->MaximumLength;
1487
1488 /* query the atom name */
1489 Status = RtlQueryAtomInAtomTable(gAtomTable,
1490 Atom ? Atom : Class->atomClassName,
1491 NULL,
1492 NULL,
1493 ClassName->Buffer,
1494 &BufLen);
1495
1496 if (!NT_SUCCESS(Status))
1497 {
1498 SetLastNtError(Status);
1499 _SEH2_LEAVE;
1500 }
1501
1502 Ret = BufLen / sizeof(WCHAR);
1503 }
1504 }
1505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1506 {
1507 SetLastNtError(_SEH2_GetExceptionCode());
1508 }
1509 _SEH2_END;
1510
1511 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1512 {
1513 ExFreePool(szTemp);
1514 }
1515
1516 return Ret;
1517 }
1518
1519 static BOOL
1520 IntSetClassMenuName(IN PCLS Class,
1521 IN PUNICODE_STRING MenuName)
1522 {
1523 BOOL Ret = FALSE;
1524
1525 /* change the base class first */
1526 Class = Class->pclsBase;
1527
1528 if (MenuName->Length != 0)
1529 {
1530 ANSI_STRING AnsiString;
1531 PWSTR strBufW;
1532
1533 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
1534
1535 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1536 AnsiString.MaximumLength);
1537 if (strBufW != NULL)
1538 {
1539 _SEH2_TRY
1540 {
1541 NTSTATUS Status;
1542
1543 /* copy the unicode string */
1544 RtlCopyMemory(strBufW,
1545 MenuName->Buffer,
1546 MenuName->Length);
1547 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1548
1549 /* create an ansi copy of the string */
1550 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1551 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1552 MenuName,
1553 FALSE);
1554 if (!NT_SUCCESS(Status))
1555 {
1556 SetLastNtError(Status);
1557 _SEH2_LEAVE;
1558 }
1559
1560 Ret = TRUE;
1561 }
1562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1563 {
1564 SetLastNtError(_SEH2_GetExceptionCode());
1565 }
1566 _SEH2_END;
1567
1568 if (Ret)
1569 {
1570 /* update the base class */
1571 IntFreeClassMenuName(Class);
1572 Class->lpszClientUnicodeMenuName = strBufW;
1573 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1574 Class->MenuNameIsString = TRUE;
1575
1576 /* update the clones */
1577 Class = Class->pclsClone;
1578 while (Class != NULL)
1579 {
1580 Class->lpszClientUnicodeMenuName = strBufW;
1581 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1582 Class->MenuNameIsString = TRUE;
1583
1584 Class = Class->pclsNext;
1585 }
1586 }
1587 else
1588 {
1589 ERR("Failed to copy class menu name!\n");
1590 UserHeapFree(strBufW);
1591 }
1592 }
1593 else
1594 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1595 }
1596 else
1597 {
1598 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1599
1600 /* update the base class */
1601 IntFreeClassMenuName(Class);
1602 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1603 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1604 Class->MenuNameIsString = FALSE;
1605
1606 /* update the clones */
1607 Class = Class->pclsClone;
1608 while (Class != NULL)
1609 {
1610 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1611 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1612 Class->MenuNameIsString = FALSE;
1613
1614 Class = Class->pclsNext;
1615 }
1616
1617 Ret = TRUE;
1618 }
1619
1620 return Ret;
1621 }
1622
1623 ULONG_PTR
1624 UserSetClassLongPtr(IN PCLS Class,
1625 IN INT Index,
1626 IN ULONG_PTR NewLong,
1627 IN BOOL Ansi)
1628 {
1629 ULONG_PTR Ret = 0;
1630
1631 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1632
1633 /* change the information in the base class first, then update the clones */
1634 Class = Class->pclsBase;
1635
1636 if (Index >= 0)
1637 {
1638 PULONG_PTR Data;
1639
1640 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1641
1642 if (Index + sizeof(ULONG_PTR) < Index ||
1643 Index + sizeof(ULONG_PTR) > Class->cbclsExtra)
1644 {
1645 EngSetLastError(ERROR_INVALID_PARAMETER);
1646 return 0;
1647 }
1648
1649 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1650
1651 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1652 certain architectures, maybe using RtlCopyMemory is a
1653 better choice for those architectures! */
1654 Ret = *Data;
1655 *Data = NewLong;
1656
1657 /* update the clones */
1658 Class = Class->pclsClone;
1659 while (Class != NULL)
1660 {
1661 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1662 Class = Class->pclsNext;
1663 }
1664
1665 return Ret;
1666 }
1667
1668 switch (Index)
1669 {
1670 case GCL_CBWNDEXTRA:
1671 Ret = (ULONG_PTR)Class->cbwndExtra;
1672 Class->cbwndExtra = (INT)NewLong;
1673
1674 /* update the clones */
1675 Class = Class->pclsClone;
1676 while (Class != NULL)
1677 {
1678 Class->cbwndExtra = (INT)NewLong;
1679 Class = Class->pclsNext;
1680 }
1681
1682 break;
1683
1684 case GCL_CBCLSEXTRA:
1685 EngSetLastError(ERROR_INVALID_PARAMETER);
1686 break;
1687
1688 case GCLP_HBRBACKGROUND:
1689 Ret = (ULONG_PTR)Class->hbrBackground;
1690 Class->hbrBackground = (HBRUSH)NewLong;
1691
1692 /* update the clones */
1693 Class = Class->pclsClone;
1694 while (Class != NULL)
1695 {
1696 Class->hbrBackground = (HBRUSH)NewLong;
1697 Class = Class->pclsNext;
1698 }
1699 break;
1700
1701 case GCLP_HCURSOR:
1702 /* FIXME - get handle from pointer to CURSOR object */
1703 Ret = (ULONG_PTR)Class->hCursor;
1704 Class->hCursor = (HANDLE)NewLong;
1705
1706 /* update the clones */
1707 Class = Class->pclsClone;
1708 while (Class != NULL)
1709 {
1710 Class->hCursor = (HANDLE)NewLong;
1711 Class = Class->pclsNext;
1712 }
1713 break;
1714
1715 case GCLP_HICON:
1716 /* FIXME - get handle from pointer to ICON object */
1717 Ret = (ULONG_PTR)Class->hIcon;
1718 Class->hIcon = (HANDLE)NewLong;
1719
1720 /* update the clones */
1721 Class = Class->pclsClone;
1722 while (Class != NULL)
1723 {
1724 Class->hIcon = (HANDLE)NewLong;
1725 Class = Class->pclsNext;
1726 }
1727 break;
1728
1729 case GCLP_HICONSM:
1730 /* FIXME - get handle from pointer to ICON object */
1731 Ret = (ULONG_PTR)Class->hIconSm;
1732 Class->hIconSm = (HANDLE)NewLong;
1733
1734 /* update the clones */
1735 Class = Class->pclsClone;
1736 while (Class != NULL)
1737 {
1738 Class->hIconSm = (HANDLE)NewLong;
1739 Class = Class->pclsNext;
1740 }
1741 break;
1742
1743 case GCLP_HMODULE:
1744 Ret = (ULONG_PTR)Class->hModule;
1745 Class->hModule = (HINSTANCE)NewLong;
1746
1747 /* update the clones */
1748 Class = Class->pclsClone;
1749 while (Class != NULL)
1750 {
1751 Class->hModule = (HINSTANCE)NewLong;
1752 Class = Class->pclsNext;
1753 }
1754 break;
1755
1756 case GCLP_MENUNAME:
1757 {
1758 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1759
1760 if (!IntSetClassMenuName(Class,
1761 Value))
1762 {
1763 ERR("Setting the class menu name failed!\n");
1764 }
1765
1766 /* FIXME - really return NULL? Wine does so... */
1767 break;
1768 }
1769
1770 case GCL_STYLE:
1771 Ret = (ULONG_PTR)Class->style;
1772 Class->style = (UINT)NewLong;
1773
1774 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1775 move the class to the appropriate list? For now, we save
1776 the original value in Class->Global, so we can always
1777 locate the appropriate list */
1778
1779 /* update the clones */
1780 Class = Class->pclsClone;
1781 while (Class != NULL)
1782 {
1783 Class->style = (UINT)NewLong;
1784 Class = Class->pclsNext;
1785 }
1786 break;
1787
1788 case GCLP_WNDPROC:
1789 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1790 (WNDPROC)NewLong,
1791 Ansi);
1792 break;
1793
1794 case GCW_ATOM:
1795 {
1796 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1797
1798 Ret = (ULONG_PTR)Class->atomClassName;
1799 if (!IntSetClassAtom(Class,
1800 Value))
1801 {
1802 Ret = 0;
1803 }
1804 break;
1805 }
1806
1807 default:
1808 EngSetLastError(ERROR_INVALID_INDEX);
1809 break;
1810 }
1811
1812 return Ret;
1813 }
1814
1815 static BOOL
1816 UserGetClassInfo(IN PCLS Class,
1817 OUT PWNDCLASSEXW lpwcx,
1818 IN BOOL Ansi,
1819 HINSTANCE hInstance)
1820 {
1821 if (!Class) return FALSE;
1822
1823 lpwcx->style = Class->style;
1824
1825 // If fnId is set, clear the global bit. See wine class test check_style.
1826 if (Class->fnid)
1827 lpwcx->style &= ~CS_GLOBALCLASS;
1828
1829 lpwcx->lpfnWndProc = IntGetClassWndProc(Class, Ansi);
1830
1831 lpwcx->cbClsExtra = Class->cbclsExtra;
1832 lpwcx->cbWndExtra = Class->cbwndExtra;
1833 lpwcx->hIcon = Class->hIcon; /* FIXME - get handle from pointer */
1834 lpwcx->hCursor = Class->hCursor; /* FIXME - get handle from pointer */
1835 lpwcx->hbrBackground = Class->hbrBackground;
1836
1837 /* Copy non-string to user first. */
1838 if (Ansi)
1839 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName;
1840 else
1841 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName;
1842 /*
1843 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1844 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1845 lpszClientXxxMenuName should already be mapped to user space.
1846 */
1847 /* Copy string ptr to user. */
1848 if ( Class->lpszClientUnicodeMenuName != NULL &&
1849 Class->MenuNameIsString)
1850 {
1851 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ?
1852 (PVOID)Class->lpszClientAnsiMenuName :
1853 (PVOID)Class->lpszClientUnicodeMenuName);
1854 }
1855
1856 if (hInstance == hModClient)
1857 lpwcx->hInstance = NULL;
1858 else
1859 lpwcx->hInstance = hInstance;
1860
1861 /* FIXME - return the string? Okay! This is performed in User32!*/
1862 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1863
1864 lpwcx->hIconSm = Class->hIconSm; /* FIXME - get handle from pointer */
1865
1866 return TRUE;
1867 }
1868
1869 //
1870 //
1871 //
1872 BOOL
1873 FASTCALL
1874 UserRegisterSystemClasses(VOID)
1875 {
1876 UINT i;
1877 UNICODE_STRING ClassName, MenuName;
1878 PPROCESSINFO ppi = GetW32ProcessInfo();
1879 WNDCLASSEXW wc;
1880 PCLS Class;
1881 BOOL Ret = TRUE;
1882 DWORD Flags = 0;
1883
1884 if (ppi->W32PF_flags & W32PF_CLASSESREGISTERED)
1885 return TRUE;
1886
1887 if ( hModClient == NULL)
1888 return FALSE;
1889
1890 RtlZeroMemory(&ClassName, sizeof(ClassName));
1891 RtlZeroMemory(&MenuName, sizeof(MenuName));
1892
1893 for (i = 0; i != ARRAYSIZE(DefaultServerClasses); i++)
1894 {
1895 if (!IS_ATOM(DefaultServerClasses[i].ClassName))
1896 {
1897 RtlInitUnicodeString(&ClassName, DefaultServerClasses[i].ClassName);
1898 }
1899 else
1900 {
1901 ClassName.Buffer = DefaultServerClasses[i].ClassName;
1902 ClassName.Length = 0;
1903 ClassName.MaximumLength = 0;
1904 }
1905
1906 wc.cbSize = sizeof(wc);
1907 wc.style = DefaultServerClasses[i].Style;
1908
1909 Flags |= CSF_SERVERSIDEPROC;
1910
1911 if (DefaultServerClasses[i].ProcW)
1912 {
1913 wc.lpfnWndProc = DefaultServerClasses[i].ProcW;
1914 wc.hInstance = hModuleWin;
1915 }
1916 else
1917 {
1918 wc.lpfnWndProc = GETPFNSERVER(DefaultServerClasses[i].fiId);
1919 wc.hInstance = hModClient;
1920 }
1921
1922 wc.cbClsExtra = 0;
1923 wc.cbWndExtra = DefaultServerClasses[i].ExtraBytes;
1924 wc.hIcon = NULL;
1925 wc.hCursor = DefaultServerClasses[i].hCursor;
1926 wc.hbrBackground = DefaultServerClasses[i].hBrush;
1927 wc.lpszMenuName = NULL;
1928 wc.lpszClassName = ClassName.Buffer;
1929 wc.hIconSm = NULL;
1930
1931 Class = IntCreateClass( &wc,
1932 &ClassName,
1933 &MenuName,
1934 DefaultServerClasses[i].fiId,
1935 Flags,
1936 NULL,
1937 ppi);
1938 if (Class != NULL)
1939 {
1940 Class->pclsNext = ppi->pclsPublicList;
1941 (void)InterlockedExchangePointer((PVOID*)&ppi->pclsPublicList,
1942 Class);
1943
1944 ppi->dwRegisteredClasses |= ICLASS_TO_MASK(DefaultServerClasses[i].iCls);
1945 }
1946 else
1947 {
1948 ERR("!!! Registering system class failed!\n");
1949 Ret = FALSE;
1950 }
1951 }
1952 if (Ret) ppi->W32PF_flags |= W32PF_CLASSESREGISTERED;
1953 return Ret;
1954 }
1955
1956 /* SYSCALLS *****************************************************************/
1957
1958 RTL_ATOM
1959 APIENTRY
1960 NtUserRegisterClassExWOW(
1961 WNDCLASSEXW* lpwcx,
1962 PUNICODE_STRING ClassName,
1963 PUNICODE_STRING ClsNVersion,
1964 PCLSMENUNAME pClassMenuName,
1965 DWORD fnID,
1966 DWORD Flags,
1967 LPDWORD pWow)
1968 /*
1969 * FUNCTION:
1970 * Registers a new class with the window manager
1971 * ARGUMENTS:
1972 * lpwcx = Win32 extended window class structure
1973 * bUnicodeClass = Whether to send ANSI or unicode strings
1974 * to window procedures
1975 * RETURNS:
1976 * Atom identifying the new class
1977 */
1978 {
1979 WNDCLASSEXW CapturedClassInfo = {0};
1980 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
1981 RTL_ATOM Ret = (RTL_ATOM)0;
1982 PPROCESSINFO ppi = GetW32ProcessInfo();
1983
1984 if (Flags & ~(CSF_ANSIPROC))
1985 {
1986 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
1987 EngSetLastError(ERROR_INVALID_FLAGS);
1988 return Ret;
1989 }
1990
1991 UserEnterExclusive();
1992
1993 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName);
1994
1995 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1996 {
1997 UserRegisterSystemClasses();
1998 }
1999
2000 _SEH2_TRY
2001 {
2002 /* Probe the parameters and basic parameter checks */
2003 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2004 {
2005 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2006 goto InvalidParameter;
2007 }
2008
2009 ProbeForRead(lpwcx,
2010 sizeof(WNDCLASSEXW),
2011 sizeof(ULONG));
2012 RtlCopyMemory(&CapturedClassInfo,
2013 lpwcx,
2014 sizeof(WNDCLASSEXW));
2015
2016 CapturedName = ProbeForReadUnicodeString(ClassName);
2017
2018 ProbeForRead(pClassMenuName,
2019 sizeof(CLSMENUNAME),
2020 1);
2021
2022 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName);
2023
2024 if ( CapturedName.Length & 1 ||
2025 CapturedMenuName.Length & 1 ||
2026 CapturedClassInfo.cbClsExtra < 0 ||
2027 CapturedClassInfo.cbClsExtra +
2028 CapturedName.Length +
2029 CapturedMenuName.Length +
2030 sizeof(CLS) < CapturedClassInfo.cbClsExtra ||
2031 CapturedClassInfo.cbWndExtra < 0 ||
2032 CapturedClassInfo.hInstance == NULL)
2033 {
2034 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2035 goto InvalidParameter;
2036 }
2037
2038 if (CapturedName.Length != 0)
2039 {
2040 ProbeForRead(CapturedName.Buffer,
2041 CapturedName.Length,
2042 sizeof(WCHAR));
2043 }
2044 else
2045 {
2046 if (!IS_ATOM(CapturedName.Buffer))
2047 {
2048 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2049 goto InvalidParameter;
2050 }
2051 }
2052
2053 if (CapturedMenuName.Length != 0)
2054 {
2055 ProbeForRead(CapturedMenuName.Buffer,
2056 CapturedMenuName.Length,
2057 sizeof(WCHAR));
2058 }
2059 else if (CapturedMenuName.Buffer != NULL &&
2060 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2061 {
2062 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2063 InvalidParameter:
2064 EngSetLastError(ERROR_INVALID_PARAMETER);
2065 _SEH2_LEAVE;
2066 }
2067
2068 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2069 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2070 // If this pops up we know what todo!
2071 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2072 }
2073
2074 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2075
2076 /* Register the class */
2077 Ret = UserRegisterClass(&CapturedClassInfo,
2078 &CapturedName,
2079 &CapturedMenuName,
2080 fnID,
2081 Flags);
2082 }
2083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2084 {
2085 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2086 SetLastNtError(_SEH2_GetExceptionCode());
2087 }
2088 _SEH2_END;
2089 /*
2090 if (!Ret)
2091 {
2092 ERR("NtUserRegisterClassExWOW Null Return!\n");
2093 }
2094 */
2095 UserLeave();
2096
2097 return Ret;
2098 }
2099
2100 ULONG_PTR APIENTRY
2101 NtUserSetClassLong(HWND hWnd,
2102 INT Offset,
2103 ULONG_PTR dwNewLong,
2104 BOOL Ansi)
2105 {
2106 PPROCESSINFO pi;
2107 PWND Window;
2108 ULONG_PTR Ret = 0;
2109
2110 UserEnterExclusive();
2111
2112 pi = GetW32ProcessInfo();
2113
2114 Window = UserGetWindowObject(hWnd);
2115 if (Window != NULL)
2116 {
2117 if (Window->head.pti->ppi != pi)
2118 {
2119 EngSetLastError(ERROR_ACCESS_DENIED);
2120 goto Cleanup;
2121 }
2122
2123 _SEH2_TRY
2124 {
2125 UNICODE_STRING Value;
2126
2127 /* probe the parameters */
2128 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2129 {
2130 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2131 if (Value.Length & 1)
2132 {
2133 goto InvalidParameter;
2134 }
2135
2136 if (Value.Length != 0)
2137 {
2138 ProbeForRead(Value.Buffer,
2139 Value.Length,
2140 sizeof(WCHAR));
2141 }
2142 else
2143 {
2144 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2145 {
2146 goto InvalidParameter;
2147 }
2148 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2149 {
2150 InvalidParameter:
2151 EngSetLastError(ERROR_INVALID_PARAMETER);
2152 _SEH2_LEAVE;
2153 }
2154 }
2155
2156 dwNewLong = (ULONG_PTR)&Value;
2157 }
2158
2159 Ret = UserSetClassLongPtr(Window->pcls,
2160 Offset,
2161 dwNewLong,
2162 Ansi);
2163 }
2164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2165 {
2166 SetLastNtError(_SEH2_GetExceptionCode());
2167 }
2168 _SEH2_END;
2169 }
2170
2171 Cleanup:
2172 UserLeave();
2173
2174 return Ret;
2175 }
2176
2177 WORD
2178 APIENTRY
2179 NtUserSetClassWord(
2180 HWND hWnd,
2181 INT nIndex,
2182 WORD wNewWord)
2183 {
2184 /*
2185 * NOTE: Obsoleted in 32-bit windows
2186 */
2187 return(0);
2188 }
2189
2190 BOOL APIENTRY
2191 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2192 IN HINSTANCE hInstance,
2193 OUT PCLSMENUNAME pClassMenuName)
2194 {
2195 UNICODE_STRING CapturedClassName;
2196 BOOL Ret = FALSE;
2197
2198 UserEnterExclusive();
2199
2200 _SEH2_TRY
2201 {
2202 /* probe the paramters */
2203 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2204 if (CapturedClassName.Length & 1)
2205 {
2206 goto InvalidParameter;
2207 }
2208
2209 if (CapturedClassName.Length != 0)
2210 {
2211 ProbeForRead(CapturedClassName.Buffer,
2212 CapturedClassName.Length,
2213 sizeof(WCHAR));
2214 }
2215 else
2216 {
2217 if (!IS_ATOM(CapturedClassName.Buffer))
2218 {
2219 InvalidParameter:
2220 EngSetLastError(ERROR_INVALID_PARAMETER);
2221 _SEH2_LEAVE;
2222 }
2223 }
2224
2225 /* unregister the class */
2226 Ret = UserUnregisterClass(&CapturedClassName,
2227 hInstance,
2228 NULL); // Null for now~
2229 }
2230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2231 {
2232 SetLastNtError(_SEH2_GetExceptionCode());
2233 }
2234 _SEH2_END;
2235
2236 UserLeave();
2237 return Ret;
2238 }
2239
2240 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2241 BOOL APIENTRY
2242 NtUserGetClassInfo(
2243 HINSTANCE hInstance,
2244 PUNICODE_STRING ClassName,
2245 LPWNDCLASSEXW lpWndClassEx,
2246 LPWSTR *ppszMenuName,
2247 BOOL Ansi)
2248 {
2249 UNICODE_STRING CapturedClassName, SafeClassName;
2250 WNDCLASSEXW Safewcexw;
2251 PCLS Class;
2252 RTL_ATOM ClassAtom = 0;
2253 PPROCESSINFO ppi;
2254 BOOL Ret = TRUE;
2255
2256 /* NOTE: need exclusive lock because getting the wndproc might require the
2257 creation of a call procedure handle */
2258 UserEnterExclusive();
2259
2260 ppi = GetW32ProcessInfo();
2261
2262 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2263 {
2264 UserRegisterSystemClasses();
2265 }
2266
2267 _SEH2_TRY
2268 {
2269 /* probe the paramters */
2270 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2271
2272 if (CapturedClassName.Length == 0)
2273 {
2274 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2275 }
2276 else
2277 {
2278 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2279 }
2280
2281 if (CapturedClassName.Length & 1)
2282 {
2283 EngSetLastError(ERROR_INVALID_PARAMETER);
2284 Ret = FALSE;
2285 _SEH2_LEAVE;
2286 }
2287
2288 if (CapturedClassName.Length != 0)
2289 {
2290 ProbeForRead( CapturedClassName.Buffer,
2291 CapturedClassName.Length,
2292 sizeof(WCHAR));
2293
2294 RtlInitUnicodeString( &SafeClassName, CapturedClassName.Buffer);
2295
2296 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2297 SafeClassName.MaximumLength,
2298 TAG_STRING);
2299 RtlCopyMemory( SafeClassName.Buffer,
2300 CapturedClassName.Buffer,
2301 SafeClassName.MaximumLength);
2302 }
2303 else
2304 {
2305 if (!IS_ATOM(CapturedClassName.Buffer))
2306 {
2307 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2308 EngSetLastError(ERROR_INVALID_PARAMETER);
2309 Ret = FALSE;
2310 _SEH2_LEAVE;
2311 }
2312
2313 SafeClassName.Buffer = CapturedClassName.Buffer;
2314 SafeClassName.Length = 0;
2315 SafeClassName.MaximumLength = 0;
2316 }
2317
2318 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2319
2320 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2321 }
2322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2323 {
2324 SetLastNtError(_SEH2_GetExceptionCode());
2325 Ret = FALSE;
2326 }
2327 _SEH2_END;
2328
2329 // If null instance use client.
2330 if (!hInstance) hInstance = hModClient;
2331
2332 if (Ret)
2333 {
2334 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
2335 ClassAtom = IntGetClassAtom( &SafeClassName,
2336 hInstance,
2337 ppi,
2338 &Class,
2339 NULL);
2340 if (ClassAtom != (RTL_ATOM)0)
2341 {
2342 if (hInstance == NULL) hInstance = hModClient;
2343
2344 Ret = UserGetClassInfo( Class,
2345 &Safewcexw,
2346 Ansi,
2347 hInstance);
2348 }
2349 else
2350 {
2351 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2352 Ret = FALSE;
2353 }
2354 }
2355 _SEH2_TRY
2356 {
2357 if (Ret)
2358 {
2359 /* Emulate Function. */
2360 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2361
2362 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2363
2364 // From Wine:
2365 /* We must return the atom of the class here instead of just TRUE. */
2366 /* Undocumented behavior! Return the class atom as a BOOL! */
2367 Ret = (BOOL)ClassAtom;
2368 }
2369 }
2370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2371 {
2372 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2373 Ret = FALSE;
2374 }
2375 _SEH2_END;
2376
2377 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2378 UserLeave();
2379 return Ret;
2380 }
2381
2382
2383 INT APIENTRY
2384 NtUserGetClassName (IN HWND hWnd,
2385 IN BOOL Real,
2386 OUT PUNICODE_STRING ClassName)
2387 {
2388 PWND Window;
2389 UNICODE_STRING CapturedClassName;
2390 INT iCls, Ret = 0;
2391 RTL_ATOM Atom = 0;
2392
2393 UserEnterShared();
2394
2395 Window = UserGetWindowObject(hWnd);
2396 if (Window != NULL)
2397 {
2398 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY))
2399 {
2400 if (LookupFnIdToiCls(Window->fnid, &iCls))
2401 {
2402 Atom = gpsi->atomSysClass[iCls];
2403 }
2404 }
2405
2406 _SEH2_TRY
2407 {
2408 ProbeForWriteUnicodeString(ClassName);
2409 CapturedClassName = *ClassName;
2410
2411 /* get the class name */
2412 Ret = UserGetClassName(Window->pcls,
2413 &CapturedClassName,
2414 Atom,
2415 FALSE);
2416
2417 if (Ret != 0)
2418 {
2419 /* update the Length field */
2420 ClassName->Length = CapturedClassName.Length;
2421 }
2422 }
2423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2424 {
2425 SetLastNtError(_SEH2_GetExceptionCode());
2426 }
2427 _SEH2_END;
2428 }
2429
2430 UserLeave();
2431
2432 return Ret;
2433 }
2434
2435 /* Return Pointer to Class structure. */
2436 PCLS APIENTRY
2437 NtUserGetWOWClass(HINSTANCE hInstance,
2438 PUNICODE_STRING ClassName)
2439 {
2440 UNICODE_STRING SafeClassName;
2441 PPROCESSINFO pi;
2442 PCLS Class = NULL;
2443 RTL_ATOM ClassAtom = 0;
2444 BOOL Hit = FALSE;
2445
2446 UserEnterExclusive();
2447
2448 pi = GetW32ProcessInfo();
2449
2450 _SEH2_TRY
2451 {
2452 if (ClassName->Length != 0)
2453 {
2454 ProbeForRead( ClassName->Buffer,
2455 ClassName->Length,
2456 sizeof(WCHAR));
2457
2458 RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
2459
2460 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2461 SafeClassName.MaximumLength,
2462 TAG_STRING);
2463 RtlCopyMemory( SafeClassName.Buffer,
2464 ClassName->Buffer,
2465 SafeClassName.MaximumLength);
2466 }
2467 else
2468 {
2469 if (!IS_ATOM(ClassName->Buffer))
2470 {
2471 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2472 Hit = TRUE;
2473 }
2474 else
2475 {
2476 SafeClassName.Buffer = ClassName->Buffer;
2477 SafeClassName.Length = 0;
2478 SafeClassName.MaximumLength = 0;
2479 }
2480 }
2481 }
2482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2483 {
2484 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2485 Hit = TRUE;
2486 }
2487 _SEH2_END;
2488
2489 if (!Hit)
2490 {
2491 ClassAtom = IntGetClassAtom( &SafeClassName,
2492 hInstance,
2493 pi,
2494 &Class,
2495 NULL);
2496 if (!ClassAtom)
2497 {
2498 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2499 }
2500 }
2501
2502 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2503 UserLeave();
2504 //
2505 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2506 //
2507 return Class;
2508 }
2509
2510 /* EOF */