- [Win32k] If Proc is null, use original one and perform processing.
[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 <w32k.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,
512 BaseClass,
513 ClassSize);
514 DPRINT("Clone Class 0x%x hM 0x%x\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
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(&BaseClass->pclsClone,
547 Class);
548 }
549 }
550 else
551 {
552 SetLastWin32Error(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, BaseClass;
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 BaseClass = Class->pclsBase;
597
598 /* update the class information to make it a base class */
599 Class->pclsBase = Class;
600 Class->pclsNext = (*BaseClassLink)->pclsNext;
601
602 /* update all clones */
603 Clone = Class->pclsClone;
604 while (Clone != NULL)
605 {
606 ASSERT(Clone->pclsClone == NULL);
607 Clone->pclsBase = Class;
608
609 Clone = Clone->pclsNext;
610 }
611
612 /* link in the new base class */
613 (void)InterlockedExchangePointer((PVOID*)BaseClassLink,
614 Class);
615 }
616
617
618 VOID
619 IntDereferenceClass(IN OUT PCLS Class,
620 IN PDESKTOPINFO Desktop,
621 IN PPROCESSINFO pi)
622 {
623 PCLS *PrevLink, BaseClass, CurrentClass;
624
625 BaseClass = Class->pclsBase;
626
627 if (--Class->cWndReferenceCount <= 0)
628 {
629 if (BaseClass == Class)
630 {
631 ASSERT(Class->pclsBase == Class);
632
633 DPRINT("IntDereferenceClass 0x%x\n", Class);
634 /* check if there are clones of the class on other desktops,
635 link the first clone in if possible. If there are no clones
636 then leave the class on the desktop heap. It will get moved
637 to the shared heap when the thread detaches. */
638 if (BaseClass->pclsClone != NULL)
639 {
640 if (BaseClass->Global)
641 PrevLink = &pi->pclsPublicList;
642 else
643 PrevLink = &pi->pclsPrivateList;
644
645 CurrentClass = *PrevLink;
646 while (CurrentClass != BaseClass)
647 {
648 ASSERT(CurrentClass != NULL);
649
650 PrevLink = &CurrentClass->pclsNext;
651 CurrentClass = CurrentClass->pclsNext;
652 }
653
654 ASSERT(*PrevLink == BaseClass);
655
656 /* make the first clone become the new base class */
657 IntMakeCloneBaseClass(BaseClass->pclsClone,
658 PrevLink,
659 &BaseClass->pclsClone);
660
661 /* destroy the class, there's still another clone of the class
662 that now serves as a base class. Make sure we don't destruct
663 resources shared by all classes (Base = NULL)! */
664 BaseClass->pclsBase = NULL;
665 BaseClass->pclsClone = NULL;
666 IntDestroyClass(BaseClass);
667 }
668 }
669 else
670 {
671 DPRINT("IntDereferenceClass1 0x%x\n", Class);
672
673 /* locate the cloned class and unlink it */
674 PrevLink = &BaseClass->pclsClone;
675 CurrentClass = BaseClass->pclsClone;
676 while (CurrentClass != Class)
677 {
678 ASSERT(CurrentClass != NULL);
679
680 PrevLink = &CurrentClass->pclsNext;
681 CurrentClass = CurrentClass->pclsNext;
682 }
683
684 ASSERT(CurrentClass == Class);
685
686 (void)InterlockedExchangePointer((PVOID*)PrevLink,
687 Class->pclsNext);
688
689 ASSERT(Class->pclsBase == BaseClass);
690 ASSERT(Class->pclsClone == NULL);
691
692 /* the class was just a clone, we don't need it anymore */
693 IntDestroyClass(Class);
694 }
695 }
696 }
697
698 static BOOL
699 IntMoveClassToSharedHeap(IN OUT PCLS Class,
700 IN OUT PCLS **ClassLinkPtr)
701 {
702 PCLS NewClass;
703 SIZE_T ClassSize;
704
705 ASSERT(Class->pclsBase == Class);
706 ASSERT(Class->rpdeskParent != NULL);
707 ASSERT(Class->cWndReferenceCount == 0);
708 ASSERT(Class->pclsClone == NULL);
709
710 ClassSize = sizeof(*Class) + (SIZE_T)Class->cbclsExtra;
711
712 /* allocate the new base class on the shared heap */
713 NewClass = UserHeapAlloc(ClassSize);
714 if (NewClass != NULL)
715 {
716 RtlCopyMemory(NewClass,
717 Class,
718 ClassSize);
719
720 NewClass->rpdeskParent = NULL;
721 NewClass->pclsBase = NewClass;
722
723 /* replace the class in the list */
724 (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
725 NewClass);
726 *ClassLinkPtr = &NewClass->pclsNext;
727
728 /* free the obsolete class on the desktop heap */
729 Class->pclsBase = NULL;
730 IntDestroyClass(Class);
731 return TRUE;
732 }
733
734 return FALSE;
735 }
736
737 static VOID
738 IntCheckDesktopClasses(IN PDESKTOP Desktop,
739 IN OUT PCLS *ClassList,
740 IN BOOL FreeOnFailure,
741 OUT BOOL *Ret)
742 {
743 PCLS Class, NextClass, *Link;
744
745 /* NOTE: We only need to check base classes! When classes are no longer needed
746 on a desktop, the clones will be freed automatically as soon as possible.
747 However, we need to move base classes to the shared heap, as soon as
748 the last desktop heap where a class is allocated on is about to be destroyed.
749 If we didn't move the class to the shared heap, the class would become
750 inaccessible! */
751
752 ASSERT(Desktop != NULL);
753
754 Link = ClassList;
755 Class = *Link;
756 while (Class != NULL)
757 {
758 NextClass = Class->pclsNext;
759
760 ASSERT(Class->pclsBase == Class);
761
762 if (Class->rpdeskParent == Desktop &&
763 Class->cWndReferenceCount == 0)
764 {
765 /* there shouldn't be any clones around anymore! */
766 ASSERT(Class->pclsClone == NULL);
767
768 /* FIXME - If process is terminating, don't move the class but rather destroy it! */
769 /* FIXME - We could move the class to another desktop heap if there's still desktops
770 mapped into the process... */
771
772 /* move the class to the shared heap */
773 if (IntMoveClassToSharedHeap(Class,
774 &Link))
775 {
776 ASSERT(*Link == NextClass);
777 }
778 else
779 {
780 ASSERT(NextClass == Class->pclsNext);
781
782 if (FreeOnFailure)
783 {
784 /* unlink the base class */
785 (void)InterlockedExchangePointer((PVOID*)Link,
786 Class->pclsNext);
787
788 /* we can free the old base class now */
789 Class->pclsBase = NULL;
790 IntDestroyClass(Class);
791 }
792 else
793 {
794 Link = &Class->pclsNext;
795 *Ret = FALSE;
796 }
797 }
798 }
799 else
800 Link = &Class->pclsNext;
801
802 Class = NextClass;
803 }
804 }
805
806 BOOL
807 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
808 IN BOOL FreeOnFailure)
809 {
810 PPROCESSINFO pi;
811 BOOL Ret = TRUE;
812
813 pi = GetW32ProcessInfo();
814
815 /* check all local classes */
816 IntCheckDesktopClasses(Desktop,
817 &pi->pclsPrivateList,
818 FreeOnFailure,
819 &Ret);
820
821 /* check all global classes */
822 IntCheckDesktopClasses(Desktop,
823 &pi->pclsPublicList,
824 FreeOnFailure,
825 &Ret);
826 if (!Ret)
827 {
828 DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
829 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
830 }
831
832 return Ret;
833 }
834
835 PCLS
836 FASTCALL
837 IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
838 IN PUNICODE_STRING ClassName,
839 IN PUNICODE_STRING MenuName,
840 IN DWORD fnID,
841 IN DWORD dwFlags,
842 IN PDESKTOP Desktop,
843 IN PPROCESSINFO pi)
844 {
845 SIZE_T ClassSize;
846 PCLS Class = NULL;
847 RTL_ATOM Atom;
848 WNDPROC WndProc;
849 PWSTR pszMenuName = NULL;
850 NTSTATUS Status = STATUS_SUCCESS;
851
852 DPRINT("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
853 lpwcx, ClassName, MenuName, dwFlags, Desktop, pi);
854
855 if (!IntRegisterClassAtom(ClassName,
856 &Atom))
857 {
858 DPRINT1("Failed to register class atom!\n");
859 return NULL;
860 }
861
862 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
863 if (MenuName->Length != 0)
864 {
865 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
866 RtlUnicodeStringToAnsiSize(MenuName));
867 if (pszMenuName == NULL)
868 goto NoMem;
869 }
870
871 if (Desktop != NULL)
872 {
873 Class = DesktopHeapAlloc(Desktop,
874 ClassSize);
875 }
876 else
877 {
878 /* FIXME - the class was created before being connected
879 to a desktop. It is possible for the desktop window,
880 but should it be allowed for any other case? */
881 Class = UserHeapAlloc(ClassSize);
882 }
883
884 if (Class != NULL)
885 {
886 int iCls = 0;
887
888 RtlZeroMemory(Class, ClassSize);
889
890 Class->rpdeskParent = Desktop;
891 Class->pclsBase = Class;
892 Class->atomClassName = Atom;
893 Class->fnid = fnID;
894 Class->CSF_flags = dwFlags;
895
896 if (LookupFnIdToiCls(Class->fnid, &iCls))
897 {
898 gpsi->atomSysClass[iCls] = Class->atomClassName;
899 }
900
901 _SEH2_TRY
902 {
903 PWSTR pszMenuNameBuffer = pszMenuName;
904
905 /* need to protect with SEH since accessing the WNDCLASSEX structure
906 and string buffers might raise an exception! We don't want to
907 leak memory... */
908 // What?! If the user interface was written correctly this would not be an issue!
909 Class->lpfnWndProc = lpwcx->lpfnWndProc;
910 Class->style = lpwcx->style;
911 Class->cbclsExtra = lpwcx->cbClsExtra;
912 Class->cbwndExtra = lpwcx->cbWndExtra;
913 Class->hModule = lpwcx->hInstance;
914 Class->hIcon = lpwcx->hIcon; /* FIXME */
915 Class->hIconSm = lpwcx->hIconSm; /* FIXME */
916 Class->hCursor = lpwcx->hCursor; /* FIXME */
917 Class->hbrBackground = lpwcx->hbrBackground;
918
919 /* make a copy of the string */
920 if (pszMenuNameBuffer != NULL)
921 {
922 Class->MenuNameIsString = TRUE;
923
924 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
925 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
926 MenuName->Buffer,
927 MenuName->Length);
928 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
929
930 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
931 }
932 else
933 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
934
935 /* save an ansi copy of the string */
936 if (pszMenuNameBuffer != NULL)
937 {
938 ANSI_STRING AnsiString;
939
940 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
941 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
942 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
943 Status = RtlUnicodeStringToAnsiString(&AnsiString,
944 MenuName,
945 FALSE);
946 if (!NT_SUCCESS(Status))
947 {
948 DPRINT1("Failed to convert unicode menu name to ansi!\n");
949
950 /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
951 _SEH2_LEAVE;
952 }
953 }
954 else
955 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
956
957 /* Save kernel use menu name and ansi class name */
958 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // Fixme!
959 //Class->lpszAnsiClassName = Fixme!
960
961 /* Server Side overrides class calling type (A/W)!
962 User32 whine test_builtinproc: "deftest"
963 built-in winproc - window A/W type automatically detected */
964 if (!(Class->CSF_flags & CSF_SERVERSIDEPROC))
965 {
966 int i;
967 WndProc = NULL;
968 /* Due to the wine class "deftest" and most likely no FNID to reference
969 from, sort through the Server Side list and compare proc addresses
970 for match. This method will be used in related code.
971 */
972 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
973 { // Open Ansi or Unicode, just match, set and break.
974 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
975 {
976 WndProc = GETPFNSERVER(i);
977 break;
978 }
979 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
980 {
981 WndProc = GETPFNSERVER(i);
982 break;
983 }
984 }
985 if (WndProc)
986 { // If a hit, we are Server Side so set the right flags and proc.
987 Class->CSF_flags |= CSF_SERVERSIDEPROC;
988 Class->CSF_flags &= ~CSF_ANSIPROC;
989 Class->lpfnWndProc = WndProc;
990 }
991 }
992
993 if (!(Class->CSF_flags & CSF_ANSIPROC))
994 Class->Unicode = TRUE;
995
996 if (Class->style & CS_GLOBALCLASS)
997 Class->Global = TRUE;
998 }
999 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1000 {
1001 Status = _SEH2_GetExceptionCode();
1002 }
1003 _SEH2_END;
1004
1005 if (!NT_SUCCESS(Status))
1006 {
1007 DPRINT1("Failed creating the class: 0x%x\n", Status);
1008
1009 SetLastNtError(Status);
1010
1011 if (pszMenuName != NULL)
1012 UserHeapFree(pszMenuName);
1013
1014 DesktopHeapFree(Desktop,
1015 Class);
1016 Class = NULL;
1017
1018 IntDeregisterClassAtom(Atom);
1019 }
1020 }
1021 else
1022 {
1023 NoMem:
1024 DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop);
1025
1026 if (pszMenuName != NULL)
1027 UserHeapFree(pszMenuName);
1028
1029 IntDeregisterClassAtom(Atom);
1030
1031 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1032 }
1033
1034 return Class;
1035 }
1036
1037 static PCLS
1038 IntFindClass(IN RTL_ATOM Atom,
1039 IN HINSTANCE hInstance,
1040 IN PCLS *ClassList,
1041 OUT PCLS **Link OPTIONAL)
1042 {
1043 PCLS Class, *PrevLink = ClassList;
1044
1045 Class = *PrevLink;
1046 while (Class != NULL)
1047 {
1048 if (Class->atomClassName == Atom &&
1049 (hInstance == NULL || Class->hModule == hInstance) &&
1050 !(Class->CSF_flags & CSF_WOWDEFERDESTROY))
1051 {
1052 ASSERT(Class->pclsBase == Class);
1053
1054 if (Link != NULL)
1055 *Link = PrevLink;
1056 break;
1057 }
1058
1059 PrevLink = &Class->pclsNext;
1060 Class = Class->pclsNext;
1061 }
1062
1063 return Class;
1064 }
1065
1066 BOOL
1067 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
1068 OUT RTL_ATOM *Atom)
1069 {
1070 BOOL Ret = FALSE;
1071
1072 if (ClassName->Length != 0)
1073 {
1074 WCHAR szBuf[65];
1075 PWSTR AtomName;
1076 NTSTATUS Status;
1077
1078 /* NOTE: Caller has to protect the call with SEH! */
1079
1080 if (ClassName->Length != 0)
1081 {
1082 /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
1083 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
1084 {
1085 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1086 return (RTL_ATOM)0;
1087 }
1088
1089 /* We need to make a local copy of the class name! The caller could
1090 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1091 We're protected by SEH, but the ranges that might be accessed were
1092 not probed... */
1093 RtlCopyMemory(szBuf,
1094 ClassName->Buffer,
1095 ClassName->Length);
1096 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1097 AtomName = szBuf;
1098 }
1099 else
1100 AtomName = ClassName->Buffer;
1101
1102 /* lookup the atom */
1103 Status = RtlLookupAtomInAtomTable(gAtomTable,
1104 AtomName,
1105 Atom);
1106 if (NT_SUCCESS(Status))
1107 {
1108 Ret = TRUE;
1109 }
1110 else
1111 {
1112 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1113 {
1114 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
1115 }
1116 else
1117 {
1118 SetLastNtError(Status);
1119 }
1120 }
1121 }
1122 else
1123 {
1124 ASSERT(IS_ATOM(ClassName->Buffer));
1125 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1126 Ret = TRUE;
1127 }
1128
1129 return Ret;
1130 }
1131
1132 RTL_ATOM
1133 IntGetClassAtom(IN PUNICODE_STRING ClassName,
1134 IN HINSTANCE hInstance OPTIONAL,
1135 IN PPROCESSINFO pi OPTIONAL,
1136 OUT PCLS *BaseClass OPTIONAL,
1137 OUT PCLS **Link OPTIONAL)
1138 {
1139 RTL_ATOM Atom = (RTL_ATOM)0;
1140
1141 ASSERT(BaseClass != NULL);
1142
1143 if (IntGetAtomFromStringOrAtom(ClassName,
1144 &Atom) &&
1145 Atom != (RTL_ATOM)0)
1146 {
1147 PCLS Class;
1148
1149 /* attempt to locate the class object */
1150
1151 ASSERT(pi != NULL);
1152
1153 /* Step 1: try to find an exact match of locally registered classes */
1154 Class = IntFindClass(Atom,
1155 hInstance,
1156 &pi->pclsPrivateList,
1157 Link);
1158 if (Class != NULL)
1159 { DPRINT("Step 1: 0x%x\n",Class );
1160 goto FoundClass;
1161 }
1162
1163 /* Step 2: try to find any globally registered class. The hInstance
1164 is not relevant for global classes */
1165 Class = IntFindClass(Atom,
1166 NULL,
1167 &pi->pclsPublicList,
1168 Link);
1169 if (Class != NULL)
1170 { DPRINT("Step 2: 0x%x 0x%x\n",Class, Class->hModule);
1171 goto FoundClass;
1172 }
1173
1174 /* Step 3: try to find any local class registered by user32 */
1175 Class = IntFindClass(Atom,
1176 hModClient,
1177 &pi->pclsPrivateList,
1178 Link);
1179 if (Class != NULL)
1180 { DPRINT("Step 3: 0x%x\n",Class );
1181 goto FoundClass;
1182 }
1183
1184 /* Step 4: try to find any global class registered by user32 */
1185 Class = IntFindClass(Atom,
1186 hModClient,
1187 &pi->pclsPublicList,
1188 Link);
1189 if (Class == NULL)
1190 {
1191 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
1192 return (RTL_ATOM)0;
1193 }else{DPRINT("Step 4: 0x%x\n",Class );}
1194
1195 FoundClass:
1196 *BaseClass = Class;
1197 }
1198
1199 return Atom;
1200 }
1201
1202 RTL_ATOM
1203 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1204 IN PUNICODE_STRING ClassName,
1205 IN PUNICODE_STRING MenuName,
1206 IN DWORD fnID,
1207 IN DWORD dwFlags)
1208 {
1209 PTHREADINFO pti;
1210 PPROCESSINFO pi;
1211 PCLS Class;
1212 RTL_ATOM ClassAtom;
1213 RTL_ATOM Ret = (RTL_ATOM)0;
1214
1215 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1216
1217 pti = GetW32ThreadInfo();
1218
1219 pi = pti->ppi;
1220
1221 // Need only to test for two conditions not four....... Fix more whine tests....
1222 if ( IntGetAtomFromStringOrAtom( ClassName, &ClassAtom) &&
1223 ClassAtom != (RTL_ATOM)0 &&
1224 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
1225 {
1226 Class = IntFindClass( ClassAtom,
1227 lpwcx->hInstance,
1228 &pi->pclsPrivateList,
1229 NULL);
1230
1231 if (Class != NULL && !Class->Global)
1232 {
1233 // local class already exists
1234 DPRINT1("Local Class 0x%p does already exist!\n", ClassAtom);
1235 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1236 return (RTL_ATOM)0;
1237 }
1238
1239 if (lpwcx->style & CS_GLOBALCLASS)
1240 {
1241 Class = IntFindClass( ClassAtom,
1242 NULL,
1243 &pi->pclsPublicList,
1244 NULL);
1245
1246 if (Class != NULL && Class->Global)
1247 {
1248 DPRINT1("Global Class 0x%p does already exist!\n", ClassAtom);
1249 SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
1250 return (RTL_ATOM)0;
1251 }
1252 }
1253 }
1254
1255 Class = IntCreateClass(lpwcx,
1256 ClassName,
1257 MenuName,
1258 fnID,
1259 dwFlags,
1260 pti->Desktop,
1261 pi);
1262
1263 if (Class != NULL)
1264 {
1265 PCLS *List;
1266
1267 /* Register the class */
1268 if (Class->Global)
1269 List = &pi->pclsPublicList;
1270 else
1271 List = &pi->pclsPrivateList;
1272
1273 Class->pclsNext = *List;
1274 (void)InterlockedExchangePointer((PVOID*)List,
1275 Class);
1276
1277 Ret = Class->atomClassName;
1278 }
1279 else
1280 {
1281 DPRINT1("UserRegisterClass: Yes, that is right, you have no Class!\n");
1282 }
1283
1284 return Ret;
1285 }
1286
1287 BOOL
1288 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1289 IN HINSTANCE hInstance,
1290 OUT PCLSMENUNAME pClassMenuName)
1291 {
1292 PCLS *Link;
1293 PPROCESSINFO pi;
1294 RTL_ATOM ClassAtom;
1295 PCLS Class;
1296
1297 pi = GetW32ProcessInfo();
1298
1299 DPRINT("UserUnregisterClass(%wZ, 0x%x)\n", ClassName, hInstance);
1300
1301 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1302 ClassAtom = IntGetClassAtom(ClassName,
1303 hInstance,
1304 pi,
1305 &Class,
1306 &Link);
1307 if (ClassAtom == (RTL_ATOM)0)
1308 {
1309 DPRINT1("UserUnregisterClass: No Class found.\n");
1310 return FALSE;
1311 }
1312
1313 ASSERT(Class != NULL);
1314
1315 if (Class->cWndReferenceCount != 0 ||
1316 Class->pclsClone != NULL)
1317 {
1318 DPRINT("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class->cWndReferenceCount, Class->pclsClone);
1319 SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
1320 return FALSE;
1321 }
1322
1323 /* must be a base class! */
1324 ASSERT(Class->pclsBase == Class);
1325
1326 /* unlink the class */
1327 *Link = Class->pclsNext;
1328
1329 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1330 {
1331 DPRINT("Class 0x%x\n", Class);
1332 DPRINT("UserUnregisterClass: Good Exit!\n");
1333 /* finally free the resources */
1334 IntDestroyClass(Class);
1335 return TRUE;
1336 }
1337 DPRINT1("UserUnregisterClass: Can not deregister Class Atom.\n");
1338 return FALSE;
1339 }
1340
1341 INT
1342 UserGetClassName(IN PCLS Class,
1343 IN OUT PUNICODE_STRING ClassName,
1344 IN BOOL Ansi)
1345 {
1346 NTSTATUS Status = STATUS_SUCCESS;
1347 WCHAR szStaticTemp[32];
1348 PWSTR szTemp = NULL;
1349 ULONG BufLen = sizeof(szStaticTemp);
1350 INT Ret = 0;
1351
1352 /* Note: Accessing the buffer in ClassName may raise an exception! */
1353
1354 _SEH2_TRY
1355 {
1356 if (Ansi)
1357 {
1358 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1359 UNICODE_STRING UnicodeClassName;
1360
1361 /* limit the size of the static buffer on the stack to the
1362 size of the buffer provided by the caller */
1363 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1364 {
1365 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1366 }
1367
1368 /* find out how big the buffer needs to be */
1369 Status = RtlQueryAtomInAtomTable(gAtomTable,
1370 Class->atomClassName,
1371 NULL,
1372 NULL,
1373 szStaticTemp,
1374 &BufLen);
1375 if (Status == STATUS_BUFFER_TOO_SMALL)
1376 {
1377 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1378 {
1379 /* the buffer required exceeds the ansi buffer provided,
1380 pretend like we're using the ansi buffer and limit the
1381 size to the buffer size provided */
1382 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1383 }
1384
1385 /* allocate a temporary buffer that can hold the unicode class name */
1386 szTemp = ExAllocatePool(PagedPool,
1387 BufLen);
1388 if (szTemp == NULL)
1389 {
1390 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1391 _SEH2_LEAVE;
1392 }
1393
1394 /* query the class name */
1395 Status = RtlQueryAtomInAtomTable(gAtomTable,
1396 Class->atomClassName,
1397 NULL,
1398 NULL,
1399 szTemp,
1400 &BufLen);
1401 }
1402 else
1403 szTemp = szStaticTemp;
1404
1405 if (NT_SUCCESS(Status))
1406 {
1407 /* convert the atom name to ansi */
1408
1409 RtlInitUnicodeString(&UnicodeClassName,
1410 szTemp);
1411
1412 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1413 &UnicodeClassName,
1414 FALSE);
1415 if (!NT_SUCCESS(Status))
1416 {
1417 SetLastNtError(Status);
1418 _SEH2_LEAVE;
1419 }
1420 }
1421
1422 Ret = BufLen / sizeof(WCHAR);
1423 }
1424 else /* !Ansi */
1425 {
1426 BufLen = ClassName->MaximumLength;
1427
1428 /* query the atom name */
1429 Status = RtlQueryAtomInAtomTable(gAtomTable,
1430 Class->atomClassName,
1431 NULL,
1432 NULL,
1433 ClassName->Buffer,
1434 &BufLen);
1435
1436 if (!NT_SUCCESS(Status))
1437 {
1438 SetLastNtError(Status);
1439 _SEH2_LEAVE;
1440 }
1441
1442 Ret = BufLen / sizeof(WCHAR);
1443 }
1444 }
1445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1446 {
1447 SetLastNtError(_SEH2_GetExceptionCode());
1448 }
1449 _SEH2_END;
1450
1451 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1452 {
1453 ExFreePool(szTemp);
1454 }
1455
1456 return Ret;
1457 }
1458
1459 ULONG_PTR
1460 UserGetClassLongPtr(IN PCLS Class,
1461 IN INT Index,
1462 IN BOOL Ansi)
1463 {
1464 ULONG_PTR Ret = 0;
1465
1466 if (Index >= 0)
1467 {
1468 PULONG_PTR Data;
1469
1470 TRACE("GetClassLong(%d)\n", Index);
1471 if (Index + sizeof(ULONG_PTR) < Index ||
1472 Index + sizeof(ULONG_PTR) > Class->cbclsExtra)
1473 {
1474 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1475 return 0;
1476 }
1477
1478 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1479
1480 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1481 certain architectures, maybe using RtlCopyMemory is a
1482 better choice for those architectures! */
1483
1484 TRACE("Result: %x\n", Ret);
1485 return *Data;
1486 }
1487
1488 switch (Index)
1489 {
1490 case GCL_CBWNDEXTRA:
1491 Ret = (ULONG_PTR)Class->cbwndExtra;
1492 break;
1493
1494 case GCL_CBCLSEXTRA:
1495 Ret = (ULONG_PTR)Class->cbclsExtra;
1496 break;
1497
1498 case GCLP_HBRBACKGROUND:
1499 Ret = (ULONG_PTR)Class->hbrBackground;
1500 break;
1501
1502 case GCLP_HCURSOR:
1503 /* FIXME - get handle from pointer to CURSOR object */
1504 Ret = (ULONG_PTR)Class->hCursor;
1505 break;
1506
1507 case GCLP_HICON:
1508 /* FIXME - get handle from pointer to ICON object */
1509 Ret = (ULONG_PTR)Class->hIcon;
1510 break;
1511
1512 case GCLP_HICONSM:
1513 /* FIXME - get handle from pointer to ICON object */
1514 Ret = (ULONG_PTR)Class->hIconSm;
1515 break;
1516
1517 case GCLP_HMODULE:
1518 Ret = (ULONG_PTR)Class->hModule;
1519 break;
1520
1521 case GCLP_MENUNAME:
1522 /* NOTE: Returns pointer in kernel heap! */
1523 if (Ansi)
1524 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
1525 else
1526 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
1527 break;
1528
1529 case GCL_STYLE:
1530 Ret = (ULONG_PTR)Class->style;
1531 break;
1532
1533 case GCLP_WNDPROC:
1534 Ret = (ULONG_PTR)IntGetClassWndProc(Class, Ansi);
1535 break;
1536
1537 case GCW_ATOM:
1538 Ret = (ULONG_PTR)Class->atomClassName;
1539 break;
1540
1541 default:
1542 SetLastWin32Error(ERROR_INVALID_INDEX);
1543 break;
1544 }
1545
1546 return Ret;
1547 }
1548
1549 static BOOL
1550 IntSetClassMenuName(IN PCLS Class,
1551 IN PUNICODE_STRING MenuName)
1552 {
1553 BOOL Ret = FALSE;
1554
1555 /* change the base class first */
1556 Class = Class->pclsBase;
1557
1558 if (MenuName->Length != 0)
1559 {
1560 ANSI_STRING AnsiString;
1561 PWSTR strBufW;
1562
1563 AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
1564
1565 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1566 AnsiString.MaximumLength);
1567 if (strBufW != NULL)
1568 {
1569 _SEH2_TRY
1570 {
1571 NTSTATUS Status;
1572
1573 /* copy the unicode string */
1574 RtlCopyMemory(strBufW,
1575 MenuName->Buffer,
1576 MenuName->Length);
1577 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1578
1579 /* create an ansi copy of the string */
1580 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1581 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1582 MenuName,
1583 FALSE);
1584 if (!NT_SUCCESS(Status))
1585 {
1586 SetLastNtError(Status);
1587 _SEH2_LEAVE;
1588 }
1589
1590 Ret = TRUE;
1591 }
1592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1593 {
1594 SetLastNtError(_SEH2_GetExceptionCode());
1595 }
1596 _SEH2_END;
1597
1598 if (Ret)
1599 {
1600 /* update the base class */
1601 IntFreeClassMenuName(Class);
1602 Class->lpszClientUnicodeMenuName = strBufW;
1603 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1604 Class->MenuNameIsString = TRUE;
1605
1606 /* update the clones */
1607 Class = Class->pclsClone;
1608 while (Class != NULL)
1609 {
1610 Class->lpszClientUnicodeMenuName = strBufW;
1611 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1612 Class->MenuNameIsString = TRUE;
1613
1614 Class = Class->pclsNext;
1615 }
1616 }
1617 else
1618 {
1619 DPRINT1("Failed to copy class menu name!\n");
1620 UserHeapFree(strBufW);
1621 }
1622 }
1623 else
1624 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1625 }
1626 else
1627 {
1628 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1629
1630 /* update the base class */
1631 IntFreeClassMenuName(Class);
1632 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1633 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1634 Class->MenuNameIsString = FALSE;
1635
1636 /* update the clones */
1637 Class = Class->pclsClone;
1638 while (Class != NULL)
1639 {
1640 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1641 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1642 Class->MenuNameIsString = FALSE;
1643
1644 Class = Class->pclsNext;
1645 }
1646
1647 Ret = TRUE;
1648 }
1649
1650 return Ret;
1651 }
1652
1653 ULONG_PTR
1654 UserSetClassLongPtr(IN PCLS Class,
1655 IN INT Index,
1656 IN ULONG_PTR NewLong,
1657 IN BOOL Ansi)
1658 {
1659 ULONG_PTR Ret = 0;
1660
1661 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1662
1663 /* change the information in the base class first, then update the clones */
1664 Class = Class->pclsBase;
1665
1666 if (Index >= 0)
1667 {
1668 PULONG_PTR Data;
1669
1670 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1671
1672 if (Index + sizeof(ULONG_PTR) < Index ||
1673 Index + sizeof(ULONG_PTR) > Class->cbclsExtra)
1674 {
1675 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1676 return 0;
1677 }
1678
1679 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1680
1681 /* FIXME - Data might be a unaligned pointer! Might be a problem on
1682 certain architectures, maybe using RtlCopyMemory is a
1683 better choice for those architectures! */
1684 Ret = *Data;
1685 *Data = NewLong;
1686
1687 /* update the clones */
1688 Class = Class->pclsClone;
1689 while (Class != NULL)
1690 {
1691 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1692 Class = Class->pclsNext;
1693 }
1694
1695 return Ret;
1696 }
1697
1698 switch (Index)
1699 {
1700 case GCL_CBWNDEXTRA:
1701 Ret = (ULONG_PTR)Class->cbwndExtra;
1702 Class->cbwndExtra = (INT)NewLong;
1703
1704 /* update the clones */
1705 Class = Class->pclsClone;
1706 while (Class != NULL)
1707 {
1708 Class->cbwndExtra = (INT)NewLong;
1709 Class = Class->pclsNext;
1710 }
1711
1712 break;
1713
1714 case GCL_CBCLSEXTRA:
1715 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1716 break;
1717
1718 case GCLP_HBRBACKGROUND:
1719 Ret = (ULONG_PTR)Class->hbrBackground;
1720 Class->hbrBackground = (HBRUSH)NewLong;
1721
1722 /* update the clones */
1723 Class = Class->pclsClone;
1724 while (Class != NULL)
1725 {
1726 Class->hbrBackground = (HBRUSH)NewLong;
1727 Class = Class->pclsNext;
1728 }
1729 break;
1730
1731 case GCLP_HCURSOR:
1732 /* FIXME - get handle from pointer to CURSOR object */
1733 Ret = (ULONG_PTR)Class->hCursor;
1734 Class->hCursor = (HANDLE)NewLong;
1735
1736 /* update the clones */
1737 Class = Class->pclsClone;
1738 while (Class != NULL)
1739 {
1740 Class->hCursor = (HANDLE)NewLong;
1741 Class = Class->pclsNext;
1742 }
1743 break;
1744
1745 case GCLP_HICON:
1746 /* FIXME - get handle from pointer to ICON object */
1747 Ret = (ULONG_PTR)Class->hIcon;
1748 Class->hIcon = (HANDLE)NewLong;
1749
1750 /* update the clones */
1751 Class = Class->pclsClone;
1752 while (Class != NULL)
1753 {
1754 Class->hIcon = (HANDLE)NewLong;
1755 Class = Class->pclsNext;
1756 }
1757 break;
1758
1759 case GCLP_HICONSM:
1760 /* FIXME - get handle from pointer to ICON object */
1761 Ret = (ULONG_PTR)Class->hIconSm;
1762 Class->hIconSm = (HANDLE)NewLong;
1763
1764 /* update the clones */
1765 Class = Class->pclsClone;
1766 while (Class != NULL)
1767 {
1768 Class->hIconSm = (HANDLE)NewLong;
1769 Class = Class->pclsNext;
1770 }
1771 break;
1772
1773 case GCLP_HMODULE:
1774 Ret = (ULONG_PTR)Class->hModule;
1775 Class->hModule = (HINSTANCE)NewLong;
1776
1777 /* update the clones */
1778 Class = Class->pclsClone;
1779 while (Class != NULL)
1780 {
1781 Class->hModule = (HINSTANCE)NewLong;
1782 Class = Class->pclsNext;
1783 }
1784 break;
1785
1786 case GCLP_MENUNAME:
1787 {
1788 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1789
1790 if (!IntSetClassMenuName(Class,
1791 Value))
1792 {
1793 DPRINT1("Setting the class menu name failed!\n");
1794 }
1795
1796 /* FIXME - really return NULL? Wine does so... */
1797 break;
1798 }
1799
1800 case GCL_STYLE:
1801 Ret = (ULONG_PTR)Class->style;
1802 Class->style = (UINT)NewLong;
1803
1804 /* FIXME - what if the CS_GLOBALCLASS style is changed? should we
1805 move the class to the appropriate list? For now, we save
1806 the original value in Class->Global, so we can always
1807 locate the appropriate list */
1808
1809 /* update the clones */
1810 Class = Class->pclsClone;
1811 while (Class != NULL)
1812 {
1813 Class->style = (UINT)NewLong;
1814 Class = Class->pclsNext;
1815 }
1816 break;
1817
1818 case GCLP_WNDPROC:
1819 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1820 (WNDPROC)NewLong,
1821 Ansi);
1822 break;
1823
1824 case GCW_ATOM:
1825 {
1826 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1827
1828 Ret = (ULONG_PTR)Class->atomClassName;
1829 if (!IntSetClassAtom(Class,
1830 Value))
1831 {
1832 Ret = 0;
1833 }
1834 break;
1835 }
1836
1837 default:
1838 SetLastWin32Error(ERROR_INVALID_INDEX);
1839 break;
1840 }
1841
1842 return Ret;
1843 }
1844
1845 static BOOL
1846 UserGetClassInfo(IN PCLS Class,
1847 OUT PWNDCLASSEXW lpwcx,
1848 IN BOOL Ansi,
1849 HINSTANCE hInstance)
1850 {
1851 PPROCESSINFO pi;
1852
1853 if (!Class) return FALSE;
1854
1855 lpwcx->style = Class->style;
1856
1857 // If fnId is set, clear the global bit. See wine class test check_style.
1858 if (Class->fnid)
1859 lpwcx->style &= ~CS_GLOBALCLASS;
1860
1861 pi = GetW32ProcessInfo();
1862
1863 lpwcx->lpfnWndProc = IntGetClassWndProc(Class, Ansi);
1864
1865 lpwcx->cbClsExtra = Class->cbclsExtra;
1866 lpwcx->cbWndExtra = Class->cbwndExtra;
1867 lpwcx->hIcon = Class->hIcon; /* FIXME - get handle from pointer */
1868 lpwcx->hCursor = Class->hCursor; /* FIXME - get handle from pointer */
1869 lpwcx->hbrBackground = Class->hbrBackground;
1870
1871 /* Copy non-string to user first. */
1872 if (Ansi)
1873 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName;
1874 else
1875 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName;
1876 /*
1877 FIXME! CLSMENUNAME has the answers! Copy the already made buffers from there!
1878 Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
1879 lpszClientXxxMenuName should already be mapped to user space.
1880 */
1881 /* Copy string ptr to user. */
1882 if ( Class->lpszClientUnicodeMenuName != NULL &&
1883 Class->MenuNameIsString)
1884 {
1885 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ?
1886 (PVOID)Class->lpszClientAnsiMenuName :
1887 (PVOID)Class->lpszClientUnicodeMenuName);
1888 }
1889
1890 if (hInstance == hModClient)
1891 lpwcx->hInstance = NULL;
1892 else
1893 lpwcx->hInstance = hInstance;
1894
1895 /* FIXME - return the string? Okay! This is performed in User32!*/
1896 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
1897
1898 lpwcx->hIconSm = Class->hIconSm; /* FIXME - get handle from pointer */
1899
1900 return TRUE;
1901 }
1902
1903 //
1904 //
1905 //
1906 BOOL
1907 FASTCALL
1908 UserRegisterSystemClasses(VOID)
1909 {
1910 UINT i;
1911 UNICODE_STRING ClassName, MenuName;
1912 PPROCESSINFO ppi = GetW32ProcessInfo();
1913 WNDCLASSEXW wc;
1914 PCLS Class;
1915 BOOL Ret = TRUE;
1916 DWORD Flags = 0;
1917
1918 if (ppi->W32PF_flags & W32PF_CLASSESREGISTERED)
1919 return TRUE;
1920
1921 if ( hModClient == NULL)
1922 return FALSE;
1923
1924 RtlZeroMemory(&ClassName, sizeof(ClassName));
1925 RtlZeroMemory(&MenuName, sizeof(MenuName));
1926
1927 for (i = 0; i != ARRAYSIZE(DefaultServerClasses); i++)
1928 {
1929 if (!IS_ATOM(DefaultServerClasses[i].ClassName))
1930 {
1931 RtlInitUnicodeString(&ClassName, DefaultServerClasses[i].ClassName);
1932 }
1933 else
1934 {
1935 ClassName.Buffer = DefaultServerClasses[i].ClassName;
1936 ClassName.Length = 0;
1937 ClassName.MaximumLength = 0;
1938 }
1939
1940 wc.cbSize = sizeof(wc);
1941 wc.style = DefaultServerClasses[i].Style;
1942
1943 Flags |= CSF_SERVERSIDEPROC;
1944
1945 if (DefaultServerClasses[i].ProcW)
1946 {
1947 wc.lpfnWndProc = DefaultServerClasses[i].ProcW;
1948 wc.hInstance = hModuleWin;
1949 }
1950 else
1951 {
1952 wc.lpfnWndProc = GETPFNSERVER(DefaultServerClasses[i].fiId);
1953 wc.hInstance = hModClient;
1954 }
1955
1956 wc.cbClsExtra = 0;
1957 wc.cbWndExtra = DefaultServerClasses[i].ExtraBytes;
1958 wc.hIcon = NULL;
1959 wc.hCursor = DefaultServerClasses[i].hCursor;
1960 wc.hbrBackground = DefaultServerClasses[i].hBrush;
1961 wc.lpszMenuName = NULL;
1962 wc.lpszClassName = ClassName.Buffer;
1963 wc.hIconSm = NULL;
1964
1965 Class = IntCreateClass( &wc,
1966 &ClassName,
1967 &MenuName,
1968 DefaultServerClasses[i].fiId,
1969 Flags,
1970 NULL,
1971 ppi);
1972 if (Class != NULL)
1973 {
1974 Class->pclsNext = ppi->pclsPublicList;
1975 (void)InterlockedExchangePointer((PVOID*)&ppi->pclsPublicList,
1976 Class);
1977
1978 ppi->dwRegisteredClasses |= ICLASS_TO_MASK(DefaultServerClasses[i].iCls);
1979 }
1980 else
1981 {
1982 WARN("!!! Registering system class failed!\n");
1983 Ret = FALSE;
1984 }
1985 }
1986 if (Ret) ppi->W32PF_flags |= W32PF_CLASSESREGISTERED;
1987 return Ret;
1988 }
1989
1990 /* SYSCALLS *****************************************************************/
1991
1992 RTL_ATOM
1993 APIENTRY
1994 NtUserRegisterClassExWOW(
1995 WNDCLASSEXW* lpwcx,
1996 PUNICODE_STRING ClassName,
1997 PUNICODE_STRING ClsNVersion,
1998 PCLSMENUNAME pClassMenuName,
1999 DWORD fnID,
2000 DWORD Flags,
2001 LPDWORD pWow)
2002 /*
2003 * FUNCTION:
2004 * Registers a new class with the window manager
2005 * ARGUMENTS:
2006 * lpwcx = Win32 extended window class structure
2007 * bUnicodeClass = Whether to send ANSI or unicode strings
2008 * to window procedures
2009 * RETURNS:
2010 * Atom identifying the new class
2011 */
2012 {
2013 WNDCLASSEXW CapturedClassInfo = {0};
2014 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
2015 RTL_ATOM Ret = (RTL_ATOM)0;
2016 PPROCESSINFO ppi = GetW32ProcessInfo();
2017
2018 if (Flags & ~(CSF_ANSIPROC))
2019 {
2020 DPRINT1("NtUserRegisterClassExWOW Bad Flags!\n");
2021 SetLastWin32Error(ERROR_INVALID_FLAGS);
2022 return Ret;
2023 }
2024
2025 UserEnterExclusive();
2026
2027 DPRINT("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName);
2028
2029 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2030 {
2031 UserRegisterSystemClasses();
2032 }
2033
2034 _SEH2_TRY
2035 {
2036 /* Probe the parameters and basic parameter checks */
2037 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2038 {
2039 DPRINT1("NtUserRegisterClassExWOW Wrong cbSize!\n");
2040 goto InvalidParameter;
2041 }
2042
2043 ProbeForRead(lpwcx,
2044 sizeof(WNDCLASSEXW),
2045 sizeof(ULONG));
2046 RtlCopyMemory(&CapturedClassInfo,
2047 lpwcx,
2048 sizeof(WNDCLASSEXW));
2049
2050 CapturedName = ProbeForReadUnicodeString(ClassName);
2051
2052 ProbeForRead(pClassMenuName,
2053 sizeof(CLSMENUNAME),
2054 1);
2055
2056 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName);
2057
2058 if ( CapturedName.Length & 1 ||
2059 CapturedMenuName.Length & 1 ||
2060 CapturedClassInfo.cbClsExtra < 0 ||
2061 CapturedClassInfo.cbClsExtra +
2062 CapturedName.Length +
2063 CapturedMenuName.Length +
2064 sizeof(CLS) < CapturedClassInfo.cbClsExtra ||
2065 CapturedClassInfo.cbWndExtra < 0 ||
2066 CapturedClassInfo.hInstance == NULL)
2067 {
2068 DPRINT1("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2069 goto InvalidParameter;
2070 }
2071
2072 if (CapturedName.Length != 0)
2073 {
2074 ProbeForRead(CapturedName.Buffer,
2075 CapturedName.Length,
2076 sizeof(WCHAR));
2077 }
2078 else
2079 {
2080 if (!IS_ATOM(CapturedName.Buffer))
2081 {
2082 DPRINT1("NtUserRegisterClassExWOW ClassName Error!\n");
2083 goto InvalidParameter;
2084 }
2085 }
2086
2087 if (CapturedMenuName.Length != 0)
2088 {
2089 ProbeForRead(CapturedMenuName.Buffer,
2090 CapturedMenuName.Length,
2091 sizeof(WCHAR));
2092 }
2093 else if (CapturedMenuName.Buffer != NULL &&
2094 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2095 {
2096 DPRINT1("NtUserRegisterClassExWOW MenuName Error!\n");
2097 InvalidParameter:
2098 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2099 _SEH2_LEAVE;
2100 }
2101
2102 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2103 {// Never seen this yet, but I'm sure it's a little haxxy trick!
2104 // If this pops up we know what todo!
2105 DPRINT1("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2106 }
2107
2108 DPRINT("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2109
2110 /* Register the class */
2111 Ret = UserRegisterClass(&CapturedClassInfo,
2112 &CapturedName,
2113 &CapturedMenuName,
2114 fnID,
2115 Flags);
2116 }
2117 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2118 {
2119 DPRINT1("NtUserRegisterClassExWOW Exception Error!\n");
2120 SetLastNtError(_SEH2_GetExceptionCode());
2121 }
2122 _SEH2_END;
2123
2124 if (!Ret)
2125 {
2126 DPRINT1("NtUserRegisterClassExWOW Null Return!\n");
2127 }
2128
2129 UserLeave();
2130
2131 return Ret;
2132 }
2133
2134 ULONG_PTR APIENTRY
2135 NtUserGetClassLong(IN HWND hWnd,
2136 IN INT Offset,
2137 IN BOOL Ansi)
2138 {
2139 PWINDOW_OBJECT Window;
2140 ULONG_PTR Ret = 0;
2141
2142 if (Offset != GCLP_WNDPROC)
2143 {
2144 UserEnterShared();
2145 }
2146 else
2147 {
2148 UserEnterExclusive();
2149 }
2150
2151 Window = UserGetWindowObject(hWnd);
2152 if (Window != NULL)
2153 {
2154 Ret = UserGetClassLongPtr(Window->Wnd->pcls,
2155 Offset,
2156 Ansi);
2157
2158 if ( Ret != 0 &&
2159 Offset == GCLP_MENUNAME &&
2160 Window->Wnd->pcls->MenuNameIsString)
2161 {
2162 Ret = (ULONG_PTR)UserHeapAddressToUser((PVOID)Ret);
2163 }
2164 }
2165
2166 UserLeave();
2167
2168 return Ret;
2169 }
2170
2171
2172
2173 ULONG_PTR APIENTRY
2174 NtUserSetClassLong(HWND hWnd,
2175 INT Offset,
2176 ULONG_PTR dwNewLong,
2177 BOOL Ansi)
2178 {
2179 PPROCESSINFO pi;
2180 PWINDOW_OBJECT Window;
2181 ULONG_PTR Ret = 0;
2182
2183 UserEnterExclusive();
2184
2185 pi = GetW32ProcessInfo();
2186
2187 Window = UserGetWindowObject(hWnd);
2188 if (Window != NULL)
2189 {
2190 if (Window->ti->ppi != pi)
2191 {
2192 SetLastWin32Error(ERROR_ACCESS_DENIED);
2193 goto Cleanup;
2194 }
2195
2196 _SEH2_TRY
2197 {
2198 UNICODE_STRING Value;
2199
2200 /* probe the parameters */
2201 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2202 {
2203 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2204 if (Value.Length & 1)
2205 {
2206 goto InvalidParameter;
2207 }
2208
2209 if (Value.Length != 0)
2210 {
2211 ProbeForRead(Value.Buffer,
2212 Value.Length,
2213 sizeof(WCHAR));
2214 }
2215 else
2216 {
2217 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2218 {
2219 goto InvalidParameter;
2220 }
2221 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2222 {
2223 InvalidParameter:
2224 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2225 _SEH2_LEAVE;
2226 }
2227 }
2228
2229 dwNewLong = (ULONG_PTR)&Value;
2230 }
2231
2232 Ret = UserSetClassLongPtr(Window->Wnd->pcls,
2233 Offset,
2234 dwNewLong,
2235 Ansi);
2236 }
2237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2238 {
2239 SetLastNtError(_SEH2_GetExceptionCode());
2240 }
2241 _SEH2_END;
2242 }
2243
2244 Cleanup:
2245 UserLeave();
2246
2247 return Ret;
2248 }
2249
2250 WORD
2251 APIENTRY
2252 NtUserSetClassWord(
2253 HWND hWnd,
2254 INT nIndex,
2255 WORD wNewWord)
2256 {
2257 /*
2258 * NOTE: Obsoleted in 32-bit windows
2259 */
2260 return(0);
2261 }
2262
2263 BOOL APIENTRY
2264 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2265 IN HINSTANCE hInstance,
2266 OUT PCLSMENUNAME pClassMenuName)
2267 {
2268 UNICODE_STRING CapturedClassName;
2269 BOOL Ret = FALSE;
2270
2271 UserEnterExclusive();
2272
2273 _SEH2_TRY
2274 {
2275 /* probe the paramters */
2276 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2277 if (CapturedClassName.Length & 1)
2278 {
2279 goto InvalidParameter;
2280 }
2281
2282 if (CapturedClassName.Length != 0)
2283 {
2284 ProbeForRead(CapturedClassName.Buffer,
2285 CapturedClassName.Length,
2286 sizeof(WCHAR));
2287 }
2288 else
2289 {
2290 if (!IS_ATOM(CapturedClassName.Buffer))
2291 {
2292 InvalidParameter:
2293 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2294 _SEH2_LEAVE;
2295 }
2296 }
2297
2298 /* unregister the class */
2299 Ret = UserUnregisterClass(&CapturedClassName,
2300 hInstance,
2301 NULL); // Null for now~
2302 }
2303 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2304 {
2305 SetLastNtError(_SEH2_GetExceptionCode());
2306 }
2307 _SEH2_END;
2308
2309 UserLeave();
2310 return Ret;
2311 }
2312
2313 /* NOTE: for system classes hInstance is not NULL here, but User32Instance */
2314 BOOL APIENTRY
2315 NtUserGetClassInfo(
2316 HINSTANCE hInstance,
2317 PUNICODE_STRING ClassName,
2318 LPWNDCLASSEXW lpWndClassEx,
2319 LPWSTR *ppszMenuName,
2320 BOOL Ansi)
2321 {
2322 UNICODE_STRING CapturedClassName, SafeClassName;
2323 WNDCLASSEXW Safewcexw;
2324 PCLS Class;
2325 RTL_ATOM ClassAtom = 0;
2326 PPROCESSINFO ppi;
2327 BOOL Ret = TRUE;
2328
2329 /* NOTE: need exclusive lock because getting the wndproc might require the
2330 creation of a call procedure handle */
2331 UserEnterExclusive();
2332
2333 ppi = GetW32ProcessInfo();
2334
2335 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2336 {
2337 UserRegisterSystemClasses();
2338 }
2339
2340 _SEH2_TRY
2341 {
2342 /* probe the paramters */
2343 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2344
2345 if (CapturedClassName.Length == 0)
2346 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2347 else
2348 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2349
2350 if (CapturedClassName.Length & 1)
2351 {
2352 goto InvalidParameter;
2353 }
2354
2355 if (CapturedClassName.Length != 0)
2356 {
2357 ProbeForRead( CapturedClassName.Buffer,
2358 CapturedClassName.Length,
2359 sizeof(WCHAR));
2360
2361 RtlInitUnicodeString( &SafeClassName, CapturedClassName.Buffer);
2362
2363 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2364 SafeClassName.MaximumLength,
2365 TAG_STRING);
2366 RtlCopyMemory( SafeClassName.Buffer,
2367 CapturedClassName.Buffer,
2368 SafeClassName.MaximumLength);
2369 }
2370 else
2371 {
2372 if (!IS_ATOM(CapturedClassName.Buffer))
2373 {
2374 ERR("NtUserGetClassInfo() got ClassName instead of Atom!\n");
2375 goto InvalidParameter;
2376 }
2377
2378 SafeClassName.Buffer = CapturedClassName.Buffer;
2379 SafeClassName.Length = 0;
2380 SafeClassName.MaximumLength = 0;
2381 }
2382
2383 if (ProbeForReadUint(&lpWndClassEx->cbSize) != sizeof(WNDCLASSEXW))
2384 {
2385 InvalidParameter:
2386 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2387 Ret = FALSE;
2388 _SEH2_LEAVE;
2389 }
2390
2391 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2392
2393 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2394 }
2395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2396 {
2397 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2398 Ret = FALSE;
2399 }
2400 _SEH2_END;
2401
2402 // If null instance use client.
2403 if (!hInstance) hInstance = hModClient;
2404
2405 if (Ret)
2406 {
2407 DPRINT("GetClassInfo(%wZ, 0x%x)\n", ClassName, hInstance);
2408 ClassAtom = IntGetClassAtom( &SafeClassName,
2409 hInstance,
2410 ppi,
2411 &Class,
2412 NULL);
2413 if (ClassAtom != (RTL_ATOM)0)
2414 {
2415 if (hInstance == NULL) hInstance = hModClient;
2416
2417 Ret = UserGetClassInfo( Class,
2418 &Safewcexw,
2419 Ansi,
2420 hInstance);
2421 }
2422 else
2423 {
2424 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2425 Ret = FALSE;
2426 }
2427 }
2428 _SEH2_TRY
2429 {
2430 if (Ret)
2431 {
2432 /* Emulate Function. */
2433 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2434
2435 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2436
2437 // From Wine:
2438 /* We must return the atom of the class here instead of just TRUE. */
2439 /* Undocumented behavior! Return the class atom as a BOOL! */
2440 Ret = (BOOL)ClassAtom;
2441 }
2442 }
2443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2444 {
2445 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2446 Ret = FALSE;
2447 }
2448 _SEH2_END;
2449
2450 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2451 UserLeave();
2452 return Ret;
2453 }
2454
2455
2456 INT APIENTRY
2457 NtUserGetClassName (IN HWND hWnd,
2458 OUT PUNICODE_STRING ClassName,
2459 IN BOOL Ansi)
2460 {
2461 PWINDOW_OBJECT Window;
2462 UNICODE_STRING CapturedClassName;
2463 INT Ret = 0;
2464
2465 UserEnterShared();
2466
2467 Window = UserGetWindowObject(hWnd);
2468 if (Window != NULL)
2469 {
2470 _SEH2_TRY
2471 {
2472 ProbeForWriteUnicodeString(ClassName);
2473 CapturedClassName = *ClassName;
2474
2475 /* get the class name */
2476 Ret = UserGetClassName(Window->Wnd->pcls,
2477 &CapturedClassName,
2478 Ansi);
2479
2480 if (Ret != 0)
2481 {
2482 /* update the Length field */
2483 ClassName->Length = CapturedClassName.Length;
2484 }
2485 }
2486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2487 {
2488 SetLastNtError(_SEH2_GetExceptionCode());
2489 }
2490 _SEH2_END;
2491 }
2492
2493 UserLeave();
2494
2495 return Ret;
2496 }
2497
2498 /* Return Pointer to Class structure. */
2499 PCLS APIENTRY
2500 NtUserGetWOWClass(HINSTANCE hInstance,
2501 PUNICODE_STRING ClassName)
2502 {
2503 UNICODE_STRING SafeClassName;
2504 PPROCESSINFO pi;
2505 PCLS Class = NULL;
2506 RTL_ATOM ClassAtom = 0;
2507 BOOL Hit = FALSE;
2508
2509 UserEnterExclusive();
2510
2511 pi = GetW32ProcessInfo();
2512
2513 _SEH2_TRY
2514 {
2515 if (ClassName->Length != 0)
2516 {
2517 ProbeForRead( ClassName->Buffer,
2518 ClassName->Length,
2519 sizeof(WCHAR));
2520
2521 RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
2522
2523 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2524 SafeClassName.MaximumLength,
2525 TAG_STRING);
2526 RtlCopyMemory( SafeClassName.Buffer,
2527 ClassName->Buffer,
2528 SafeClassName.MaximumLength);
2529 }
2530 else
2531 {
2532 if (!IS_ATOM(ClassName->Buffer))
2533 {
2534 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2535 Hit = TRUE;
2536 }
2537 else
2538 {
2539 SafeClassName.Buffer = ClassName->Buffer;
2540 SafeClassName.Length = 0;
2541 SafeClassName.MaximumLength = 0;
2542 }
2543 }
2544 }
2545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2546 {
2547 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2548 Hit = TRUE;
2549 }
2550 _SEH2_END;
2551
2552 if (!Hit)
2553 {
2554 ClassAtom = IntGetClassAtom( &SafeClassName,
2555 hInstance,
2556 pi,
2557 &Class,
2558 NULL);
2559 if (!ClassAtom)
2560 {
2561 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2562 }
2563 }
2564
2565 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2566 UserLeave();
2567 //
2568 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2569 //
2570 return Class;
2571 }
2572
2573 /* EOF */