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