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