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