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