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 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 } 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 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 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!! */ 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 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 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 421 IntDeregisterClassAtom(IN RTL_ATOM Atom) 422 { 423 return RtlDeleteAtomFromAtomTable(gAtomTable, 424 Atom); 425 } 426 427 VOID 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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