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