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