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