[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / class.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/class.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserClass);
11
12 REGISTER_SYSCLASS DefaultServerClasses[] =
13 {
14 { ((PWSTR)((ULONG_PTR)(WORD)(0x8001))),
15 CS_GLOBALCLASS|CS_DBLCLKS,
16 NULL,
17 0,
18 (HICON)IDC_ARROW,
19 (HBRUSH)(COLOR_BACKGROUND + 1),
20 FNID_DESKTOP,
21 ICLS_DESKTOP
22 },
23 { ((PWSTR)((ULONG_PTR)(WORD)(0x8003))),
24 CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS,
25 NULL, // Use User32 procs
26 sizeof(LONG),
27 (HICON)IDC_ARROW,
28 NULL,
29 FNID_SWITCH,
30 ICLS_SWITCH
31 },
32 { ((PWSTR)((ULONG_PTR)(WORD)(0x8000))),
33 CS_DBLCLKS|CS_SAVEBITS,
34 NULL, // Use User32 procs
35 sizeof(LONG),
36 (HICON)IDC_ARROW,
37 (HBRUSH)(COLOR_MENU + 1),
38 FNID_MENU,
39 ICLS_MENU
40 },
41 { L"ScrollBar",
42 CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW|CS_PARENTDC,
43 NULL, // Use User32 procs
44 sizeof(SBWND)-sizeof(WND),
45 (HICON)IDC_ARROW,
46 NULL,
47 FNID_SCROLLBAR,
48 ICLS_SCROLLBAR
49 },
50 { ((PWSTR)((ULONG_PTR)(WORD)(0x8004))), // IconTitle is here for now...
51 0,
52 NULL, // Use User32 procs
53 0,
54 (HICON)IDC_ARROW,
55 0,
56 FNID_ICONTITLE,
57 ICLS_ICONTITLE
58 },
59 { L"Message",
60 CS_GLOBALCLASS,
61 NULL, // Use User32 procs
62 0,
63 (HICON)IDC_ARROW,
64 NULL,
65 FNID_MESSAGEWND,
66 ICLS_HWNDMESSAGE
67 }
68 };
69
70 static struct
71 {
72 int FnId;
73 int ClsId;
74 } FnidToiCls[] =
75 { /* Function Ids to Class indexes. */
76 { FNID_SCROLLBAR, ICLS_SCROLLBAR},
77 { FNID_ICONTITLE, ICLS_ICONTITLE},
78 { FNID_MENU, ICLS_MENU},
79 { FNID_DESKTOP, ICLS_DESKTOP},
80 { FNID_SWITCH, ICLS_SWITCH},
81 { FNID_MESSAGEWND, ICLS_HWNDMESSAGE},
82 { FNID_BUTTON, ICLS_BUTTON},
83 { FNID_COMBOBOX, ICLS_COMBOBOX},
84 { FNID_COMBOLBOX, ICLS_COMBOLBOX},
85 { FNID_DIALOG, ICLS_DIALOG},
86 { FNID_EDIT, ICLS_EDIT},
87 { FNID_LISTBOX, ICLS_LISTBOX},
88 { FNID_MDICLIENT, ICLS_MDICLIENT},
89 { FNID_STATIC, ICLS_STATIC},
90 { FNID_IME, ICLS_IME},
91 { FNID_GHOST, ICLS_GHOST},
92 { FNID_TOOLTIPS, ICLS_TOOLTIPS}
93 };
94
95 BOOL
96 FASTCALL
97 LookupFnIdToiCls(int FnId, int *iCls )
98 {
99 int i;
100
101 for ( i = 0; i < ARRAYSIZE(FnidToiCls); i++)
102 {
103 if (FnidToiCls[i].FnId == FnId)
104 {
105 if (iCls) *iCls = FnidToiCls[i].ClsId;
106 return TRUE;
107 }
108 }
109 if (iCls) *iCls = 0;
110 return FALSE;
111 }
112
113 /* WINDOWCLASS ***************************************************************/
114
115 static VOID
116 IntFreeClassMenuName(IN OUT PCLS Class)
117 {
118 /* Free the menu name, if it was changed and allocated */
119 if (Class->lpszClientUnicodeMenuName != NULL && Class->MenuNameIsString)
120 {
121 UserHeapFree(Class->lpszClientUnicodeMenuName);
122 Class->lpszClientUnicodeMenuName = NULL;
123 Class->lpszClientAnsiMenuName = NULL;
124 }
125 }
126
127 static VOID
128 IntDestroyClass(IN OUT PCLS Class)
129 {
130 PDESKTOP pDesk;
131
132 /* There shouldn't be any clones anymore */
133 ASSERT(Class->cWndReferenceCount == 0);
134 ASSERT(Class->pclsClone == NULL);
135
136 if (Class->pclsBase == Class)
137 {
138 PCALLPROCDATA CallProc, NextCallProc;
139
140 /* Destroy allocated callproc handles */
141 CallProc = Class->spcpdFirst;
142 while (CallProc != NULL)
143 {
144 NextCallProc = CallProc->spcpdNext;
145
146 CallProc->spcpdNext = NULL;
147 DestroyCallProc(NULL,
148 CallProc);
149
150 CallProc = NextCallProc;
151 }
152
153 if (Class->pdce)
154 {
155 DceFreeClassDCE(((PDCE)Class->pdce)->hDC);
156 Class->pdce = NULL;
157 }
158
159 IntFreeClassMenuName(Class);
160 }
161
162 pDesk = Class->rpdeskParent;
163 Class->rpdeskParent = NULL;
164
165 /* Free the structure */
166 if (pDesk != NULL)
167 {
168 DesktopHeapFree(pDesk, Class);
169 }
170 else
171 {
172 UserHeapFree(Class);
173 }
174 }
175
176
177 /* Clean all process classes. all process windows must cleaned first!! */
178 void FASTCALL DestroyProcessClasses(PPROCESSINFO Process )
179 {
180 PCLS Class;
181 PPROCESSINFO pi = (PPROCESSINFO)Process;
182
183 if (pi != NULL)
184 {
185 /* Free all local classes */
186 Class = pi->pclsPrivateList;
187 while (Class != NULL)
188 {
189 pi->pclsPrivateList = Class->pclsNext;
190
191 ASSERT(Class->pclsBase == Class);
192 IntDestroyClass(Class);
193
194 Class = pi->pclsPrivateList;
195 }
196
197 /* Free all global classes */
198 Class = pi->pclsPublicList;
199 while (Class != NULL)
200 {
201 pi->pclsPublicList = Class->pclsNext;
202
203 ASSERT(Class->pclsBase == Class);
204 IntDestroyClass(Class);
205
206 Class = pi->pclsPublicList;
207 }
208 }
209 }
210
211 static BOOL
212 IntRegisterClassAtom(IN PUNICODE_STRING ClassName,
213 OUT RTL_ATOM *pAtom)
214 {
215 WCHAR szBuf[65];
216 PWSTR AtomName;
217 NTSTATUS Status;
218
219 if (ClassName->Length != 0)
220 {
221 /* FIXME: Don't limit to 64 characters! Use SEH when allocating memory! */
222 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
223 {
224 EngSetLastError(ERROR_INVALID_PARAMETER);
225 return (RTL_ATOM)0;
226 }
227
228 RtlCopyMemory(szBuf,
229 ClassName->Buffer,
230 ClassName->Length);
231 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
232 AtomName = szBuf;
233 }
234 else
235 AtomName = ClassName->Buffer;
236
237 Status = RtlAddAtomToAtomTable(gAtomTable,
238 AtomName,
239 pAtom);
240
241 if (!NT_SUCCESS(Status))
242 {
243 SetLastNtError(Status);
244 return FALSE;
245 }
246
247 return TRUE;
248 }
249
250 static NTSTATUS
251 IntDeregisterClassAtom(IN RTL_ATOM Atom)
252 {
253 return RtlDeleteAtomFromAtomTable(gAtomTable,
254 Atom);
255 }
256
257 VOID
258 UserAddCallProcToClass(IN OUT PCLS Class,
259 IN PCALLPROCDATA CallProc)
260 {
261 PCLS BaseClass;
262
263 ASSERT(CallProc->spcpdNext == NULL);
264
265 BaseClass = Class->pclsBase;
266 ASSERT(CallProc->spcpdNext == NULL);
267 CallProc->spcpdNext = BaseClass->spcpdFirst;
268 BaseClass->spcpdFirst = CallProc;
269
270 /* Update all clones */
271 Class = Class->pclsClone;
272 while (Class != NULL)
273 {
274 Class->spcpdFirst = BaseClass->spcpdFirst;
275 Class = Class->pclsNext;
276 }
277 }
278
279 static BOOL
280 IntSetClassAtom(IN OUT PCLS Class,
281 IN PUNICODE_STRING ClassName)
282 {
283 RTL_ATOM Atom = (RTL_ATOM)0;
284
285 /* Update the base class first */
286 Class = Class->pclsBase;
287
288 if (!IntRegisterClassAtom(ClassName,
289 &Atom))
290 {
291 return FALSE;
292 }
293
294 IntDeregisterClassAtom(Class->atomClassName);
295
296 Class->atomClassName = Atom;
297
298 /* Update the clones */
299 Class = Class->pclsClone;
300 while (Class != NULL)
301 {
302 Class->atomClassName = Atom;
303
304 Class = Class->pclsNext;
305 }
306
307 return TRUE;
308 }
309
310 //
311 // Same as User32:IntGetClsWndProc.
312 //
313 WNDPROC FASTCALL
314 IntGetClassWndProc(PCLS Class, BOOL Ansi)
315 {
316 INT i;
317 WNDPROC gcpd = NULL, Ret = NULL;
318
319 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
320 {
321 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
322 {
323 if (GETPFNSERVER(i) == Class->lpfnWndProc)
324 {
325 if (Ansi)
326 Ret = GETPFNCLIENTA(i);
327 else
328 Ret = GETPFNCLIENTW(i);
329 }
330 }
331 return Ret;
332 }
333 Ret = Class->lpfnWndProc;
334
335 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
336 {
337 if (Ansi)
338 {
339 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
340 Ret = GETPFNCLIENTA(Class->fnid);
341 }
342 else
343 {
344 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
345 Ret = GETPFNCLIENTW(Class->fnid);
346 }
347 }
348
349 if ( Ret != Class->lpfnWndProc ||
350 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
351 return Ret;
352
353 gcpd = (WNDPROC)UserGetCPD( Class,
354 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDClass,
355 (ULONG_PTR)Ret);
356
357 return (gcpd ? gcpd : Ret);
358 }
359
360
361 static
362 WNDPROC FASTCALL
363 IntSetClassWndProc(IN OUT PCLS Class,
364 IN WNDPROC WndProc,
365 IN BOOL Ansi)
366 {
367 INT i;
368 PCALLPROCDATA pcpd;
369 WNDPROC Ret, chWndProc;
370
371 Ret = IntGetClassWndProc(Class, Ansi);
372
373 // If Server Side, downgrade to Client Side.
374 if (Class->CSF_flags & CSF_SERVERSIDEPROC)
375 {
376 if (Ansi) Class->CSF_flags |= CSF_ANSIPROC;
377 Class->CSF_flags &= ~CSF_SERVERSIDEPROC;
378 Class->Unicode = !Ansi;
379 }
380
381 if (!WndProc) WndProc = Class->lpfnWndProc;
382
383 chWndProc = WndProc;
384
385 // Check if CallProc handle and retrieve previous call proc address and set.
386 if (IsCallProcHandle(WndProc))
387 {
388 pcpd = UserGetObject(gHandleTable, WndProc, otCallProc);
389 if (pcpd) chWndProc = pcpd->pfnClientPrevious;
390 }
391
392 Class->lpfnWndProc = chWndProc;
393
394 // Clear test proc.
395 chWndProc = NULL;
396
397 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
398 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
399 {
400 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
401 {
402 chWndProc = GETPFNSERVER(i);
403 break;
404 }
405 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
406 {
407 chWndProc = GETPFNSERVER(i);
408 break;
409 }
410 }
411 // If match, set/reset to Server Side and clear ansi.
412 if (chWndProc)
413 {
414 Class->lpfnWndProc = chWndProc;
415 Class->Unicode = TRUE;
416 Class->CSF_flags &= ~CSF_ANSIPROC;
417 Class->CSF_flags |= CSF_SERVERSIDEPROC;
418 }
419 else
420 {
421 Class->Unicode = !Ansi;
422
423 if (Ansi)
424 Class->CSF_flags |= CSF_ANSIPROC;
425 else
426 Class->CSF_flags &= ~CSF_ANSIPROC;
427 }
428
429 /* Update the clones */
430 chWndProc = Class->lpfnWndProc;
431
432 Class = Class->pclsClone;
433 while (Class != NULL)
434 {
435 Class->Unicode = !Ansi;
436 Class->lpfnWndProc = chWndProc;
437
438 Class = Class->pclsNext;
439 }
440
441 return Ret;
442 }
443
444 static PCLS
445 IntGetClassForDesktop(IN OUT PCLS BaseClass,
446 IN OUT PCLS *ClassLink,
447 IN PDESKTOP Desktop)
448 {
449 SIZE_T ClassSize;
450 PCLS Class;
451
452 ASSERT(Desktop != NULL);
453 ASSERT(BaseClass->pclsBase == BaseClass);
454
455 if (BaseClass->rpdeskParent == Desktop)
456 {
457 /* It is most likely that a window is created on the same
458 desktop as the window class. */
459
460 return BaseClass;
461 }
462
463 if (BaseClass->rpdeskParent == NULL)
464 {
465 ASSERT(BaseClass->cWndReferenceCount == 0);
466 ASSERT(BaseClass->pclsClone == NULL);
467
468 /* Classes are also located in the shared heap when the class
469 was created before the thread attached to a desktop. As soon
470 as a window is created for such a class located on the shared
471 heap, the class is cloned into the desktop heap on which the
472 window is created. */
473 Class = NULL;
474 }
475 else
476 {
477 /* The user is asking for a class object on a different desktop,
478 try to find one! */
479 Class = BaseClass->pclsClone;
480 while (Class != NULL)
481 {
482 if (Class->rpdeskParent == Desktop)
483 {
484 ASSERT(Class->pclsBase == BaseClass);
485 ASSERT(Class->pclsClone == NULL);
486 break;
487 }
488
489 Class = Class->pclsNext;
490 }
491 }
492
493 if (Class == NULL)
494 {
495 /* The window is created on a different desktop, we need to
496 clone the class object to the desktop heap of the window! */
497 ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->cbclsExtra;
498
499 Class = DesktopHeapAlloc(Desktop,
500 ClassSize);
501 if (Class != NULL)
502 {
503 /* Simply clone the class */
504 RtlCopyMemory( Class, BaseClass, ClassSize);
505
506 TRACE("Clone Class 0x%x hM 0x%x\n %S\n",Class, Class->hModule, Class->lpszClientUnicodeMenuName);
507
508 /* Restore module address if default user class Ref: Bug 4778 */
509 if ( Class->hModule != hModClient &&
510 Class->fnid <= FNID_GHOST &&
511 Class->fnid >= FNID_BUTTON )
512 {
513 Class->hModule = hModClient;
514 TRACE("Clone Class 0x%x Reset hM 0x%x\n",Class, Class->hModule);
515 }
516
517 /* Update some pointers and link the class */
518 Class->rpdeskParent = Desktop;
519 Class->cWndReferenceCount = 0;
520
521 if (BaseClass->rpdeskParent == NULL)
522 {
523 /* We don't really need the base class on the shared
524 heap anymore, delete it so the only class left is
525 the clone we just created, which now serves as the
526 new base class */
527 ASSERT(BaseClass->pclsClone == NULL);
528 ASSERT(Class->pclsClone == NULL);
529 Class->pclsBase = Class;
530 Class->pclsNext = BaseClass->pclsNext;
531
532 /* Replace the base class */
533 (void)InterlockedExchangePointer((PVOID*)ClassLink,
534 Class);
535
536 /* Destroy the obsolete copy on the shared heap */
537 BaseClass->pclsBase = NULL;
538 BaseClass->pclsClone = NULL;
539 IntDestroyClass(BaseClass);
540 }
541 else
542 {
543 /* Link in the clone */
544 Class->pclsClone = NULL;
545 Class->pclsBase = BaseClass;
546 Class->pclsNext = BaseClass->pclsClone;
547 (void)InterlockedExchangePointer((PVOID*)&BaseClass->pclsClone,
548 Class);
549 }
550 }
551 else
552 {
553 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
554 }
555 }
556 return Class;
557 }
558
559 PCLS
560 IntReferenceClass(IN OUT PCLS BaseClass,
561 IN OUT PCLS *ClassLink,
562 IN PDESKTOP Desktop)
563 {
564 PCLS Class;
565 ASSERT(BaseClass->pclsBase == BaseClass);
566
567 Class = IntGetClassForDesktop(BaseClass,
568 ClassLink,
569 Desktop);
570 if (Class != NULL)
571 {
572 Class->cWndReferenceCount++;
573 }
574
575 return Class;
576 }
577
578 static
579 VOID
580 IntMakeCloneBaseClass(IN OUT PCLS Class,
581 IN OUT PCLS *BaseClassLink,
582 IN OUT PCLS *CloneLink)
583 {
584 PCLS Clone;
585
586 ASSERT(Class->pclsBase != Class);
587 ASSERT(Class->pclsBase->pclsClone != NULL);
588 ASSERT(Class->rpdeskParent != NULL);
589 ASSERT(Class->cWndReferenceCount != 0);
590 ASSERT(Class->pclsBase->rpdeskParent != NULL);
591 ASSERT(Class->pclsBase->cWndReferenceCount == 0);
592
593 /* Unlink the clone */
594 *CloneLink = Class->pclsNext;
595 Class->pclsClone = Class->pclsBase->pclsClone;
596
597 /* Update the class information to make it a base class */
598 Class->pclsBase = Class;
599 Class->pclsNext = (*BaseClassLink)->pclsNext;
600
601 /* Update all clones */
602 Clone = Class->pclsClone;
603 while (Clone != NULL)
604 {
605 ASSERT(Clone->pclsClone == NULL);
606 Clone->pclsBase = Class;
607
608 Clone = Clone->pclsNext;
609 }
610
611 /* Link in the new base class */
612 (void)InterlockedExchangePointer((PVOID*)BaseClassLink,
613 Class);
614 }
615
616
617 VOID
618 IntDereferenceClass(IN OUT PCLS Class,
619 IN PDESKTOPINFO Desktop,
620 IN PPROCESSINFO pi)
621 {
622 PCLS *PrevLink, BaseClass, CurrentClass;
623
624 ASSERT(Class->cWndReferenceCount >= 1);
625
626 BaseClass = Class->pclsBase;
627
628 if (--Class->cWndReferenceCount == 0)
629 {
630 if (BaseClass == Class)
631 {
632 ASSERT(Class->pclsBase == Class);
633
634 TRACE("IntDereferenceClass 0x%x\n", Class);
635 /* Check if there are clones of the class on other desktops,
636 link the first clone in if possible. If there are no clones
637 then leave the class on the desktop heap. It will get moved
638 to the shared heap when the thread detaches. */
639 if (BaseClass->pclsClone != NULL)
640 {
641 if (BaseClass->Global)
642 PrevLink = &pi->pclsPublicList;
643 else
644 PrevLink = &pi->pclsPrivateList;
645
646 CurrentClass = *PrevLink;
647 while (CurrentClass != BaseClass)
648 {
649 ASSERT(CurrentClass != NULL);
650
651 PrevLink = &CurrentClass->pclsNext;
652 CurrentClass = CurrentClass->pclsNext;
653 }
654
655 ASSERT(*PrevLink == BaseClass);
656
657 /* Make the first clone become the new base class */
658 IntMakeCloneBaseClass(BaseClass->pclsClone,
659 PrevLink,
660 &BaseClass->pclsClone);
661
662 /* Destroy the class, there's still another clone of the class
663 that now serves as a base class. Make sure we don't destruct
664 resources shared by all classes (Base = NULL)! */
665 BaseClass->pclsBase = NULL;
666 BaseClass->pclsClone = NULL;
667 IntDestroyClass(BaseClass);
668 }
669 }
670 else
671 {
672 TRACE("IntDereferenceClass1 0x%x\n", Class);
673
674 /* Locate the cloned class and unlink it */
675 PrevLink = &BaseClass->pclsClone;
676 CurrentClass = BaseClass->pclsClone;
677 while (CurrentClass != Class)
678 {
679 ASSERT(CurrentClass != NULL);
680
681 PrevLink = &CurrentClass->pclsNext;
682 CurrentClass = CurrentClass->pclsNext;
683 }
684
685 ASSERT(CurrentClass == Class);
686
687 (void)InterlockedExchangePointer((PVOID*)PrevLink,
688 Class->pclsNext);
689
690 ASSERT(Class->pclsBase == BaseClass);
691 ASSERT(Class->pclsClone == NULL);
692
693 /* The class was just a clone, we don't need it anymore */
694 IntDestroyClass(Class);
695 }
696 }
697 }
698
699 static BOOL
700 IntMoveClassToSharedHeap(IN OUT PCLS Class,
701 IN OUT PCLS **ClassLinkPtr)
702 {
703 PCLS NewClass;
704 SIZE_T ClassSize;
705
706 ASSERT(Class->pclsBase == Class);
707 ASSERT(Class->rpdeskParent != NULL);
708 ASSERT(Class->cWndReferenceCount == 0);
709 ASSERT(Class->pclsClone == NULL);
710
711 ClassSize = sizeof(*Class) + (SIZE_T)Class->cbclsExtra;
712
713 /* Allocate the new base class on the shared heap */
714 NewClass = UserHeapAlloc(ClassSize);
715 if (NewClass != NULL)
716 {
717 RtlCopyMemory(NewClass,
718 Class,
719 ClassSize);
720
721 NewClass->rpdeskParent = NULL;
722 NewClass->pclsBase = NewClass;
723
724 /* Replace the class in the list */
725 (void)InterlockedExchangePointer((PVOID*)*ClassLinkPtr,
726 NewClass);
727 *ClassLinkPtr = &NewClass->pclsNext;
728
729 /* Free the obsolete class on the desktop heap */
730 Class->pclsBase = NULL;
731 IntDestroyClass(Class);
732 return TRUE;
733 }
734
735 return FALSE;
736 }
737
738 static VOID
739 IntCheckDesktopClasses(IN PDESKTOP Desktop,
740 IN OUT PCLS *ClassList,
741 IN BOOL FreeOnFailure,
742 OUT BOOL *Ret)
743 {
744 PCLS Class, NextClass, *Link;
745
746 /* NOTE: We only need to check base classes! When classes are no longer needed
747 on a desktop, the clones will be freed automatically as soon as possible.
748 However, we need to move base classes to the shared heap, as soon as
749 the last desktop heap where a class is allocated on is about to be destroyed.
750 If we didn't move the class to the shared heap, the class would become
751 inaccessible! */
752
753 ASSERT(Desktop != NULL);
754
755 Link = ClassList;
756 Class = *Link;
757 while (Class != NULL)
758 {
759 NextClass = Class->pclsNext;
760
761 ASSERT(Class->pclsBase == Class);
762
763 if (Class->rpdeskParent == Desktop &&
764 Class->cWndReferenceCount == 0)
765 {
766 /* There shouldn't be any clones around anymore! */
767 ASSERT(Class->pclsClone == NULL);
768
769 /* FIXME: If process is terminating, don't move the class but rather destroy it! */
770 /* FIXME: We could move the class to another desktop heap if there's still desktops
771 mapped into the process... */
772
773 /* Move the class to the shared heap */
774 if (IntMoveClassToSharedHeap(Class,
775 &Link))
776 {
777 ASSERT(*Link == NextClass);
778 }
779 else
780 {
781 ASSERT(NextClass == Class->pclsNext);
782
783 if (FreeOnFailure)
784 {
785 /* Unlink the base class */
786 (void)InterlockedExchangePointer((PVOID*)Link,
787 Class->pclsNext);
788
789 /* We can free the old base class now */
790 Class->pclsBase = NULL;
791 IntDestroyClass(Class);
792 }
793 else
794 {
795 Link = &Class->pclsNext;
796 *Ret = FALSE;
797 }
798 }
799 }
800 else
801 Link = &Class->pclsNext;
802
803 Class = NextClass;
804 }
805 }
806
807 BOOL
808 IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
809 IN BOOL FreeOnFailure)
810 {
811 PPROCESSINFO pi;
812 BOOL Ret = TRUE;
813
814 pi = GetW32ProcessInfo();
815
816 /* Check all local classes */
817 IntCheckDesktopClasses(Desktop,
818 &pi->pclsPrivateList,
819 FreeOnFailure,
820 &Ret);
821
822 /* Check all global classes */
823 IntCheckDesktopClasses(Desktop,
824 &pi->pclsPublicList,
825 FreeOnFailure,
826 &Ret);
827 if (!Ret)
828 {
829 ERR("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
830 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
831 }
832
833 return Ret;
834 }
835
836 PCLS
837 FASTCALL
838 IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
839 IN PUNICODE_STRING ClassName,
840 IN PUNICODE_STRING MenuName,
841 IN DWORD fnID,
842 IN DWORD dwFlags,
843 IN PDESKTOP Desktop,
844 IN PPROCESSINFO pi)
845 {
846 SIZE_T ClassSize;
847 PCLS Class = NULL;
848 RTL_ATOM Atom;
849 WNDPROC WndProc;
850 PWSTR pszMenuName = NULL;
851 NTSTATUS Status = STATUS_SUCCESS;
852
853 TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ dwFlags=%08x Desktop=%p pi=%p\n",
854 lpwcx, ClassName, MenuName, dwFlags, Desktop, pi);
855
856 if (!IntRegisterClassAtom(ClassName,
857 &Atom))
858 {
859 ERR("Failed to register class atom!\n");
860 return NULL;
861 }
862
863 ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
864 if (MenuName->Length != 0)
865 {
866 pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
867 RtlUnicodeStringToAnsiSize(MenuName));
868 if (pszMenuName == NULL)
869 goto NoMem;
870 }
871
872 if (Desktop != NULL)
873 {
874 Class = DesktopHeapAlloc(Desktop,
875 ClassSize);
876 }
877 else
878 {
879 /* FIXME: The class was created before being connected
880 to a desktop. It is possible for the desktop window,
881 but should it be allowed for any other case? */
882 Class = UserHeapAlloc(ClassSize);
883 }
884
885 if (Class != NULL)
886 {
887 int iCls = 0;
888
889 RtlZeroMemory(Class, ClassSize);
890
891 Class->rpdeskParent = Desktop;
892 Class->pclsBase = Class;
893 Class->atomClassName = Atom;
894 Class->fnid = fnID;
895 Class->CSF_flags = dwFlags;
896
897 if (LookupFnIdToiCls(Class->fnid, &iCls))
898 {
899 gpsi->atomSysClass[iCls] = Class->atomClassName;
900 }
901
902 _SEH2_TRY
903 {
904 PWSTR pszMenuNameBuffer = pszMenuName;
905
906 /* Need to protect with SEH since accessing the WNDCLASSEX structure
907 and string buffers might raise an exception! We don't want to
908 leak memory... */
909 // What?! If the user interface was written correctly this would not be an issue!
910 Class->lpfnWndProc = lpwcx->lpfnWndProc;
911 Class->style = lpwcx->style;
912 Class->cbclsExtra = lpwcx->cbClsExtra;
913 Class->cbwndExtra = lpwcx->cbWndExtra;
914 Class->hModule = lpwcx->hInstance;
915 Class->hIcon = lpwcx->hIcon; /* FIXME */
916 Class->hIconSm = lpwcx->hIconSm; /* FIXME */
917 Class->hCursor = lpwcx->hCursor; /* FIXME */
918 Class->hbrBackground = lpwcx->hbrBackground;
919
920 /* Make a copy of the string */
921 if (pszMenuNameBuffer != NULL)
922 {
923 Class->MenuNameIsString = TRUE;
924
925 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
926 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
927 MenuName->Buffer,
928 MenuName->Length);
929 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
930
931 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
932 }
933 else
934 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
935
936 /* Save an ANSI copy of the string */
937 if (pszMenuNameBuffer != NULL)
938 {
939 ANSI_STRING AnsiString;
940
941 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
942 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName);
943 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
944 Status = RtlUnicodeStringToAnsiString(&AnsiString,
945 MenuName,
946 FALSE);
947 if (!NT_SUCCESS(Status))
948 {
949 ERR("Failed to convert unicode menu name to ansi!\n");
950
951 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
952 _SEH2_LEAVE;
953 }
954 }
955 else
956 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
957
958 /* Save kernel use menu name and ansi class name */
959 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // FIXME!
960 //Class->lpszAnsiClassName = FIXME
961
962 /* Server Side overrides class calling type (A/W)!
963 User32 whine test_builtinproc: "deftest"
964 built-in winproc - window A/W type automatically detected */
965 if (!(Class->CSF_flags & CSF_SERVERSIDEPROC))
966 {
967 int i;
968 WndProc = NULL;
969 /* Due to the wine class "deftest" and most likely no FNID to reference
970 from, sort through the Server Side list and compare proc addresses
971 for match. This method will be used in related code.
972 */
973 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
974 { // Open ANSI or Unicode, just match, set and break.
975 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
976 {
977 WndProc = GETPFNSERVER(i);
978 break;
979 }
980 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
981 {
982 WndProc = GETPFNSERVER(i);
983 break;
984 }
985 }
986 if (WndProc)
987 { // If a hit, we are Server Side so set the right flags and proc.
988 Class->CSF_flags |= CSF_SERVERSIDEPROC;
989 Class->CSF_flags &= ~CSF_ANSIPROC;
990 Class->lpfnWndProc = WndProc;
991 }
992 }
993
994 if (!(Class->CSF_flags & CSF_ANSIPROC))
995 Class->Unicode = TRUE;
996
997 if (Class->style & CS_GLOBALCLASS)
998 Class->Global = TRUE;
999 }
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1001 {
1002 Status = _SEH2_GetExceptionCode();
1003 }
1004 _SEH2_END;
1005
1006 if (!NT_SUCCESS(Status))
1007 {
1008 ERR("Failed creating the class: 0x%x\n", Status);
1009
1010 SetLastNtError(Status);
1011
1012 if (pszMenuName != NULL)
1013 UserHeapFree(pszMenuName);
1014
1015 DesktopHeapFree(Desktop,
1016 Class);
1017 Class = NULL;
1018
1019 IntDeregisterClassAtom(Atom);
1020 }
1021 }
1022 else
1023 {
1024 NoMem:
1025 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop);
1026
1027 if (pszMenuName != NULL)
1028 UserHeapFree(pszMenuName);
1029
1030 IntDeregisterClassAtom(Atom);
1031
1032 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1033 }
1034
1035 TRACE("Created class 0x%x with name %wZ and proc 0x%x for atom 0x%x and hInstance 0x%x, global %d\n",
1036 Class, ClassName, Class->lpfnWndProc, Atom, Class->hModule, Class->Global);
1037
1038 return Class;
1039 }
1040
1041 static PCLS
1042 IntFindClass(IN RTL_ATOM Atom,
1043 IN HINSTANCE hInstance,
1044 IN PCLS *ClassList,
1045 OUT PCLS **Link OPTIONAL)
1046 {
1047 PCLS Class, *PrevLink = ClassList;
1048
1049 Class = *PrevLink;
1050 while (Class != NULL)
1051 {
1052 if (Class->atomClassName == Atom &&
1053 (hInstance == NULL || Class->hModule == hInstance) &&
1054 !(Class->CSF_flags & CSF_WOWDEFERDESTROY))
1055 {
1056 ASSERT(Class->pclsBase == Class);
1057
1058 if (Link != NULL)
1059 *Link = PrevLink;
1060 break;
1061 }
1062
1063 PrevLink = &Class->pclsNext;
1064 Class = Class->pclsNext;
1065 }
1066
1067 return Class;
1068 }
1069
1070 BOOL
1071 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
1072 OUT RTL_ATOM *Atom)
1073 {
1074 BOOL Ret = FALSE;
1075
1076 if (ClassName->Length != 0)
1077 {
1078 WCHAR szBuf[65];
1079 PWSTR AtomName;
1080 NTSTATUS Status;
1081
1082 /* NOTE: Caller has to protect the call with SEH! */
1083
1084 if (ClassName->Length != 0)
1085 {
1086 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1087 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
1088 {
1089 EngSetLastError(ERROR_INVALID_PARAMETER);
1090 return (RTL_ATOM)0;
1091 }
1092
1093 /* We need to make a local copy of the class name! The caller could
1094 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1095 We're protected by SEH, but the ranges that might be accessed were
1096 not probed... */
1097 RtlCopyMemory(szBuf,
1098 ClassName->Buffer,
1099 ClassName->Length);
1100 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1101 AtomName = szBuf;
1102 }
1103 else
1104 AtomName = ClassName->Buffer;
1105
1106 /* Lookup the atom */
1107 Status = RtlLookupAtomInAtomTable(gAtomTable,
1108 AtomName,
1109 Atom);
1110 if (NT_SUCCESS(Status))
1111 {
1112 Ret = TRUE;
1113 }
1114 else
1115 {
1116 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1117 {
1118 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1119 }
1120 else
1121 {
1122 SetLastNtError(Status);
1123 }
1124 }
1125 }
1126 else
1127 {
1128 ASSERT(IS_ATOM(ClassName->Buffer));
1129 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1130 Ret = TRUE;
1131 }
1132
1133 return Ret;
1134 }
1135
1136 RTL_ATOM
1137 IntGetClassAtom(IN PUNICODE_STRING ClassName,
1138 IN HINSTANCE hInstance OPTIONAL,
1139 IN PPROCESSINFO pi OPTIONAL,
1140 OUT PCLS *BaseClass OPTIONAL,
1141 OUT PCLS **Link OPTIONAL)
1142 {
1143 RTL_ATOM Atom = (RTL_ATOM)0;
1144
1145 ASSERT(BaseClass != NULL);
1146
1147 if (IntGetAtomFromStringOrAtom(ClassName,
1148 &Atom) &&
1149 Atom != (RTL_ATOM)0)
1150 {
1151 PCLS Class;
1152
1153 /* Attempt to locate the class object */
1154
1155 ASSERT(pi != NULL);
1156
1157 /* Step 1: Try to find an exact match of locally registered classes */
1158 Class = IntFindClass(Atom,
1159 hInstance,
1160 &pi->pclsPrivateList,
1161 Link);
1162 if (Class != NULL)
1163 { TRACE("Step 1: 0x%x\n",Class );
1164 goto FoundClass;
1165 }
1166
1167 /* Step 2: Try to find any globally registered class. The hInstance
1168 is not relevant for global classes */
1169 Class = IntFindClass(Atom,
1170 NULL,
1171 &pi->pclsPublicList,
1172 Link);
1173 if (Class != NULL)
1174 { TRACE("Step 2: 0x%x 0x%x\n",Class, Class->hModule);
1175 goto FoundClass;
1176 }
1177
1178 /* Step 3: Try to find any local class registered by user32 */
1179 Class = IntFindClass(Atom,
1180 hModClient,
1181 &pi->pclsPrivateList,
1182 Link);
1183 if (Class != NULL)
1184 { TRACE("Step 3: 0x%x\n",Class );
1185 goto FoundClass;
1186 }
1187
1188 /* Step 4: Try to find any global class registered by user32 */
1189 Class = IntFindClass(Atom,
1190 hModClient,
1191 &pi->pclsPublicList,
1192 Link);
1193 if (Class == NULL)
1194 {
1195 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1196 return (RTL_ATOM)0;
1197 }else{TRACE("Step 4: 0x%x\n",Class );}
1198
1199 FoundClass:
1200 *BaseClass = Class;
1201 }
1202
1203 return Atom;
1204 }
1205
1206 PCLS
1207 IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance)
1208 {
1209 PCLS *ClassLink, Class = NULL;
1210 RTL_ATOM ClassAtom;
1211 PTHREADINFO pti;
1212
1213 pti = PsGetCurrentThreadWin32Thread();
1214
1215 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1216 {
1217 UserRegisterSystemClasses();
1218 }
1219
1220 /* Check the class. */
1221
1222 TRACE("Finding Class %wZ for hInstance 0x%x\n", ClassName, hInstance);
1223
1224 ClassAtom = IntGetClassAtom(ClassName,
1225 hInstance,
1226 pti->ppi,
1227 &Class,
1228 &ClassLink);
1229
1230 if (ClassAtom == (RTL_ATOM)0)
1231 {
1232 if (IS_ATOM(ClassName->Buffer))
1233 {
1234 ERR("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
1235 }
1236 else
1237 {
1238 ERR("Class \"%wZ\" not found\n", ClassName);
1239 }
1240
1241 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
1242 return NULL;
1243 }
1244
1245 TRACE("Referencing Class 0x%x with atom 0x%x\n", Class, ClassAtom);
1246 Class = IntReferenceClass(Class,
1247 ClassLink,
1248 pti->rpdesk);
1249 if (Class == NULL)
1250 {
1251 ERR("Failed to reference window class!\n");
1252 return NULL;
1253 }
1254
1255 return Class;
1256 }
1257
1258 RTL_ATOM
1259 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1260 IN PUNICODE_STRING ClassName,
1261 IN PUNICODE_STRING MenuName,
1262 IN DWORD fnID,
1263 IN DWORD dwFlags)
1264 {
1265 PTHREADINFO pti;
1266 PPROCESSINFO pi;
1267 PCLS Class;
1268 RTL_ATOM ClassAtom;
1269 RTL_ATOM Ret = (RTL_ATOM)0;
1270
1271 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1272
1273 pti = GetW32ThreadInfo();
1274
1275 pi = pti->ppi;
1276
1277 // Need only to test for two conditions not four....... Fix more whine tests....
1278 if ( IntGetAtomFromStringOrAtom( ClassName, &ClassAtom) &&
1279 ClassAtom != (RTL_ATOM)0 &&
1280 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
1281 {
1282 Class = IntFindClass( ClassAtom,
1283 lpwcx->hInstance,
1284 &pi->pclsPrivateList,
1285 NULL);
1286
1287 if (Class != NULL && !Class->Global)
1288 {
1289 // Local class already exists
1290 TRACE("Local Class 0x%p does already exist!\n", ClassAtom);
1291 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1292 return (RTL_ATOM)0;
1293 }
1294
1295 if (lpwcx->style & CS_GLOBALCLASS)
1296 {
1297 Class = IntFindClass( ClassAtom,
1298 NULL,
1299 &pi->pclsPublicList,
1300 NULL);
1301
1302 if (Class != NULL && Class->Global)
1303 {
1304 TRACE("Global Class 0x%p does already exist!\n", ClassAtom);
1305 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1306 return (RTL_ATOM)0;
1307 }
1308 }
1309 }
1310
1311 Class = IntCreateClass(lpwcx,
1312 ClassName,
1313 MenuName,
1314 fnID,
1315 dwFlags,
1316 pti->rpdesk,
1317 pi);
1318
1319 if (Class != NULL)
1320 {
1321 PCLS *List;
1322
1323 /* Register the class */
1324 if (Class->Global)
1325 List = &pi->pclsPublicList;
1326 else
1327 List = &pi->pclsPrivateList;
1328
1329 Class->pclsNext = *List;
1330 (void)InterlockedExchangePointer((PVOID*)List,
1331 Class);
1332
1333 Ret = Class->atomClassName;
1334 }
1335 else
1336 {
1337 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1338 }
1339
1340 return Ret;
1341 }
1342
1343 BOOL
1344 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1345 IN HINSTANCE hInstance,
1346 OUT PCLSMENUNAME pClassMenuName)
1347 {
1348 PCLS *Link;
1349 PPROCESSINFO pi;
1350 RTL_ATOM ClassAtom;
1351 PCLS Class;
1352
1353 pi = GetW32ProcessInfo();
1354
1355 TRACE("UserUnregisterClass(%wZ, 0x%x)\n", ClassName, hInstance);
1356
1357 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1358 ClassAtom = IntGetClassAtom(ClassName,
1359 hInstance,
1360 pi,
1361 &Class,
1362 &Link);
1363 if (ClassAtom == (RTL_ATOM)0)
1364 {
1365 TRACE("UserUnregisterClass: No Class found.\n");
1366 return FALSE;
1367 }
1368
1369 ASSERT(Class != NULL);
1370
1371 if (Class->cWndReferenceCount != 0 ||
1372 Class->pclsClone != NULL)
1373 {
1374 TRACE("UserUnregisterClass: Class has a Window. Ct %d : Clone 0x%x\n", Class->cWndReferenceCount, Class->pclsClone);
1375 EngSetLastError(ERROR_CLASS_HAS_WINDOWS);
1376 return FALSE;
1377 }
1378
1379 /* Must be a base class! */
1380 ASSERT(Class->pclsBase == Class);
1381
1382 /* Unlink the class */
1383 *Link = Class->pclsNext;
1384
1385 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1386 {
1387 TRACE("Class 0x%x\n", Class);
1388 TRACE("UserUnregisterClass: Good Exit!\n");
1389 /* Finally free the resources */
1390 IntDestroyClass(Class);
1391 return TRUE;
1392 }
1393 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1394 return FALSE;
1395 }
1396
1397 INT
1398 UserGetClassName(IN PCLS Class,
1399 IN OUT PUNICODE_STRING ClassName,
1400 IN RTL_ATOM Atom,
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 Atom ? Atom : 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 Atom ? Atom : 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 = (USHORT)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 ERR("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 (((ULONG)Index + sizeof(ULONG_PTR)) < (ULONG)Index ||
1641 ((ULONG)Index + sizeof(ULONG_PTR)) > (ULONG)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 ERR("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 ERR("!!! 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 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
1985 EngSetLastError(ERROR_INVALID_FLAGS);
1986 return Ret;
1987 }
1988
1989 UserEnterExclusive();
1990
1991 TRACE("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 ERR("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 + CapturedName.Length +
2026 CapturedMenuName.Length + sizeof(CLS))
2027 < (ULONG)CapturedClassInfo.cbClsExtra) ||
2028 (CapturedClassInfo.cbWndExtra < 0) ||
2029 (CapturedClassInfo.hInstance == NULL) )
2030 {
2031 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2032 goto InvalidParameter;
2033 }
2034
2035 if (CapturedName.Length != 0)
2036 {
2037 ProbeForRead(CapturedName.Buffer,
2038 CapturedName.Length,
2039 sizeof(WCHAR));
2040 }
2041 else
2042 {
2043 if (!IS_ATOM(CapturedName.Buffer))
2044 {
2045 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2046 goto InvalidParameter;
2047 }
2048 }
2049
2050 if (CapturedMenuName.Length != 0)
2051 {
2052 ProbeForRead(CapturedMenuName.Buffer,
2053 CapturedMenuName.Length,
2054 sizeof(WCHAR));
2055 }
2056 else if (CapturedMenuName.Buffer != NULL &&
2057 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2058 {
2059 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2060 InvalidParameter:
2061 EngSetLastError(ERROR_INVALID_PARAMETER);
2062 _SEH2_LEAVE;
2063 }
2064
2065 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2066 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2067 // If this pops up we know what todo!
2068 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2069 }
2070
2071 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2072
2073 /* Register the class */
2074 Ret = UserRegisterClass(&CapturedClassInfo,
2075 &CapturedName,
2076 &CapturedMenuName,
2077 fnID,
2078 Flags);
2079 }
2080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2081 {
2082 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2083 SetLastNtError(_SEH2_GetExceptionCode());
2084 }
2085 _SEH2_END;
2086 /*
2087 if (!Ret)
2088 {
2089 ERR("NtUserRegisterClassExWOW Null Return!\n");
2090 }
2091 */
2092 UserLeave();
2093
2094 return Ret;
2095 }
2096
2097 ULONG_PTR APIENTRY
2098 NtUserSetClassLong(HWND hWnd,
2099 INT Offset,
2100 ULONG_PTR dwNewLong,
2101 BOOL Ansi)
2102 {
2103 PPROCESSINFO pi;
2104 PWND Window;
2105 ULONG_PTR Ret = 0;
2106
2107 UserEnterExclusive();
2108
2109 pi = GetW32ProcessInfo();
2110
2111 Window = UserGetWindowObject(hWnd);
2112 if (Window != NULL)
2113 {
2114 if (Window->head.pti->ppi != pi)
2115 {
2116 EngSetLastError(ERROR_ACCESS_DENIED);
2117 goto Cleanup;
2118 }
2119
2120 _SEH2_TRY
2121 {
2122 UNICODE_STRING Value;
2123
2124 /* Probe the parameters */
2125 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2126 {
2127 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2128 if (Value.Length & 1)
2129 {
2130 goto InvalidParameter;
2131 }
2132
2133 if (Value.Length != 0)
2134 {
2135 ProbeForRead(Value.Buffer,
2136 Value.Length,
2137 sizeof(WCHAR));
2138 }
2139 else
2140 {
2141 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2142 {
2143 goto InvalidParameter;
2144 }
2145 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2146 {
2147 InvalidParameter:
2148 EngSetLastError(ERROR_INVALID_PARAMETER);
2149 _SEH2_LEAVE;
2150 }
2151 }
2152
2153 dwNewLong = (ULONG_PTR)&Value;
2154 }
2155
2156 Ret = UserSetClassLongPtr(Window->pcls,
2157 Offset,
2158 dwNewLong,
2159 Ansi);
2160 }
2161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2162 {
2163 SetLastNtError(_SEH2_GetExceptionCode());
2164 }
2165 _SEH2_END;
2166 }
2167
2168 Cleanup:
2169 UserLeave();
2170
2171 return Ret;
2172 }
2173
2174 WORD
2175 APIENTRY
2176 NtUserSetClassWord(
2177 HWND hWnd,
2178 INT nIndex,
2179 WORD wNewWord)
2180 {
2181 /*
2182 * NOTE: Obsoleted in 32-bit windows
2183 */
2184 return(0);
2185 }
2186
2187 BOOL APIENTRY
2188 NtUserUnregisterClass(IN PUNICODE_STRING ClassNameOrAtom,
2189 IN HINSTANCE hInstance,
2190 OUT PCLSMENUNAME pClassMenuName)
2191 {
2192 UNICODE_STRING CapturedClassName;
2193 BOOL Ret = FALSE;
2194
2195 UserEnterExclusive();
2196
2197 _SEH2_TRY
2198 {
2199 /* Probe the paramters */
2200 CapturedClassName = ProbeForReadUnicodeString(ClassNameOrAtom);
2201 if (CapturedClassName.Length & 1)
2202 {
2203 goto InvalidParameter;
2204 }
2205
2206 if (CapturedClassName.Length != 0)
2207 {
2208 ProbeForRead(CapturedClassName.Buffer,
2209 CapturedClassName.Length,
2210 sizeof(WCHAR));
2211 }
2212 else
2213 {
2214 if (!IS_ATOM(CapturedClassName.Buffer))
2215 {
2216 InvalidParameter:
2217 EngSetLastError(ERROR_INVALID_PARAMETER);
2218 _SEH2_LEAVE;
2219 }
2220 }
2221
2222 /* Unregister the class */
2223 Ret = UserUnregisterClass(&CapturedClassName,
2224 hInstance,
2225 NULL); // Null for now~
2226 }
2227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2228 {
2229 SetLastNtError(_SEH2_GetExceptionCode());
2230 }
2231 _SEH2_END;
2232
2233 UserLeave();
2234 return Ret;
2235 }
2236
2237 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2238 BOOL APIENTRY
2239 NtUserGetClassInfo(
2240 HINSTANCE hInstance,
2241 PUNICODE_STRING ClassName,
2242 LPWNDCLASSEXW lpWndClassEx,
2243 LPWSTR *ppszMenuName,
2244 BOOL Ansi)
2245 {
2246 UNICODE_STRING CapturedClassName, SafeClassName;
2247 WNDCLASSEXW Safewcexw;
2248 PCLS Class;
2249 RTL_ATOM ClassAtom = 0;
2250 PPROCESSINFO ppi;
2251 BOOL Ret = TRUE;
2252
2253 /* NOTE: Need exclusive lock because getting the wndproc might require the
2254 creation of a call procedure handle */
2255 UserEnterExclusive();
2256
2257 ppi = GetW32ProcessInfo();
2258
2259 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2260 {
2261 UserRegisterSystemClasses();
2262 }
2263
2264 _SEH2_TRY
2265 {
2266 /* Probe the paramters */
2267 CapturedClassName = ProbeForReadUnicodeString(ClassName);
2268
2269 if (CapturedClassName.Length == 0)
2270 {
2271 TRACE("hInst %p atom %04X lpWndClassEx %p Ansi %d\n", hInstance, CapturedClassName.Buffer, lpWndClassEx, Ansi);
2272 }
2273 else
2274 {
2275 TRACE("hInst %p class %wZ lpWndClassEx %p Ansi %d\n", hInstance, &CapturedClassName, lpWndClassEx, Ansi);
2276 }
2277
2278 if (CapturedClassName.Length & 1)
2279 {
2280 EngSetLastError(ERROR_INVALID_PARAMETER);
2281 Ret = FALSE;
2282 _SEH2_LEAVE;
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 EngSetLastError(ERROR_INVALID_PARAMETER);
2306 Ret = FALSE;
2307 _SEH2_LEAVE;
2308 }
2309
2310 SafeClassName.Buffer = CapturedClassName.Buffer;
2311 SafeClassName.Length = 0;
2312 SafeClassName.MaximumLength = 0;
2313 }
2314
2315 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2316
2317 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2318 }
2319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2320 {
2321 SetLastNtError(_SEH2_GetExceptionCode());
2322 Ret = FALSE;
2323 }
2324 _SEH2_END;
2325
2326 // If null instance use client.
2327 if (!hInstance) hInstance = hModClient;
2328
2329 if (Ret)
2330 {
2331 TRACE("GetClassInfo(%wZ, 0x%x)\n", SafeClassName, hInstance);
2332 ClassAtom = IntGetClassAtom( &SafeClassName,
2333 hInstance,
2334 ppi,
2335 &Class,
2336 NULL);
2337 if (ClassAtom != (RTL_ATOM)0)
2338 {
2339 if (hInstance == NULL) hInstance = hModClient;
2340
2341 Ret = UserGetClassInfo( Class,
2342 &Safewcexw,
2343 Ansi,
2344 hInstance);
2345 }
2346 else
2347 {
2348 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2349 Ret = FALSE;
2350 }
2351 }
2352 _SEH2_TRY
2353 {
2354 if (Ret)
2355 {
2356 /* Emulate Function. */
2357 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2358
2359 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2360
2361 // From Wine:
2362 /* We must return the atom of the class here instead of just TRUE. */
2363 /* Undocumented behavior! Return the class atom as a BOOL! */
2364 Ret = (BOOL)ClassAtom;
2365 }
2366 }
2367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2368 {
2369 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2370 Ret = FALSE;
2371 }
2372 _SEH2_END;
2373
2374 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2375 UserLeave();
2376 return Ret;
2377 }
2378
2379
2380 INT APIENTRY
2381 NtUserGetClassName (IN HWND hWnd,
2382 IN BOOL Real,
2383 OUT PUNICODE_STRING ClassName)
2384 {
2385 PWND Window;
2386 UNICODE_STRING CapturedClassName;
2387 INT iCls, Ret = 0;
2388 RTL_ATOM Atom = 0;
2389
2390 UserEnterShared();
2391
2392 Window = UserGetWindowObject(hWnd);
2393 if (Window != NULL)
2394 {
2395 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY))
2396 {
2397 if (LookupFnIdToiCls(Window->fnid, &iCls))
2398 {
2399 Atom = gpsi->atomSysClass[iCls];
2400 }
2401 }
2402
2403 _SEH2_TRY
2404 {
2405 ProbeForWriteUnicodeString(ClassName);
2406 CapturedClassName = *ClassName;
2407
2408 /* Get the class name */
2409 Ret = UserGetClassName(Window->pcls,
2410 &CapturedClassName,
2411 Atom,
2412 FALSE);
2413
2414 if (Ret != 0)
2415 {
2416 /* Update the Length field */
2417 ClassName->Length = CapturedClassName.Length;
2418 }
2419 }
2420 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2421 {
2422 SetLastNtError(_SEH2_GetExceptionCode());
2423 }
2424 _SEH2_END;
2425 }
2426
2427 UserLeave();
2428
2429 return Ret;
2430 }
2431
2432 /* Return Pointer to Class structure. */
2433 PCLS APIENTRY
2434 NtUserGetWOWClass(HINSTANCE hInstance,
2435 PUNICODE_STRING ClassName)
2436 {
2437 UNICODE_STRING SafeClassName;
2438 PPROCESSINFO pi;
2439 PCLS Class = NULL;
2440 RTL_ATOM ClassAtom = 0;
2441 BOOL Hit = FALSE;
2442
2443 UserEnterExclusive();
2444
2445 pi = GetW32ProcessInfo();
2446
2447 _SEH2_TRY
2448 {
2449 if (ClassName->Length != 0)
2450 {
2451 ProbeForRead( ClassName->Buffer,
2452 ClassName->Length,
2453 sizeof(WCHAR));
2454
2455 RtlInitUnicodeString( &SafeClassName, ClassName->Buffer);
2456
2457 SafeClassName.Buffer = ExAllocatePoolWithTag( PagedPool,
2458 SafeClassName.MaximumLength,
2459 TAG_STRING);
2460 RtlCopyMemory( SafeClassName.Buffer,
2461 ClassName->Buffer,
2462 SafeClassName.MaximumLength);
2463 }
2464 else
2465 {
2466 if (!IS_ATOM(ClassName->Buffer))
2467 {
2468 ERR("NtUserGetWOWClass() got ClassName instead of Atom!\n");
2469 Hit = TRUE;
2470 }
2471 else
2472 {
2473 SafeClassName.Buffer = ClassName->Buffer;
2474 SafeClassName.Length = 0;
2475 SafeClassName.MaximumLength = 0;
2476 }
2477 }
2478 }
2479 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2480 {
2481 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2482 Hit = TRUE;
2483 }
2484 _SEH2_END;
2485
2486 if (!Hit)
2487 {
2488 ClassAtom = IntGetClassAtom( &SafeClassName,
2489 hInstance,
2490 pi,
2491 &Class,
2492 NULL);
2493 if (!ClassAtom)
2494 {
2495 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2496 }
2497 }
2498
2499 if (SafeClassName.Length) ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2500 UserLeave();
2501 //
2502 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2503 //
2504 return Class;
2505 }
2506
2507 /* EOF */