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