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