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