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