* Reorganize the whole ReactOS codebase into a new layout. Discussing it will only...
[reactos.git] / reactos / win32ss / user / 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 = (USHORT)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 = (USHORT)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 (((ULONG)Index + sizeof(ULONG_PTR)) < (ULONG)Index ||
1638 ((ULONG)Index + sizeof(ULONG_PTR)) > (ULONG)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 + CapturedName.Length +
2023 CapturedMenuName.Length + sizeof(CLS))
2024 < (ULONG)CapturedClassInfo.cbClsExtra) ||
2025 (CapturedClassInfo.cbWndExtra < 0) ||
2026 (CapturedClassInfo.hInstance == NULL) )
2027 {
2028 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2029 goto InvalidParameter;
2030 }
2031
2032 if (CapturedName.Length != 0)
2033 {
2034 ProbeForRead(CapturedName.Buffer,
2035 CapturedName.Length,
2036 sizeof(WCHAR));
2037 }
2038 else
2039 {
2040 if (!IS_ATOM(CapturedName.Buffer))
2041 {
2042 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2043 goto InvalidParameter;
2044 }
2045 }
2046
2047 if (CapturedMenuName.Length != 0)
2048 {
2049 ProbeForRead(CapturedMenuName.Buffer,
2050 CapturedMenuName.Length,
2051 sizeof(WCHAR));
2052 }
2053 else if (CapturedMenuName.Buffer != NULL &&
2054 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2055 {
2056 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2057 InvalidParameter:
2058 EngSetLastError(ERROR_INVALID_PARAMETER);
2059 _SEH2_LEAVE;
2060 }
2061
2062 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2063 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2064 // If this pops up we know what todo!
2065 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2066 }
2067
2068 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2069
2070 /* Register the class */
2071 Ret = UserRegisterClass(&CapturedClassInfo,
2072 &CapturedName,
2073 &CapturedMenuName,
2074 fnID,
2075 Flags);
2076 }
2077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2078 {
2079 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2080 SetLastNtError(_SEH2_GetExceptionCode());
2081 }
2082 _SEH2_END;
2083 /*
2084 if (!Ret)
2085 {
2086 ERR("NtUserRegisterClassExWOW Null Return!\n");
2087 }
2088 */
2089 UserLeave();
2090
2091 return Ret;
2092 }
2093
2094 ULONG_PTR APIENTRY
2095 NtUserSetClassLong(HWND hWnd,
2096 INT Offset,
2097 ULONG_PTR dwNewLong,
2098 BOOL Ansi)
2099 {
2100 PPROCESSINFO pi;
2101 PWND Window;
2102 ULONG_PTR Ret = 0;
2103
2104 UserEnterExclusive();
2105
2106 pi = GetW32ProcessInfo();
2107
2108 Window = UserGetWindowObject(hWnd);
2109 if (Window != NULL)
2110 {
2111 if (Window->head.pti->ppi != pi)
2112 {
2113 EngSetLastError(ERROR_ACCESS_DENIED);
2114 goto Cleanup;
2115 }
2116
2117 _SEH2_TRY
2118 {
2119 UNICODE_STRING Value;
2120
2121 /* Probe the parameters */
2122 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2123 {
2124 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2125 if (Value.Length & 1)
2126 {
2127 goto InvalidParameter;
2128 }
2129
2130 if (Value.Length != 0)
2131 {
2132 ProbeForRead(Value.Buffer,
2133 Value.Length,
2134 sizeof(WCHAR));
2135 }
2136 else
2137 {
2138 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2139 {
2140 goto InvalidParameter;
2141 }
2142 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2143 {
2144 InvalidParameter:
2145 EngSetLastError(ERROR_INVALID_PARAMETER);
2146 _SEH2_LEAVE;
2147 }
2148 }
2149
2150 dwNewLong = (ULONG_PTR)&Value;
2151 }
2152
2153 Ret = UserSetClassLongPtr(Window->pcls,
2154 Offset,
2155 dwNewLong,
2156 Ansi);
2157 }
2158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2159 {
2160 SetLastNtError(_SEH2_GetExceptionCode());
2161 }
2162 _SEH2_END;
2163 }
2164
2165 Cleanup:
2166 UserLeave();
2167
2168 return Ret;
2169 }
2170
2171 WORD
2172 APIENTRY
2173 NtUserSetClassWord(
2174 HWND hWnd,
2175 INT nIndex,
2176 WORD wNewWord)
2177 {
2178 /*
2179 * NOTE: Obsoleted in 32-bit windows
2180 */
2181 return(0);
2182 }
2183
2184 BOOL APIENTRY
2185 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2186 IN HINSTANCE hInstance,
2187 OUT PCLSMENUNAME pClassMenuName)
2188 {
2189 UNICODE_STRING CapturedClassName;
2190 BOOL Ret = FALSE;
2191
2192 UserEnterExclusive();
2193
2194 _SEH2_TRY
2195 {
2196 /* Probe the paramters */
2197 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2198 if (CapturedClassName.Length & 1)
2199 {
2200 goto InvalidParameter;
2201 }
2202
2203 if (CapturedClassName.Length != 0)
2204 {
2205 ProbeForRead(CapturedClassName.Buffer,
2206 CapturedClassName.Length,
2207 sizeof(WCHAR));
2208 }
2209 else
2210 {
2211 if (!IS_ATOM(CapturedClassName.Buffer))
2212 {
2213 InvalidParameter:
2214 EngSetLastError(ERROR_INVALID_PARAMETER);
2215 _SEH2_LEAVE;
2216 }
2217 }
2218
2219 /* Unregister the class */
2220 Ret = UserUnregisterClass(&CapturedClassName,
2221 hInstance,
2222 NULL); // Null for now~
2223 }
2224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2225 {
2226 SetLastNtError(_SEH2_GetExceptionCode());
2227 }
2228 _SEH2_END;
2229
2230 UserLeave();
2231 return Ret;
2232 }
2233
2234 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2235 BOOL APIENTRY
2236 NtUserGetClassInfo(
2237 HINSTANCE hInstance,
2238 PUNICODE_STRING ClassName,
2239 LPWNDCLASSEXW lpWndClassEx,
2240 LPWSTR *ppszMenuName,
2241 BOOL Ansi)
2242 {
2243 UNICODE_STRING CapturedClassName, SafeClassName;
2244 WNDCLASSEXW Safewcexw;
2245 PCLS Class;
2246 RTL_ATOM ClassAtom = 0;
2247 PPROCESSINFO ppi;
2248 BOOL Ret = TRUE;
2249
2250 /* NOTE: Need exclusive lock because getting the wndproc might require the
2251 creation of a call procedure handle */
2252 UserEnterExclusive();
2253
2254 ppi = GetW32ProcessInfo();
2255
2256 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2257 {
2258 UserRegisterSystemClasses();
2259 }
2260
2261 _SEH2_TRY
2262 {
2263 /* Probe the paramters */
2264 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2265
2266 if (CapturedClassName.Length == 0)
2267 {
2268 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2269 }
2270 else
2271 {
2272 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2273 }
2274
2275 if (CapturedClassName.Length & 1)
2276 {
2277 EngSetLastError(ERROR_INVALID_PARAMETER);
2278 Ret = FALSE;
2279 _SEH2_LEAVE;
2280 }
2281
2282 if (CapturedClassName.Length != 0)
2283 {
2284 ProbeForRead( CapturedClassName.Buffer,
2285 CapturedClassName.Length,
2286 sizeof(WCHAR));
2287
2288 RtlInitUnicodeString( &SafeClassName, CapturedClassName.Buffer);
2289
2290 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2291 SafeClassName.MaximumLength,
2292 TAG_STRING);
2293 RtlCopyMemory( SafeClassName.Buffer,
2294 CapturedClassName.Buffer,
2295 SafeClassName.MaximumLength);
2296 }
2297 else
2298 {
2299 if (!IS_ATOM(CapturedClassName.Buffer))
2300 {
2301 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2302 EngSetLastError(ERROR_INVALID_PARAMETER);
2303 Ret = FALSE;
2304 _SEH2_LEAVE;
2305 }
2306
2307 SafeClassName.Buffer = CapturedClassName.Buffer;
2308 SafeClassName.Length = 0;
2309 SafeClassName.MaximumLength = 0;
2310 }
2311
2312 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2313
2314 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2315 }
2316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2317 {
2318 SetLastNtError(_SEH2_GetExceptionCode());
2319 Ret = FALSE;
2320 }
2321 _SEH2_END;
2322
2323 // If null instance use client.
2324 if (!hInstance) hInstance = hModClient;
2325
2326 if (Ret)
2327 {
2328 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
2329 ClassAtom = IntGetClassAtom( &SafeClassName,
2330 hInstance,
2331 ppi,
2332 &Class,
2333 NULL);
2334 if (ClassAtom != (RTL_ATOM)0)
2335 {
2336 if (hInstance == NULL) hInstance = hModClient;
2337
2338 Ret = UserGetClassInfo( Class,
2339 &Safewcexw,
2340 Ansi,
2341 hInstance);
2342 }
2343 else
2344 {
2345 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2346 Ret = FALSE;
2347 }
2348 }
2349 _SEH2_TRY
2350 {
2351 if (Ret)
2352 {
2353 /* Emulate Function. */
2354 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2355
2356 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2357
2358 // From Wine:
2359 /* We must return the atom of the class here instead of just TRUE. */
2360 /* Undocumented behavior! Return the class atom as a BOOL! */
2361 Ret = (BOOL)ClassAtom;
2362 }
2363 }
2364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2365 {
2366 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2367 Ret = FALSE;
2368 }
2369 _SEH2_END;
2370
2371 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2372 UserLeave();
2373 return Ret;
2374 }
2375
2376
2377 INT APIENTRY
2378 NtUserGetClassName (IN HWND hWnd,
2379 IN BOOL Real,
2380 OUT PUNICODE_STRING ClassName)
2381 {
2382 PWND Window;
2383 UNICODE_STRING CapturedClassName;
2384 INT iCls, Ret = 0;
2385 RTL_ATOM Atom = 0;
2386
2387 UserEnterShared();
2388
2389 Window = UserGetWindowObject(hWnd);
2390 if (Window != NULL)
2391 {
2392 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY))
2393 {
2394 if (LookupFnIdToiCls(Window->fnid, &iCls))
2395 {
2396 Atom = gpsi->atomSysClass[iCls];
2397 }
2398 }
2399
2400 _SEH2_TRY
2401 {
2402 ProbeForWriteUnicodeString(ClassName);
2403 CapturedClassName = *ClassName;
2404
2405 /* Get the class name */
2406 Ret = UserGetClassName(Window->pcls,
2407 &CapturedClassName,
2408 Atom,
2409 FALSE);
2410
2411 if (Ret != 0)
2412 {
2413 /* Update the Length field */
2414 ClassName->Length = CapturedClassName.Length;
2415 }
2416 }
2417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2418 {
2419 SetLastNtError(_SEH2_GetExceptionCode());
2420 }
2421 _SEH2_END;
2422 }
2423
2424 UserLeave();
2425
2426 return Ret;
2427 }
2428
2429 /* Return Pointer to Class structure. */
2430 PCLS APIENTRY
2431 NtUserGetWOWClass(HINSTANCE hInstance,
2432 PUNICODE_STRING ClassName)
2433 {
2434 UNICODE_STRING SafeClassName;
2435 PPROCESSINFO pi;
2436 PCLS Class = NULL;
2437 RTL_ATOM ClassAtom = 0;
2438 BOOL Hit = FALSE;
2439
2440 UserEnterExclusive();
2441
2442 pi = GetW32ProcessInfo();
2443
2444 _SEH2_TRY
2445 {
2446 if (ClassName->Length != 0)
2447 {
2448 ProbeForRead( ClassName->Buffer,
2449 ClassName->Length,
2450 sizeof(WCHAR));
2451
2452 RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
2453
2454 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2455 SafeClassName.MaximumLength,
2456 TAG_STRING);
2457 RtlCopyMemory( SafeClassName.Buffer,
2458 ClassName->Buffer,
2459 SafeClassName.MaximumLength);
2460 }
2461 else
2462 {
2463 if (!IS_ATOM(ClassName->Buffer))
2464 {
2465 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2466 Hit = TRUE;
2467 }
2468 else
2469 {
2470 SafeClassName.Buffer = ClassName->Buffer;
2471 SafeClassName.Length = 0;
2472 SafeClassName.MaximumLength = 0;
2473 }
2474 }
2475 }
2476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2477 {
2478 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2479 Hit = TRUE;
2480 }
2481 _SEH2_END;
2482
2483 if (!Hit)
2484 {
2485 ClassAtom = IntGetClassAtom( &SafeClassName,
2486 hInstance,
2487 pi,
2488 &Class,
2489 NULL);
2490 if (!ClassAtom)
2491 {
2492 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2493 }
2494 }
2495
2496 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2497 UserLeave();
2498 //
2499 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2500 //
2501 return Class;
2502 }
2503
2504 /* EOF */