c950494699308f52e5b17bde03e26634d34b91d0
[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 //// FIXME handles to pointers
1001 Class->hIcon = lpwcx->hIcon;
1002 Class->hIconSm = lpwcx->hIconSm;
1003 Class->hCursor = lpwcx->hCursor;
1004 ////
1005 Class->hbrBackground = lpwcx->hbrBackground;
1006
1007 /* Make a copy of the string */
1008 if (pszMenuNameBuffer != NULL)
1009 {
1010 Class->MenuNameIsString = TRUE;
1011
1012 Class->lpszClientUnicodeMenuName = pszMenuNameBuffer;
1013 RtlCopyMemory(Class->lpszClientUnicodeMenuName,
1014 MenuName->Buffer,
1015 MenuName->Length);
1016 Class->lpszClientUnicodeMenuName[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1017
1018 pszMenuNameBuffer += (MenuName->Length / sizeof(WCHAR)) + 1;
1019 }
1020 else
1021 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1022
1023 /* Save an ANSI copy of the string */
1024 if (pszMenuNameBuffer != NULL)
1025 {
1026 ANSI_STRING AnsiString;
1027
1028 Class->lpszClientAnsiMenuName = (PSTR)pszMenuNameBuffer;
1029 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName);
1030 AnsiString.Buffer = Class->lpszClientAnsiMenuName;
1031 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1032 MenuName,
1033 FALSE);
1034 if (!NT_SUCCESS(Status))
1035 {
1036 ERR("Failed to convert unicode menu name to ansi!\n");
1037
1038 /* Life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
1039 _SEH2_LEAVE;
1040 }
1041 }
1042 else
1043 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1044
1045 /* Save kernel use menu name and ansi class name */
1046 Class->lpszMenuName = Class->lpszClientUnicodeMenuName; // FIXME!
1047 //Class->lpszAnsiClassName = FIXME
1048
1049 /* Server Side overrides class calling type (A/W)!
1050 User32 whine test_builtinproc: "deftest"
1051 built-in winproc - window A/W type automatically detected */
1052 if (!(Class->CSF_flags & CSF_SERVERSIDEPROC))
1053 {
1054 int i;
1055 WndProc = NULL;
1056 /* Due to the wine class "deftest" and most likely no FNID to reference
1057 from, sort through the Server Side list and compare proc addresses
1058 for match. This method will be used in related code.
1059 */
1060 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
1061 { // Open ANSI or Unicode, just match, set and break.
1062 if (GETPFNCLIENTW(i) == Class->lpfnWndProc)
1063 {
1064 WndProc = GETPFNSERVER(i);
1065 break;
1066 }
1067 if (GETPFNCLIENTA(i) == Class->lpfnWndProc)
1068 {
1069 WndProc = GETPFNSERVER(i);
1070 break;
1071 }
1072 }
1073 if (WndProc)
1074 { // If a hit, we are Server Side so set the right flags and proc.
1075 Class->CSF_flags |= CSF_SERVERSIDEPROC;
1076 Class->CSF_flags &= ~CSF_ANSIPROC;
1077 Class->lpfnWndProc = WndProc;
1078 }
1079 }
1080
1081 if (!(Class->CSF_flags & CSF_ANSIPROC))
1082 Class->Unicode = TRUE;
1083
1084 if (Class->style & CS_GLOBALCLASS)
1085 Class->Global = TRUE;
1086 }
1087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1088 {
1089 Status = _SEH2_GetExceptionCode();
1090 }
1091 _SEH2_END;
1092
1093 if (!NT_SUCCESS(Status))
1094 {
1095 ERR("Failed creating the class: 0x%x\n", Status);
1096
1097 SetLastNtError(Status);
1098
1099 if (pszMenuName != NULL)
1100 UserHeapFree(pszMenuName);
1101
1102 DesktopHeapFree(Desktop,
1103 Class);
1104 Class = NULL;
1105
1106 IntDeregisterClassAtom(Atom);
1107 }
1108 }
1109 else
1110 {
1111 NoMem:
1112 ERR("Failed to allocate class on Desktop 0x%p\n", Desktop);
1113
1114 if (pszMenuName != NULL)
1115 UserHeapFree(pszMenuName);
1116
1117 IntDeregisterClassAtom(Atom);
1118
1119 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1120 }
1121
1122 TRACE("Created class 0x%p with name %wZ and proc 0x%p for atom 0x%x and hInstance 0x%p, global %u\n",
1123 Class, ClassName, Class->lpfnWndProc, Atom, Class->hModule, Class->Global);
1124
1125 return Class;
1126 }
1127
1128 static PCLS
1129 IntFindClass(IN RTL_ATOM Atom,
1130 IN HINSTANCE hInstance,
1131 IN PCLS *ClassList,
1132 OUT PCLS **Link OPTIONAL)
1133 {
1134 PCLS Class, *PrevLink = ClassList;
1135
1136 Class = *PrevLink;
1137 while (Class != NULL)
1138 {
1139 if (Class->atomClassName == Atom &&
1140 (hInstance == NULL || Class->hModule == hInstance) &&
1141 !(Class->CSF_flags & CSF_WOWDEFERDESTROY))
1142 {
1143 ASSERT(Class->pclsBase == Class);
1144
1145 if (Link != NULL)
1146 *Link = PrevLink;
1147 break;
1148 }
1149
1150 PrevLink = &Class->pclsNext;
1151 Class = Class->pclsNext;
1152 }
1153
1154 return Class;
1155 }
1156
1157 BOOL
1158 NTAPI
1159 IntGetAtomFromStringOrAtom(
1160 _In_ PUNICODE_STRING ClassName,
1161 _Out_ RTL_ATOM *Atom)
1162 {
1163 BOOL Ret = FALSE;
1164
1165 if (ClassName->Length != 0)
1166 {
1167 WCHAR szBuf[65];
1168 PWSTR AtomName;
1169 NTSTATUS Status;
1170
1171 *Atom = 0;
1172
1173 /* NOTE: Caller has to protect the call with SEH! */
1174
1175 if (ClassName->Length != 0)
1176 {
1177 /* FIXME: Don't limit to 64 characters! use SEH when allocating memory! */
1178 if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
1179 {
1180 EngSetLastError(ERROR_INVALID_PARAMETER);
1181 return (RTL_ATOM)0;
1182 }
1183
1184 /* We need to make a local copy of the class name! The caller could
1185 modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
1186 We're protected by SEH, but the ranges that might be accessed were
1187 not probed... */
1188 RtlCopyMemory(szBuf,
1189 ClassName->Buffer,
1190 ClassName->Length);
1191 szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1192 AtomName = szBuf;
1193 }
1194 else
1195 AtomName = ClassName->Buffer;
1196
1197 /* Lookup the atom */
1198 Status = RtlLookupAtomInAtomTable(gAtomTable,
1199 AtomName,
1200 Atom);
1201 if (NT_SUCCESS(Status))
1202 {
1203 Ret = TRUE;
1204 }
1205 else
1206 {
1207 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1208 {
1209 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1210 }
1211 else
1212 {
1213 SetLastNtError(Status);
1214 }
1215 }
1216 }
1217 else
1218 {
1219 ASSERT(IS_ATOM(ClassName->Buffer));
1220 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
1221 Ret = TRUE;
1222 }
1223
1224 return Ret;
1225 }
1226
1227 RTL_ATOM
1228 IntGetClassAtom(
1229 _In_ PUNICODE_STRING ClassName,
1230 IN HINSTANCE hInstance OPTIONAL,
1231 IN PPROCESSINFO pi OPTIONAL,
1232 OUT PCLS *BaseClass OPTIONAL,
1233 OUT PCLS **Link OPTIONAL)
1234 {
1235 RTL_ATOM Atom = (RTL_ATOM)0;
1236
1237 ASSERT(BaseClass != NULL);
1238
1239 if (IntGetAtomFromStringOrAtom(ClassName,
1240 &Atom) &&
1241 Atom != (RTL_ATOM)0)
1242 {
1243 PCLS Class;
1244
1245 /* Attempt to locate the class object */
1246
1247 ASSERT(pi != NULL);
1248
1249 /* Step 1: Try to find an exact match of locally registered classes */
1250 Class = IntFindClass(Atom,
1251 hInstance,
1252 &pi->pclsPrivateList,
1253 Link);
1254 if (Class != NULL)
1255 { TRACE("Step 1: 0x%p\n",Class );
1256 goto FoundClass;
1257 }
1258
1259 /* Step 2: Try to find any globally registered class. The hInstance
1260 is not relevant for global classes */
1261 Class = IntFindClass(Atom,
1262 NULL,
1263 &pi->pclsPublicList,
1264 Link);
1265 if (Class != NULL)
1266 { TRACE("Step 2: 0x%p 0x%p\n",Class, Class->hModule);
1267 goto FoundClass;
1268 }
1269
1270 /* Step 3: Try to find any local class registered by user32 */
1271 Class = IntFindClass(Atom,
1272 hModClient,
1273 &pi->pclsPrivateList,
1274 Link);
1275 if (Class != NULL)
1276 { TRACE("Step 3: 0x%p\n",Class );
1277 goto FoundClass;
1278 }
1279
1280 /* Step 4: Try to find any global class registered by user32 */
1281 Class = IntFindClass(Atom,
1282 hModClient,
1283 &pi->pclsPublicList,
1284 Link);
1285 if (Class == NULL)
1286 {
1287 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
1288 return (RTL_ATOM)0;
1289 }else{TRACE("Step 4: 0x%p\n",Class );}
1290
1291 FoundClass:
1292 *BaseClass = Class;
1293 }
1294
1295 return Atom;
1296 }
1297
1298 PCLS
1299 IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance, BOOL bDesktopThread)
1300 {
1301 PCLS *ClassLink, Class = NULL;
1302 RTL_ATOM ClassAtom;
1303 PTHREADINFO pti;
1304
1305 if (bDesktopThread)
1306 pti = gptiDesktopThread;
1307 else
1308 pti = PsGetCurrentThreadWin32Thread();
1309
1310 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
1311 {
1312 UserRegisterSystemClasses();
1313 }
1314
1315 /* Check the class. */
1316
1317 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName, hInstance);
1318
1319 ClassAtom = IntGetClassAtom(ClassName,
1320 hInstance,
1321 pti->ppi,
1322 &Class,
1323 &ClassLink);
1324
1325 if (ClassAtom == (RTL_ATOM)0)
1326 {
1327 if (IS_ATOM(ClassName->Buffer))
1328 {
1329 ERR("Class 0x%p not found\n", ClassName->Buffer);
1330 }
1331 else
1332 {
1333 ERR("Class \"%wZ\" not found\n", ClassName);
1334 }
1335
1336 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
1337 return NULL;
1338 }
1339
1340 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class, ClassAtom);
1341 Class = IntReferenceClass(Class,
1342 ClassLink,
1343 pti->rpdesk);
1344 if (Class == NULL)
1345 {
1346 ERR("Failed to reference window class!\n");
1347 return NULL;
1348 }
1349
1350 return Class;
1351 }
1352
1353 RTL_ATOM
1354 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
1355 IN PUNICODE_STRING ClassName,
1356 IN PUNICODE_STRING MenuName,
1357 IN DWORD fnID,
1358 IN DWORD dwFlags)
1359 {
1360 PTHREADINFO pti;
1361 PPROCESSINFO pi;
1362 PCLS Class;
1363 RTL_ATOM ClassAtom;
1364 RTL_ATOM Ret = (RTL_ATOM)0;
1365
1366 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */
1367
1368 pti = GetW32ThreadInfo();
1369
1370 pi = pti->ppi;
1371
1372 // Need only to test for two conditions not four....... Fix more whine tests....
1373 if ( IntGetAtomFromStringOrAtom( ClassName, &ClassAtom) &&
1374 ClassAtom != (RTL_ATOM)0 &&
1375 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides
1376 {
1377 Class = IntFindClass( ClassAtom,
1378 lpwcx->hInstance,
1379 &pi->pclsPrivateList,
1380 NULL);
1381
1382 if (Class != NULL && !Class->Global)
1383 {
1384 // Local class already exists
1385 TRACE("Local Class 0x%x does already exist!\n", ClassAtom);
1386 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1387 return (RTL_ATOM)0;
1388 }
1389
1390 if (lpwcx->style & CS_GLOBALCLASS)
1391 {
1392 Class = IntFindClass( ClassAtom,
1393 NULL,
1394 &pi->pclsPublicList,
1395 NULL);
1396
1397 if (Class != NULL && Class->Global)
1398 {
1399 TRACE("Global Class 0x%x does already exist!\n", ClassAtom);
1400 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS);
1401 return (RTL_ATOM)0;
1402 }
1403 }
1404 }
1405
1406 Class = IntCreateClass(lpwcx,
1407 ClassName,
1408 MenuName,
1409 fnID,
1410 dwFlags,
1411 pti->rpdesk,
1412 pi);
1413
1414 if (Class != NULL)
1415 {
1416 PCLS *List;
1417
1418 /* Register the class */
1419 if (Class->Global)
1420 List = &pi->pclsPublicList;
1421 else
1422 List = &pi->pclsPrivateList;
1423
1424 Class->pclsNext = *List;
1425 (void)InterlockedExchangePointer((PVOID*)List,
1426 Class);
1427
1428 Ret = Class->atomClassName;
1429 }
1430 else
1431 {
1432 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n");
1433 }
1434
1435 return Ret;
1436 }
1437
1438 BOOL
1439 UserUnregisterClass(IN PUNICODE_STRING ClassName,
1440 IN HINSTANCE hInstance,
1441 OUT PCLSMENUNAME pClassMenuName)
1442 {
1443 PCLS *Link;
1444 PPROCESSINFO pi;
1445 RTL_ATOM ClassAtom;
1446 PCLS Class;
1447
1448 pi = GetW32ProcessInfo();
1449
1450 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName, hInstance);
1451
1452 /* NOTE: Accessing the buffer in ClassName may raise an exception! */
1453 ClassAtom = IntGetClassAtom(ClassName,
1454 hInstance,
1455 pi,
1456 &Class,
1457 &Link);
1458 if (ClassAtom == (RTL_ATOM)0)
1459 {
1460 TRACE("UserUnregisterClass: No Class found.\n");
1461 return FALSE;
1462 }
1463
1464 ASSERT(Class != NULL);
1465
1466 if (Class->cWndReferenceCount != 0 ||
1467 Class->pclsClone != NULL)
1468 {
1469 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class->cWndReferenceCount, Class->pclsClone);
1470 EngSetLastError(ERROR_CLASS_HAS_WINDOWS);
1471 return FALSE;
1472 }
1473
1474 /* Must be a base class! */
1475 ASSERT(Class->pclsBase == Class);
1476
1477 /* Unlink the class */
1478 *Link = Class->pclsNext;
1479
1480 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName)))
1481 {
1482 TRACE("Class 0x%p\n", Class);
1483 TRACE("UserUnregisterClass: Good Exit!\n");
1484 /* Finally free the resources */
1485 IntDestroyClass(Class);
1486 return TRUE;
1487 }
1488 ERR("UserUnregisterClass: Can not deregister Class Atom.\n");
1489 return FALSE;
1490 }
1491
1492 INT
1493 UserGetClassName(IN PCLS Class,
1494 IN OUT PUNICODE_STRING ClassName,
1495 IN RTL_ATOM Atom,
1496 IN BOOL Ansi)
1497 {
1498 NTSTATUS Status = STATUS_SUCCESS;
1499 WCHAR szStaticTemp[32];
1500 PWSTR szTemp = NULL;
1501 ULONG BufLen = sizeof(szStaticTemp);
1502 INT Ret = 0;
1503
1504 /* Note: Accessing the buffer in ClassName may raise an exception! */
1505
1506 _SEH2_TRY
1507 {
1508 if (Ansi)
1509 {
1510 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
1511 UNICODE_STRING UnicodeClassName;
1512
1513 /* Limit the size of the static buffer on the stack to the
1514 size of the buffer provided by the caller */
1515 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1516 {
1517 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1518 }
1519
1520 /* Find out how big the buffer needs to be */
1521 Status = RtlQueryAtomInAtomTable(gAtomTable,
1522 Class->atomClassName,
1523 NULL,
1524 NULL,
1525 szStaticTemp,
1526 &BufLen);
1527 if (Status == STATUS_BUFFER_TOO_SMALL)
1528 {
1529 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
1530 {
1531 /* The buffer required exceeds the ansi buffer provided,
1532 pretend like we're using the ansi buffer and limit the
1533 size to the buffer size provided */
1534 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
1535 }
1536
1537 /* Allocate a temporary buffer that can hold the unicode class name */
1538 szTemp = ExAllocatePoolWithTag(PagedPool,
1539 BufLen,
1540 USERTAG_CLASS);
1541 if (szTemp == NULL)
1542 {
1543 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1544 _SEH2_LEAVE;
1545 }
1546
1547 /* Query the class name */
1548 Status = RtlQueryAtomInAtomTable(gAtomTable,
1549 Atom ? Atom : Class->atomClassName,
1550 NULL,
1551 NULL,
1552 szTemp,
1553 &BufLen);
1554 }
1555 else
1556 szTemp = szStaticTemp;
1557
1558 if (NT_SUCCESS(Status))
1559 {
1560 /* Convert the atom name to ansi */
1561
1562 RtlInitUnicodeString(&UnicodeClassName,
1563 szTemp);
1564
1565 Status = RtlUnicodeStringToAnsiString(AnsiClassName,
1566 &UnicodeClassName,
1567 FALSE);
1568 if (!NT_SUCCESS(Status))
1569 {
1570 SetLastNtError(Status);
1571 _SEH2_LEAVE;
1572 }
1573 }
1574
1575 Ret = BufLen / sizeof(WCHAR);
1576 }
1577 else /* !ANSI */
1578 {
1579 BufLen = ClassName->MaximumLength;
1580
1581 /* Query the atom name */
1582 Status = RtlQueryAtomInAtomTable(gAtomTable,
1583 Atom ? Atom : Class->atomClassName,
1584 NULL,
1585 NULL,
1586 ClassName->Buffer,
1587 &BufLen);
1588
1589 if (!NT_SUCCESS(Status))
1590 {
1591 SetLastNtError(Status);
1592 _SEH2_LEAVE;
1593 }
1594
1595 Ret = BufLen / sizeof(WCHAR);
1596 }
1597 }
1598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1599 {
1600 SetLastNtError(_SEH2_GetExceptionCode());
1601 }
1602 _SEH2_END;
1603
1604 if (Ansi && szTemp != NULL && szTemp != szStaticTemp)
1605 {
1606 ExFreePoolWithTag(szTemp, USERTAG_CLASS);
1607 }
1608
1609 return Ret;
1610 }
1611
1612 static BOOL
1613 IntSetClassMenuName(IN PCLS Class,
1614 IN PUNICODE_STRING MenuName)
1615 {
1616 BOOL Ret = FALSE;
1617
1618 /* Change the base class first */
1619 Class = Class->pclsBase;
1620
1621 if (MenuName->Length != 0)
1622 {
1623 ANSI_STRING AnsiString;
1624 PWSTR strBufW;
1625
1626 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName);
1627
1628 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
1629 AnsiString.MaximumLength);
1630 if (strBufW != NULL)
1631 {
1632 _SEH2_TRY
1633 {
1634 NTSTATUS Status;
1635
1636 /* Copy the unicode string */
1637 RtlCopyMemory(strBufW,
1638 MenuName->Buffer,
1639 MenuName->Length);
1640 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1641
1642 /* Create an ANSI copy of the string */
1643 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1);
1644 Status = RtlUnicodeStringToAnsiString(&AnsiString,
1645 MenuName,
1646 FALSE);
1647 if (!NT_SUCCESS(Status))
1648 {
1649 SetLastNtError(Status);
1650 _SEH2_LEAVE;
1651 }
1652
1653 Ret = TRUE;
1654 }
1655 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1656 {
1657 SetLastNtError(_SEH2_GetExceptionCode());
1658 }
1659 _SEH2_END;
1660
1661 if (Ret)
1662 {
1663 /* Update the base class */
1664 IntFreeClassMenuName(Class);
1665 Class->lpszClientUnicodeMenuName = strBufW;
1666 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1667 Class->MenuNameIsString = TRUE;
1668
1669 /* Update the clones */
1670 Class = Class->pclsClone;
1671 while (Class != NULL)
1672 {
1673 Class->lpszClientUnicodeMenuName = strBufW;
1674 Class->lpszClientAnsiMenuName = AnsiString.Buffer;
1675 Class->MenuNameIsString = TRUE;
1676
1677 Class = Class->pclsNext;
1678 }
1679 }
1680 else
1681 {
1682 ERR("Failed to copy class menu name!\n");
1683 UserHeapFree(strBufW);
1684 }
1685 }
1686 else
1687 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1688 }
1689 else
1690 {
1691 ASSERT(IS_INTRESOURCE(MenuName->Buffer));
1692
1693 /* Update the base class */
1694 IntFreeClassMenuName(Class);
1695 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1696 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1697 Class->MenuNameIsString = FALSE;
1698
1699 /* Update the clones */
1700 Class = Class->pclsClone;
1701 while (Class != NULL)
1702 {
1703 Class->lpszClientUnicodeMenuName = MenuName->Buffer;
1704 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer;
1705 Class->MenuNameIsString = FALSE;
1706
1707 Class = Class->pclsNext;
1708 }
1709
1710 Ret = TRUE;
1711 }
1712
1713 return Ret;
1714 }
1715
1716 //// Do this for now in anticipation of new cursor icon code.
1717 BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT, PPROCESSINFO);
1718
1719 BOOL FASTCALL
1720 IntClassDestroyIcon(HANDLE hCurIcon)
1721 {
1722 PCURICON_OBJECT CurIcon;
1723 BOOL Ret;
1724
1725 if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
1726 {
1727
1728 ERR("hCurIcon was not found!\n");
1729 return FALSE;
1730 }
1731 Ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
1732 /* Note: IntDestroyCurIconObject will remove our reference for us! */
1733 if (!Ret)
1734 {
1735 ERR("hCurIcon was not Destroyed!\n");
1736 }
1737 return Ret;
1738 }
1739
1740 ULONG_PTR
1741 UserSetClassLongPtr(IN PCLS Class,
1742 IN INT Index,
1743 IN ULONG_PTR NewLong,
1744 IN BOOL Ansi)
1745 {
1746 ULONG_PTR Ret = 0;
1747 HANDLE hIconSmIntern = NULL;
1748
1749 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */
1750
1751 /* Change the information in the base class first, then update the clones */
1752 Class = Class->pclsBase;
1753
1754 if (Index >= 0)
1755 {
1756 PULONG_PTR Data;
1757
1758 TRACE("SetClassLong(%d, %x)\n", Index, NewLong);
1759
1760 if (((ULONG)Index + sizeof(ULONG_PTR)) < (ULONG)Index ||
1761 ((ULONG)Index + sizeof(ULONG_PTR)) > (ULONG)Class->cbclsExtra)
1762 {
1763 EngSetLastError(ERROR_INVALID_PARAMETER);
1764 return 0;
1765 }
1766
1767 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index);
1768
1769 /* FIXME: Data might be a unaligned pointer! Might be a problem on
1770 certain architectures, maybe using RtlCopyMemory is a
1771 better choice for those architectures! */
1772 Ret = *Data;
1773 *Data = NewLong;
1774
1775 /* Update the clones */
1776 Class = Class->pclsClone;
1777 while (Class != NULL)
1778 {
1779 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong;
1780 Class = Class->pclsNext;
1781 }
1782
1783 return Ret;
1784 }
1785
1786 switch (Index)
1787 {
1788 case GCL_CBWNDEXTRA:
1789 Ret = (ULONG_PTR)Class->cbwndExtra;
1790 Class->cbwndExtra = (INT)NewLong;
1791
1792 /* Update the clones */
1793 Class = Class->pclsClone;
1794 while (Class != NULL)
1795 {
1796 Class->cbwndExtra = (INT)NewLong;
1797 Class = Class->pclsNext;
1798 }
1799
1800 break;
1801
1802 case GCL_CBCLSEXTRA:
1803 EngSetLastError(ERROR_INVALID_PARAMETER);
1804 break;
1805
1806 case GCLP_HBRBACKGROUND:
1807 Ret = (ULONG_PTR)Class->hbrBackground;
1808 Class->hbrBackground = (HBRUSH)NewLong;
1809
1810 /* Update the clones */
1811 Class = Class->pclsClone;
1812 while (Class != NULL)
1813 {
1814 Class->hbrBackground = (HBRUSH)NewLong;
1815 Class = Class->pclsNext;
1816 }
1817 break;
1818
1819 case GCLP_HCURSOR:
1820 /* FIXME: Get handle from pointer to CURSOR object */
1821 Ret = (ULONG_PTR)Class->hCursor;
1822 Class->hCursor = (HANDLE)NewLong;
1823
1824 /* Update the clones */
1825 Class = Class->pclsClone;
1826 while (Class != NULL)
1827 {
1828 Class->hCursor = (HANDLE)NewLong;
1829 Class = Class->pclsNext;
1830 }
1831 break;
1832
1833 // MSDN:
1834 // hIconSm, A handle to a small icon that is associated with the window class.
1835 // If this member is NULL, the system searches the icon resource specified by
1836 // the hIcon member for an icon of the appropriate size to use as the small icon.
1837 //
1838 case GCLP_HICON:
1839 /* FIXME: Get handle from pointer to ICON object */
1840 Ret = (ULONG_PTR)Class->hIcon;
1841 if (Class->hIcon == (HANDLE)NewLong) break;
1842 if (Ret && Class->hIconSmIntern)
1843 {
1844 IntClassDestroyIcon(Class->hIconSmIntern);
1845 Class->CSF_flags &= ~CSF_CACHEDSMICON;
1846 Class->hIconSmIntern = NULL;
1847 }
1848 if (NewLong && !Class->hIconSm)
1849 {
1850 hIconSmIntern = Class->hIconSmIntern = co_IntCopyImage( (HICON)NewLong, IMAGE_ICON,
1851 UserGetSystemMetrics( SM_CXSMICON ),
1852 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1853 Class->CSF_flags |= CSF_CACHEDSMICON;
1854 }
1855 Class->hIcon = (HANDLE)NewLong;
1856
1857 /* Update the clones */
1858 Class = Class->pclsClone;
1859 while (Class != NULL)
1860 {
1861 Class->hIcon = (HANDLE)NewLong;
1862 Class->hIconSmIntern = hIconSmIntern;
1863 Class = Class->pclsNext;
1864 }
1865 break;
1866
1867 case GCLP_HICONSM:
1868 /* FIXME: Get handle from pointer to ICON object */
1869 Ret = (ULONG_PTR)Class->hIconSm;
1870 if (Class->hIconSm == (HANDLE)NewLong) break;
1871 if (Class->CSF_flags & CSF_CACHEDSMICON)
1872 {
1873 if (Class->hIconSmIntern)
1874 {
1875 IntClassDestroyIcon(Class->hIconSmIntern);
1876 Class->hIconSmIntern = NULL;
1877 }
1878 Class->CSF_flags &= ~CSF_CACHEDSMICON;
1879 }
1880 if (Class->hIcon && !Class->hIconSmIntern)
1881 {
1882 hIconSmIntern = Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1883 UserGetSystemMetrics( SM_CXSMICON ),
1884 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1885
1886 if (hIconSmIntern) Class->CSF_flags |= CSF_CACHEDSMICON;
1887 //// FIXME: Very hacky here but it passes the tests....
1888 //// We should not kill a users handle!!!
1889 if (Class->hIconSm) IntClassDestroyIcon(Class->hIconSm); // Fixes 1013
1890 Ret = 0; // Fixes 1009
1891 }
1892 Class->hIconSm = (HANDLE)NewLong;
1893
1894 /* Update the clones */
1895 Class = Class->pclsClone;
1896 while (Class != NULL)
1897 {
1898 Class->hIconSm = (HANDLE)NewLong;
1899 Class->hIconSmIntern = hIconSmIntern;
1900 Class = Class->pclsNext;
1901 }
1902 break;
1903
1904 case GCLP_HMODULE:
1905 Ret = (ULONG_PTR)Class->hModule;
1906 Class->hModule = (HINSTANCE)NewLong;
1907
1908 /* Update the clones */
1909 Class = Class->pclsClone;
1910 while (Class != NULL)
1911 {
1912 Class->hModule = (HINSTANCE)NewLong;
1913 Class = Class->pclsNext;
1914 }
1915 break;
1916
1917 case GCLP_MENUNAME:
1918 {
1919 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1920
1921 if (!IntSetClassMenuName(Class,
1922 Value))
1923 {
1924 ERR("Setting the class menu name failed!\n");
1925 }
1926
1927 /* FIXME: Really return NULL? Wine does so... */
1928 break;
1929 }
1930
1931 case GCL_STYLE:
1932 Ret = (ULONG_PTR)Class->style;
1933 Class->style = (UINT)NewLong;
1934
1935 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we
1936 move the class to the appropriate list? For now, we save
1937 the original value in Class->Global, so we can always
1938 locate the appropriate list */
1939
1940 /* Update the clones */
1941 Class = Class->pclsClone;
1942 while (Class != NULL)
1943 {
1944 Class->style = (UINT)NewLong;
1945 Class = Class->pclsNext;
1946 }
1947 break;
1948
1949 case GCLP_WNDPROC:
1950 Ret = (ULONG_PTR)IntSetClassWndProc(Class,
1951 (WNDPROC)NewLong,
1952 Ansi);
1953 break;
1954
1955 case GCW_ATOM:
1956 {
1957 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong;
1958
1959 Ret = (ULONG_PTR)Class->atomClassName;
1960 if (!IntSetClassAtom(Class,
1961 Value))
1962 {
1963 Ret = 0;
1964 }
1965 break;
1966 }
1967
1968 default:
1969 EngSetLastError(ERROR_INVALID_INDEX);
1970 break;
1971 }
1972
1973 return Ret;
1974 }
1975
1976 static BOOL
1977 UserGetClassInfo(IN PCLS Class,
1978 OUT PWNDCLASSEXW lpwcx,
1979 IN BOOL Ansi,
1980 HINSTANCE hInstance)
1981 {
1982 if (!Class) return FALSE;
1983
1984 lpwcx->style = Class->style;
1985
1986 // If fnId is set, clear the global bit. See wine class test check_style.
1987 if (Class->fnid)
1988 lpwcx->style &= ~CS_GLOBALCLASS;
1989
1990 lpwcx->lpfnWndProc = IntGetClassWndProc(Class, Ansi);
1991
1992 lpwcx->cbClsExtra = Class->cbclsExtra;
1993 lpwcx->cbWndExtra = Class->cbwndExtra;
1994 lpwcx->hIcon = Class->hIcon; /* FIXME: Get handle from pointer */
1995 lpwcx->hCursor = Class->hCursor; /* FIXME: Get handle from pointer */
1996 lpwcx->hbrBackground = Class->hbrBackground;
1997
1998 /* Copy non-string to user first. */
1999 if (Ansi)
2000 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName;
2001 else
2002 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName;
2003 /*
2004 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there!
2005 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space.
2006 * lpszClientXxxMenuName should already be mapped to user space.
2007 */
2008 /* Copy string ptr to user. */
2009 if ( Class->lpszClientUnicodeMenuName != NULL &&
2010 Class->MenuNameIsString)
2011 {
2012 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ?
2013 (PVOID)Class->lpszClientAnsiMenuName :
2014 (PVOID)Class->lpszClientUnicodeMenuName);
2015 }
2016
2017 if (hInstance == hModClient)
2018 lpwcx->hInstance = NULL;
2019 else
2020 lpwcx->hInstance = hInstance;
2021
2022 /* FIXME: Return the string? Okay! This is performed in User32! */
2023 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName);
2024
2025 /* FIXME: Get handle from pointer */
2026 lpwcx->hIconSm = Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern;
2027
2028 return TRUE;
2029 }
2030
2031 //
2032 // ???
2033 //
2034 BOOL
2035 FASTCALL
2036 UserRegisterSystemClasses(VOID)
2037 {
2038 UINT i;
2039 UNICODE_STRING ClassName, MenuName;
2040 PPROCESSINFO ppi = GetW32ProcessInfo();
2041 WNDCLASSEXW wc;
2042 PCLS Class;
2043 BOOL Ret = TRUE;
2044 HBRUSH hBrush;
2045 DWORD Flags = 0;
2046
2047 if (ppi->W32PF_flags & W32PF_CLASSESREGISTERED)
2048 return TRUE;
2049
2050 if ( hModClient == NULL)
2051 return FALSE;
2052
2053 RtlZeroMemory(&ClassName, sizeof(ClassName));
2054 RtlZeroMemory(&MenuName, sizeof(MenuName));
2055
2056 for (i = 0; i != ARRAYSIZE(DefaultServerClasses); i++)
2057 {
2058 if (!IS_ATOM(DefaultServerClasses[i].ClassName))
2059 {
2060 RtlInitUnicodeString(&ClassName, DefaultServerClasses[i].ClassName);
2061 }
2062 else
2063 {
2064 ClassName.Buffer = DefaultServerClasses[i].ClassName;
2065 ClassName.Length = 0;
2066 ClassName.MaximumLength = 0;
2067 }
2068
2069 wc.cbSize = sizeof(wc);
2070 wc.style = DefaultServerClasses[i].Style;
2071
2072 Flags |= CSF_SERVERSIDEPROC;
2073
2074 if (DefaultServerClasses[i].ProcW)
2075 {
2076 wc.lpfnWndProc = DefaultServerClasses[i].ProcW;
2077 wc.hInstance = hModuleWin;
2078 }
2079 else
2080 {
2081 wc.lpfnWndProc = GETPFNSERVER(DefaultServerClasses[i].fiId);
2082 wc.hInstance = hModClient;
2083 }
2084
2085 wc.cbClsExtra = 0;
2086 wc.cbWndExtra = DefaultServerClasses[i].ExtraBytes;
2087 wc.hIcon = NULL;
2088 wc.hCursor = DefaultServerClasses[i].hCursor;
2089 hBrush = DefaultServerClasses[i].hBrush;
2090 if (hBrush <= (HBRUSH)COLOR_MENUBAR)
2091 {
2092 hBrush = IntGetSysColorBrush((INT)hBrush);
2093 }
2094 wc.hbrBackground = hBrush;
2095 wc.lpszMenuName = NULL;
2096 wc.lpszClassName = ClassName.Buffer;
2097 wc.hIconSm = NULL;
2098
2099 Class = IntCreateClass( &wc,
2100 &ClassName,
2101 &MenuName,
2102 DefaultServerClasses[i].fiId,
2103 Flags,
2104 NULL,
2105 ppi);
2106 if (Class != NULL)
2107 {
2108 Class->pclsNext = ppi->pclsPublicList;
2109 (void)InterlockedExchangePointer((PVOID*)&ppi->pclsPublicList,
2110 Class);
2111
2112 ppi->dwRegisteredClasses |= ICLASS_TO_MASK(DefaultServerClasses[i].iCls);
2113 }
2114 else
2115 {
2116 ERR("!!! Registering system class failed!\n");
2117 Ret = FALSE;
2118 }
2119 }
2120 if (Ret) ppi->W32PF_flags |= W32PF_CLASSESREGISTERED;
2121 return Ret;
2122 }
2123
2124 /* SYSCALLS *****************************************************************/
2125
2126 RTL_ATOM
2127 APIENTRY
2128 NtUserRegisterClassExWOW(
2129 WNDCLASSEXW* lpwcx,
2130 PUNICODE_STRING ClassName,
2131 PUNICODE_STRING ClsNVersion,
2132 PCLSMENUNAME pClassMenuName,
2133 DWORD fnID,
2134 DWORD Flags,
2135 LPDWORD pWow)
2136 /*
2137 * FUNCTION:
2138 * Registers a new class with the window manager
2139 * ARGUMENTS:
2140 * lpwcx = Win32 extended window class structure
2141 * bUnicodeClass = Whether to send ANSI or unicode strings
2142 * to window procedures
2143 * RETURNS:
2144 * Atom identifying the new class
2145 */
2146 {
2147 WNDCLASSEXW CapturedClassInfo = {0};
2148 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0};
2149 RTL_ATOM Ret = (RTL_ATOM)0;
2150 PPROCESSINFO ppi = GetW32ProcessInfo();
2151
2152 if (Flags & ~(CSF_ANSIPROC))
2153 {
2154 ERR("NtUserRegisterClassExWOW Bad Flags!\n");
2155 EngSetLastError(ERROR_INVALID_FLAGS);
2156 return Ret;
2157 }
2158
2159 UserEnterExclusive();
2160
2161 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName);
2162
2163 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED ))
2164 {
2165 UserRegisterSystemClasses();
2166 }
2167
2168 _SEH2_TRY
2169 {
2170 /* Probe the parameters and basic parameter checks */
2171 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW))
2172 {
2173 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n");
2174 goto InvalidParameter;
2175 }
2176
2177 ProbeForRead(lpwcx,
2178 sizeof(WNDCLASSEXW),
2179 sizeof(ULONG));
2180 RtlCopyMemory(&CapturedClassInfo,
2181 lpwcx,
2182 sizeof(WNDCLASSEXW));
2183
2184 CapturedName = ProbeForReadUnicodeString(ClassName);
2185
2186 ProbeForRead(pClassMenuName,
2187 sizeof(CLSMENUNAME),
2188 1);
2189
2190 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName);
2191
2192 if ( (CapturedName.Length & 1) ||
2193 (CapturedMenuName.Length & 1) ||
2194 (CapturedClassInfo.cbClsExtra < 0) ||
2195 ((CapturedClassInfo.cbClsExtra + CapturedName.Length +
2196 CapturedMenuName.Length + sizeof(CLS))
2197 < (ULONG)CapturedClassInfo.cbClsExtra) ||
2198 (CapturedClassInfo.cbWndExtra < 0) ||
2199 (CapturedClassInfo.hInstance == NULL) )
2200 {
2201 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n");
2202 goto InvalidParameter;
2203 }
2204
2205 if (CapturedName.Length != 0)
2206 {
2207 ProbeForRead(CapturedName.Buffer,
2208 CapturedName.Length,
2209 sizeof(WCHAR));
2210 }
2211 else
2212 {
2213 if (!IS_ATOM(CapturedName.Buffer))
2214 {
2215 ERR("NtUserRegisterClassExWOW ClassName Error!\n");
2216 goto InvalidParameter;
2217 }
2218 }
2219
2220 if (CapturedMenuName.Length != 0)
2221 {
2222 ProbeForRead(CapturedMenuName.Buffer,
2223 CapturedMenuName.Length,
2224 sizeof(WCHAR));
2225 }
2226 else if (CapturedMenuName.Buffer != NULL &&
2227 !IS_INTRESOURCE(CapturedMenuName.Buffer))
2228 {
2229 ERR("NtUserRegisterClassExWOW MenuName Error!\n");
2230 InvalidParameter:
2231 EngSetLastError(ERROR_INVALID_PARAMETER);
2232 _SEH2_LEAVE;
2233 }
2234
2235 if (IsCallProcHandle(lpwcx->lpfnWndProc))
2236 { // Never seen this yet, but I'm sure it's a little haxxy trick!
2237 // If this pops up we know what todo!
2238 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n");
2239 }
2240
2241 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName);
2242
2243 /* Register the class */
2244 Ret = UserRegisterClass(&CapturedClassInfo,
2245 &CapturedName,
2246 &CapturedMenuName,
2247 fnID,
2248 Flags);
2249 }
2250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2251 {
2252 ERR("NtUserRegisterClassExWOW Exception Error!\n");
2253 SetLastNtError(_SEH2_GetExceptionCode());
2254 }
2255 _SEH2_END;
2256 /*
2257 if (!Ret)
2258 {
2259 ERR("NtUserRegisterClassExWOW Null Return!\n");
2260 }
2261 */
2262 UserLeave();
2263
2264 return Ret;
2265 }
2266
2267 ULONG_PTR APIENTRY
2268 NtUserSetClassLong(HWND hWnd,
2269 INT Offset,
2270 ULONG_PTR dwNewLong,
2271 BOOL Ansi)
2272 {
2273 PPROCESSINFO pi;
2274 PWND Window;
2275 ULONG_PTR Ret = 0;
2276
2277 UserEnterExclusive();
2278
2279 pi = GetW32ProcessInfo();
2280
2281 Window = UserGetWindowObject(hWnd);
2282 if (Window != NULL)
2283 {
2284 if (Window->head.pti->ppi != pi)
2285 {
2286 EngSetLastError(ERROR_ACCESS_DENIED);
2287 goto Cleanup;
2288 }
2289
2290 _SEH2_TRY
2291 {
2292 UNICODE_STRING Value;
2293
2294 /* Probe the parameters */
2295 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME)
2296 {
2297 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong);
2298 if (Value.Length & 1)
2299 {
2300 goto InvalidParameter;
2301 }
2302
2303 if (Value.Length != 0)
2304 {
2305 ProbeForRead(Value.Buffer,
2306 Value.Length,
2307 sizeof(WCHAR));
2308 }
2309 else
2310 {
2311 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer))
2312 {
2313 goto InvalidParameter;
2314 }
2315 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer))
2316 {
2317 InvalidParameter:
2318 EngSetLastError(ERROR_INVALID_PARAMETER);
2319 _SEH2_LEAVE;
2320 }
2321 }
2322
2323 dwNewLong = (ULONG_PTR)&Value;
2324 }
2325
2326 Ret = UserSetClassLongPtr(Window->pcls,
2327 Offset,
2328 dwNewLong,
2329 Ansi);
2330 }
2331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2332 {
2333 SetLastNtError(_SEH2_GetExceptionCode());
2334 }
2335 _SEH2_END;
2336 }
2337
2338 Cleanup:
2339 UserLeave();
2340
2341 return Ret;
2342 }
2343
2344 WORD
2345 APIENTRY
2346 NtUserSetClassWord(
2347 HWND hWnd,
2348 INT nIndex,
2349 WORD wNewWord)
2350 {
2351 /*
2352 * NOTE: Obsoleted in 32-bit windows
2353 */
2354 return(0);
2355 }
2356
2357 BOOL
2358 APIENTRY
2359 NtUserUnregisterClass(
2360 IN PUNICODE_STRING ClassNameOrAtom,
2361 IN HINSTANCE hInstance,
2362 OUT PCLSMENUNAME pClassMenuName)
2363 {
2364 UNICODE_STRING SafeClassName;
2365 NTSTATUS Status;
2366 BOOL Ret;
2367
2368 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom);
2369 if (!NT_SUCCESS(Status))
2370 {
2371 ERR("Error capturing the class name\n");
2372 SetLastNtError(Status);
2373 return FALSE;
2374 }
2375
2376 UserEnterExclusive();
2377
2378 /* Unregister the class */
2379 Ret = UserUnregisterClass(&SafeClassName, hInstance, NULL); // Null for now~
2380
2381 UserLeave();
2382
2383 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
2384 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2385
2386 return Ret;
2387 }
2388
2389
2390 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */
2391 BOOL
2392 APIENTRY
2393 NtUserGetClassInfo(
2394 HINSTANCE hInstance,
2395 PUNICODE_STRING ClassName,
2396 LPWNDCLASSEXW lpWndClassEx,
2397 LPWSTR *ppszMenuName,
2398 BOOL bAnsi)
2399 {
2400 UNICODE_STRING SafeClassName;
2401 WNDCLASSEXW Safewcexw;
2402 PCLS Class;
2403 RTL_ATOM ClassAtom = 0;
2404 PPROCESSINFO ppi;
2405 BOOL Ret = TRUE;
2406 NTSTATUS Status;
2407
2408 _SEH2_TRY
2409 {
2410 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG));
2411 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW));
2412 }
2413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2414 {
2415 SetLastNtError(_SEH2_GetExceptionCode());
2416 _SEH2_YIELD(return FALSE);
2417 }
2418 _SEH2_END;
2419
2420 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
2421 if (!NT_SUCCESS(Status))
2422 {
2423 ERR("Error capturing the class name\n");
2424 SetLastNtError(Status);
2425 return FALSE;
2426 }
2427
2428 // If null instance use client.
2429 if (!hInstance) hInstance = hModClient;
2430
2431 TRACE("GetClassInfo(%wZ, %p)\n", SafeClassName, hInstance);
2432
2433 /* NOTE: Need exclusive lock because getting the wndproc might require the
2434 creation of a call procedure handle */
2435 UserEnterExclusive();
2436
2437 ppi = GetW32ProcessInfo();
2438 if (!(ppi->W32PF_flags & W32PF_CLASSESREGISTERED))
2439 {
2440 UserRegisterSystemClasses();
2441 }
2442
2443 ClassAtom = IntGetClassAtom(&SafeClassName,
2444 hInstance,
2445 ppi,
2446 &Class,
2447 NULL);
2448 if (ClassAtom != (RTL_ATOM)0)
2449 {
2450 Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance);
2451 }
2452 else
2453 {
2454 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2455 Ret = FALSE;
2456 }
2457
2458 UserLeave();
2459
2460 if (Ret)
2461 {
2462 _SEH2_TRY
2463 {
2464 /* Emulate Function. */
2465 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName;
2466
2467 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW));
2468
2469 // From Wine:
2470 /* We must return the atom of the class here instead of just TRUE. */
2471 /* Undocumented behavior! Return the class atom as a BOOL! */
2472 Ret = (BOOL)ClassAtom;
2473 }
2474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2475 {
2476 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2477 Ret = FALSE;
2478 }
2479 _SEH2_END;
2480 }
2481
2482 if (!IS_ATOM(SafeClassName.Buffer))
2483 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2484
2485 return Ret;
2486 }
2487
2488
2489 INT APIENTRY
2490 NtUserGetClassName (IN HWND hWnd,
2491 IN BOOL Real,
2492 OUT PUNICODE_STRING ClassName)
2493 {
2494 PWND Window;
2495 UNICODE_STRING CapturedClassName;
2496 INT iCls, Ret = 0;
2497 RTL_ATOM Atom = 0;
2498
2499 UserEnterShared();
2500
2501 Window = UserGetWindowObject(hWnd);
2502 if (Window != NULL)
2503 {
2504 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY))
2505 {
2506 if (LookupFnIdToiCls(Window->fnid, &iCls))
2507 {
2508 Atom = gpsi->atomSysClass[iCls];
2509 }
2510 }
2511
2512 _SEH2_TRY
2513 {
2514 ProbeForWriteUnicodeString(ClassName);
2515 CapturedClassName = *ClassName;
2516
2517 /* Get the class name */
2518 Ret = UserGetClassName(Window->pcls,
2519 &CapturedClassName,
2520 Atom,
2521 FALSE);
2522
2523 if (Ret != 0)
2524 {
2525 /* Update the Length field */
2526 ClassName->Length = CapturedClassName.Length;
2527 }
2528 }
2529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2530 {
2531 SetLastNtError(_SEH2_GetExceptionCode());
2532 }
2533 _SEH2_END;
2534 }
2535
2536 UserLeave();
2537
2538 return Ret;
2539 }
2540
2541 /* Return Pointer to Class structure. */
2542 PCLS
2543 APIENTRY
2544 NtUserGetWOWClass(
2545 HINSTANCE hInstance,
2546 PUNICODE_STRING ClassName)
2547 {
2548 UNICODE_STRING SafeClassName;
2549 PPROCESSINFO pi;
2550 PCLS Class = NULL;
2551 RTL_ATOM ClassAtom = 0;
2552 NTSTATUS Status;
2553
2554 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName);
2555 if (!NT_SUCCESS(Status))
2556 {
2557 ERR("Error capturing the class name\n");
2558 SetLastNtError(Status);
2559 return FALSE;
2560 }
2561
2562 UserEnterExclusive();
2563
2564 pi = GetW32ProcessInfo();
2565
2566 ClassAtom = IntGetClassAtom(&SafeClassName,
2567 hInstance,
2568 pi,
2569 &Class,
2570 NULL);
2571 if (!ClassAtom)
2572 {
2573 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST);
2574 }
2575
2576
2577 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer))
2578 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING);
2579
2580 UserLeave();
2581 //
2582 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space.
2583 //
2584 return Class;
2585 }
2586
2587 /* EOF */