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 if (ClassName->Buffer) 1359 { 1360 *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer); 1361 Ret = TRUE; 1362 } 1363 else 1364 { 1365 *Atom = 0; 1366 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST); 1367 Ret = FALSE; 1368 } 1369 } 1370 1371 return Ret; 1372 } 1373 1374 RTL_ATOM 1375 IntGetClassAtom( 1376 _In_ PUNICODE_STRING ClassName, 1377 IN HINSTANCE hInstance OPTIONAL, 1378 IN PPROCESSINFO pi OPTIONAL, 1379 OUT PCLS *BaseClass OPTIONAL, 1380 OUT PCLS **Link OPTIONAL) 1381 { 1382 RTL_ATOM Atom = (RTL_ATOM)0; 1383 1384 ASSERT(BaseClass != NULL); 1385 1386 if (IntGetAtomFromStringOrAtom(ClassName, &Atom) && 1387 Atom != (RTL_ATOM)0) 1388 { 1389 PCLS Class; 1390 1391 /* Attempt to locate the class object */ 1392 1393 ASSERT(pi != NULL); 1394 1395 /* Step 1: Try to find an exact match of locally registered classes */ 1396 Class = IntFindClass(Atom, 1397 hInstance, 1398 &pi->pclsPrivateList, 1399 Link); 1400 if (Class != NULL) 1401 { TRACE("Step 1: 0x%p\n",Class ); 1402 goto FoundClass; 1403 } 1404 1405 /* Step 2: Try to find any globally registered class. The hInstance 1406 is not relevant for global classes */ 1407 Class = IntFindClass(Atom, 1408 NULL, 1409 &pi->pclsPublicList, 1410 Link); 1411 if (Class != NULL) 1412 { TRACE("Step 2: 0x%p 0x%p\n",Class, Class->hModule); 1413 goto FoundClass; 1414 } 1415 1416 /* Step 3: Try to find any local class registered by user32 */ 1417 Class = IntFindClass(Atom, 1418 hModClient, 1419 &pi->pclsPrivateList, 1420 Link); 1421 if (Class != NULL) 1422 { TRACE("Step 3: 0x%p\n",Class ); 1423 goto FoundClass; 1424 } 1425 1426 /* Step 4: Try to find any global class registered by user32 */ 1427 Class = IntFindClass(Atom, 1428 hModClient, 1429 &pi->pclsPublicList, 1430 Link); 1431 if (Class == NULL) 1432 { 1433 return (RTL_ATOM)0; 1434 }else{TRACE("Step 4: 0x%p\n",Class );} 1435 1436 FoundClass: 1437 *BaseClass = Class; 1438 } 1439 else 1440 { 1441 Atom = 0; 1442 } 1443 1444 return Atom; 1445 } 1446 1447 PCLS 1448 IntGetAndReferenceClass(PUNICODE_STRING ClassName, HINSTANCE hInstance, BOOL bDesktopThread) 1449 { 1450 PCLS *ClassLink, Class = NULL; 1451 RTL_ATOM ClassAtom; 1452 PTHREADINFO pti; 1453 1454 if (bDesktopThread) 1455 pti = gptiDesktopThread; 1456 else 1457 pti = PsGetCurrentThreadWin32Thread(); 1458 1459 if ( !(pti->ppi->W32PF_flags & W32PF_CLASSESREGISTERED )) 1460 { 1461 UserRegisterSystemClasses(); 1462 } 1463 1464 /* Check the class. */ 1465 1466 TRACE("Finding Class %wZ for hInstance 0x%p\n", ClassName, hInstance); 1467 1468 ClassAtom = IntGetClassAtom(ClassName, 1469 hInstance, 1470 pti->ppi, 1471 &Class, 1472 &ClassLink); 1473 1474 if (ClassAtom == (RTL_ATOM)0) 1475 { 1476 if (IS_ATOM(ClassName->Buffer)) 1477 { 1478 ERR("Class 0x%p not found\n", ClassName->Buffer); 1479 } 1480 else 1481 { 1482 ERR("Class \"%wZ\" not found\n", ClassName); 1483 } 1484 1485 return NULL; 1486 } 1487 1488 TRACE("Referencing Class 0x%p with atom 0x%x\n", Class, ClassAtom); 1489 Class = IntReferenceClass(Class, 1490 ClassLink, 1491 pti->rpdesk); 1492 if (Class == NULL) 1493 { 1494 ERR("Failed to reference window class!\n"); 1495 return NULL; 1496 } 1497 1498 return Class; 1499 } 1500 1501 RTL_ATOM 1502 UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx, 1503 IN PUNICODE_STRING ClassName, 1504 IN PUNICODE_STRING ClassVersion, 1505 IN PUNICODE_STRING MenuName, 1506 IN DWORD fnID, 1507 IN DWORD dwFlags) 1508 { 1509 PTHREADINFO pti; 1510 PPROCESSINFO pi; 1511 PCLS Class; 1512 RTL_ATOM ClassAtom; 1513 RTL_ATOM Ret = (RTL_ATOM)0; 1514 1515 /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */ 1516 1517 pti = GetW32ThreadInfo(); 1518 1519 pi = pti->ppi; 1520 1521 // Need only to test for two conditions not four....... Fix more whine tests.... 1522 if ( IntGetAtomFromStringOrAtom( ClassVersion, &ClassAtom) && 1523 ClassAtom != (RTL_ATOM)0 && 1524 !(dwFlags & CSF_SERVERSIDEPROC) ) // Bypass Server Sides 1525 { 1526 Class = IntFindClass( ClassAtom, 1527 lpwcx->hInstance, 1528 &pi->pclsPrivateList, 1529 NULL); 1530 1531 if (Class != NULL && !Class->Global) 1532 { 1533 // Local class already exists 1534 TRACE("Local Class 0x%x does already exist!\n", ClassAtom); 1535 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS); 1536 return (RTL_ATOM)0; 1537 } 1538 1539 if (lpwcx->style & CS_GLOBALCLASS) 1540 { 1541 Class = IntFindClass( ClassAtom, 1542 NULL, 1543 &pi->pclsPublicList, 1544 NULL); 1545 1546 if (Class != NULL && Class->Global) 1547 { 1548 TRACE("Global Class 0x%x does already exist!\n", ClassAtom); 1549 EngSetLastError(ERROR_CLASS_ALREADY_EXISTS); 1550 return (RTL_ATOM)0; 1551 } 1552 } 1553 } 1554 1555 Class = IntCreateClass(lpwcx, 1556 ClassName, 1557 ClassVersion, 1558 MenuName, 1559 fnID, 1560 dwFlags, 1561 pti->rpdesk, 1562 pi); 1563 1564 if (Class != NULL) 1565 { 1566 PCLS *List; 1567 1568 /* Register the class */ 1569 if (Class->Global) 1570 List = &pi->pclsPublicList; 1571 else 1572 List = &pi->pclsPrivateList; 1573 1574 Class->pclsNext = *List; 1575 (void)InterlockedExchangePointer((PVOID*)List, 1576 Class); 1577 1578 Ret = Class->atomNVClassName; 1579 } 1580 else 1581 { 1582 ERR("UserRegisterClass: Yes, that is right, you have no Class!\n"); 1583 } 1584 1585 return Ret; 1586 } 1587 1588 BOOL 1589 UserUnregisterClass(IN PUNICODE_STRING ClassName, 1590 IN HINSTANCE hInstance, 1591 OUT PCLSMENUNAME pClassMenuName) 1592 { 1593 PCLS *Link; 1594 PPROCESSINFO pi; 1595 RTL_ATOM ClassAtom; 1596 PCLS Class; 1597 1598 pi = GetW32ProcessInfo(); 1599 1600 TRACE("UserUnregisterClass(%wZ, 0x%p)\n", ClassName, hInstance); 1601 1602 /* NOTE: Accessing the buffer in ClassName may raise an exception! */ 1603 ClassAtom = IntGetClassAtom(ClassName, 1604 hInstance, 1605 pi, 1606 &Class, 1607 &Link); 1608 if (ClassAtom == (RTL_ATOM)0) 1609 { 1610 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST); 1611 TRACE("UserUnregisterClass: No Class found.\n"); 1612 return FALSE; 1613 } 1614 1615 ASSERT(Class != NULL); 1616 1617 if (Class->cWndReferenceCount != 0 || 1618 Class->pclsClone != NULL) 1619 { 1620 TRACE("UserUnregisterClass: Class has a Window. Ct %u : Clone 0x%p\n", Class->cWndReferenceCount, Class->pclsClone); 1621 EngSetLastError(ERROR_CLASS_HAS_WINDOWS); 1622 return FALSE; 1623 } 1624 1625 /* Must be a base class! */ 1626 ASSERT(Class->pclsBase == Class); 1627 1628 /* Unlink the class */ 1629 *Link = Class->pclsNext; 1630 1631 if (NT_SUCCESS(IntDeregisterClassAtom(Class->atomClassName))) 1632 { 1633 TRACE("Class 0x%p\n", Class); 1634 TRACE("UserUnregisterClass: Good Exit!\n"); 1635 Class->atomClassName = 0; // Don't let it linger... 1636 /* Finally free the resources */ 1637 IntDestroyClass(Class); 1638 return TRUE; 1639 } 1640 ERR("UserUnregisterClass: Can not deregister Class Atom.\n"); 1641 return FALSE; 1642 } 1643 1644 INT 1645 UserGetClassName(IN PCLS Class, 1646 IN OUT PUNICODE_STRING ClassName, 1647 IN RTL_ATOM Atom, 1648 IN BOOL Ansi) 1649 { 1650 NTSTATUS Status = STATUS_SUCCESS; 1651 WCHAR szStaticTemp[32]; 1652 PWSTR szTemp = NULL; 1653 ULONG BufLen = sizeof(szStaticTemp); 1654 INT Ret = 0; 1655 1656 /* Note: Accessing the buffer in ClassName may raise an exception! */ 1657 1658 _SEH2_TRY 1659 { 1660 if (Ansi) 1661 { 1662 PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName; 1663 UNICODE_STRING UnicodeClassName; 1664 1665 /* Limit the size of the static buffer on the stack to the 1666 size of the buffer provided by the caller */ 1667 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength) 1668 { 1669 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR); 1670 } 1671 1672 /* Find out how big the buffer needs to be */ 1673 Status = RtlQueryAtomInAtomTable(gAtomTable, 1674 Class->atomClassName, 1675 NULL, 1676 NULL, 1677 szStaticTemp, 1678 &BufLen); 1679 if (Status == STATUS_BUFFER_TOO_SMALL) 1680 { 1681 if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength) 1682 { 1683 /* The buffer required exceeds the ansi buffer provided, 1684 pretend like we're using the ansi buffer and limit the 1685 size to the buffer size provided */ 1686 BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR); 1687 } 1688 1689 /* Allocate a temporary buffer that can hold the unicode class name */ 1690 szTemp = ExAllocatePoolWithTag(PagedPool, 1691 BufLen, 1692 USERTAG_CLASS); 1693 if (szTemp == NULL) 1694 { 1695 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1696 _SEH2_LEAVE; 1697 } 1698 1699 /* Query the class name */ 1700 Status = RtlQueryAtomInAtomTable(gAtomTable, 1701 Atom ? Atom : Class->atomNVClassName, 1702 NULL, 1703 NULL, 1704 szTemp, 1705 &BufLen); 1706 } 1707 else 1708 szTemp = szStaticTemp; 1709 1710 if (NT_SUCCESS(Status)) 1711 { 1712 /* Convert the atom name to ansi */ 1713 1714 RtlInitUnicodeString(&UnicodeClassName, 1715 szTemp); 1716 1717 Status = RtlUnicodeStringToAnsiString(AnsiClassName, 1718 &UnicodeClassName, 1719 FALSE); 1720 if (!NT_SUCCESS(Status)) 1721 { 1722 SetLastNtError(Status); 1723 _SEH2_LEAVE; 1724 } 1725 } 1726 1727 Ret = BufLen / sizeof(WCHAR); 1728 } 1729 else /* !ANSI */ 1730 { 1731 BufLen = ClassName->MaximumLength; 1732 1733 /* Query the atom name */ 1734 Status = RtlQueryAtomInAtomTable(gAtomTable, 1735 Atom ? Atom : Class->atomNVClassName, 1736 NULL, 1737 NULL, 1738 ClassName->Buffer, 1739 &BufLen); 1740 1741 if (!NT_SUCCESS(Status)) 1742 { 1743 SetLastNtError(Status); 1744 _SEH2_LEAVE; 1745 } 1746 1747 Ret = BufLen / sizeof(WCHAR); 1748 } 1749 } 1750 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1751 { 1752 SetLastNtError(_SEH2_GetExceptionCode()); 1753 } 1754 _SEH2_END; 1755 1756 if (Ansi && szTemp != NULL && szTemp != szStaticTemp) 1757 { 1758 ExFreePoolWithTag(szTemp, USERTAG_CLASS); 1759 } 1760 1761 return Ret; 1762 } 1763 1764 static BOOL 1765 IntSetClassMenuName(IN PCLS Class, 1766 IN PUNICODE_STRING MenuName) 1767 { 1768 BOOL Ret = FALSE; 1769 1770 /* Change the base class first */ 1771 Class = Class->pclsBase; 1772 1773 if (MenuName->Length != 0) 1774 { 1775 ANSI_STRING AnsiString; 1776 PWSTR strBufW; 1777 1778 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(MenuName); 1779 1780 strBufW = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) + 1781 AnsiString.MaximumLength); 1782 if (strBufW != NULL) 1783 { 1784 _SEH2_TRY 1785 { 1786 NTSTATUS Status; 1787 1788 /* Copy the unicode string */ 1789 RtlCopyMemory(strBufW, 1790 MenuName->Buffer, 1791 MenuName->Length); 1792 strBufW[MenuName->Length / sizeof(WCHAR)] = UNICODE_NULL; 1793 1794 /* Create an ANSI copy of the string */ 1795 AnsiString.Buffer = (PSTR)(strBufW + (MenuName->Length / sizeof(WCHAR)) + 1); 1796 Status = RtlUnicodeStringToAnsiString(&AnsiString, 1797 MenuName, 1798 FALSE); 1799 if (!NT_SUCCESS(Status)) 1800 { 1801 SetLastNtError(Status); 1802 _SEH2_LEAVE; 1803 } 1804 1805 Ret = TRUE; 1806 } 1807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1808 { 1809 SetLastNtError(_SEH2_GetExceptionCode()); 1810 } 1811 _SEH2_END; 1812 1813 if (Ret) 1814 { 1815 /* Update the base class */ 1816 IntFreeClassMenuName(Class); 1817 Class->lpszClientUnicodeMenuName = strBufW; 1818 Class->lpszClientAnsiMenuName = AnsiString.Buffer; 1819 Class->MenuNameIsString = TRUE; 1820 1821 /* Update the clones */ 1822 Class = Class->pclsClone; 1823 while (Class != NULL) 1824 { 1825 Class->lpszClientUnicodeMenuName = strBufW; 1826 Class->lpszClientAnsiMenuName = AnsiString.Buffer; 1827 Class->MenuNameIsString = TRUE; 1828 1829 Class = Class->pclsNext; 1830 } 1831 } 1832 else 1833 { 1834 ERR("Failed to copy class menu name!\n"); 1835 UserHeapFree(strBufW); 1836 } 1837 } 1838 else 1839 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1840 } 1841 else 1842 { 1843 ASSERT(IS_INTRESOURCE(MenuName->Buffer)); 1844 1845 /* Update the base class */ 1846 IntFreeClassMenuName(Class); 1847 Class->lpszClientUnicodeMenuName = MenuName->Buffer; 1848 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer; 1849 Class->MenuNameIsString = FALSE; 1850 1851 /* Update the clones */ 1852 Class = Class->pclsClone; 1853 while (Class != NULL) 1854 { 1855 Class->lpszClientUnicodeMenuName = MenuName->Buffer; 1856 Class->lpszClientAnsiMenuName = (PSTR)MenuName->Buffer; 1857 Class->MenuNameIsString = FALSE; 1858 1859 Class = Class->pclsNext; 1860 } 1861 1862 Ret = TRUE; 1863 } 1864 1865 return Ret; 1866 } 1867 1868 ULONG_PTR 1869 UserSetClassLongPtr(IN PCLS Class, 1870 IN INT Index, 1871 IN ULONG_PTR NewLong, 1872 IN BOOL Ansi) 1873 { 1874 ULONG_PTR Ret = 0; 1875 1876 /* NOTE: For GCLP_MENUNAME and GCW_ATOM this function may raise an exception! */ 1877 1878 /* Change the information in the base class first, then update the clones */ 1879 Class = Class->pclsBase; 1880 1881 if (Index >= 0) 1882 { 1883 PULONG_PTR Data; 1884 1885 TRACE("SetClassLong(%d, %x)\n", Index, NewLong); 1886 1887 if (((ULONG)Index + sizeof(ULONG_PTR)) < (ULONG)Index || 1888 ((ULONG)Index + sizeof(ULONG_PTR)) > (ULONG)Class->cbclsExtra) 1889 { 1890 EngSetLastError(ERROR_INVALID_PARAMETER); 1891 return 0; 1892 } 1893 1894 Data = (PULONG_PTR)((ULONG_PTR)(Class + 1) + Index); 1895 1896 /* FIXME: Data might be a unaligned pointer! Might be a problem on 1897 certain architectures, maybe using RtlCopyMemory is a 1898 better choice for those architectures! */ 1899 Ret = *Data; 1900 *Data = NewLong; 1901 1902 /* Update the clones */ 1903 Class = Class->pclsClone; 1904 while (Class != NULL) 1905 { 1906 *(PULONG_PTR)((ULONG_PTR)(Class + 1) + Index) = NewLong; 1907 Class = Class->pclsNext; 1908 } 1909 1910 return Ret; 1911 } 1912 1913 switch (Index) 1914 { 1915 case GCL_CBWNDEXTRA: 1916 Ret = (ULONG_PTR)Class->cbwndExtra; 1917 Class->cbwndExtra = (INT)NewLong; 1918 1919 /* Update the clones */ 1920 Class = Class->pclsClone; 1921 while (Class != NULL) 1922 { 1923 Class->cbwndExtra = (INT)NewLong; 1924 Class = Class->pclsNext; 1925 } 1926 1927 break; 1928 1929 case GCL_CBCLSEXTRA: 1930 EngSetLastError(ERROR_INVALID_PARAMETER); 1931 break; 1932 1933 case GCLP_HBRBACKGROUND: 1934 Ret = (ULONG_PTR)Class->hbrBackground; 1935 Class->hbrBackground = (HBRUSH)NewLong; 1936 1937 /* Update the clones */ 1938 Class = Class->pclsClone; 1939 while (Class != NULL) 1940 { 1941 Class->hbrBackground = (HBRUSH)NewLong; 1942 Class = Class->pclsNext; 1943 } 1944 break; 1945 1946 case GCLP_HCURSOR: 1947 { 1948 PCURICON_OBJECT NewCursor = NULL; 1949 1950 if (NewLong) 1951 { 1952 NewCursor = UserGetCurIconObject((HCURSOR)NewLong); 1953 if (!NewCursor) 1954 { 1955 EngSetLastError(ERROR_INVALID_CURSOR_HANDLE); 1956 return 0; 1957 } 1958 } 1959 1960 if (Class->spcur) 1961 { 1962 Ret = (ULONG_PTR)UserHMGetHandle(Class->spcur); 1963 UserDereferenceObject(Class->spcur); 1964 } 1965 else 1966 { 1967 Ret = 0; 1968 } 1969 1970 if (Ret == NewLong) 1971 { 1972 /* It's a nop */ 1973 return Ret; 1974 } 1975 1976 Class->spcur = NewCursor; 1977 1978 /* Update the clones */ 1979 Class = Class->pclsClone; 1980 while (Class != NULL) 1981 { 1982 if (Class->spcur) 1983 UserDereferenceObject(Class->spcur); 1984 if (NewCursor) 1985 UserReferenceObject(NewCursor); 1986 Class->spcur = NewCursor; 1987 Class = Class->pclsNext; 1988 } 1989 1990 break; 1991 } 1992 1993 // MSDN: 1994 // hIconSm, A handle to a small icon that is associated with the window class. 1995 // If this member is NULL, the system searches the icon resource specified by 1996 // the hIcon member for an icon of the appropriate size to use as the small icon. 1997 // 1998 case GCLP_HICON: 1999 { 2000 PCURICON_OBJECT NewIcon = NULL; 2001 PCURICON_OBJECT NewSmallIcon = NULL; 2002 2003 if (NewLong) 2004 { 2005 NewIcon = UserGetCurIconObject((HCURSOR)NewLong); 2006 if (!NewIcon) 2007 { 2008 EngSetLastError(ERROR_INVALID_ICON_HANDLE); 2009 return 0; 2010 } 2011 } 2012 2013 if (Class->spicn) 2014 { 2015 Ret = (ULONG_PTR)UserHMGetHandle(Class->spicn); 2016 UserDereferenceObject(Class->spicn); 2017 } 2018 else 2019 { 2020 Ret = 0; 2021 } 2022 2023 if (Ret == NewLong) 2024 { 2025 /* It's a nop */ 2026 return Ret; 2027 } 2028 2029 if (Ret && (Class->CSF_flags & CSF_CACHEDSMICON)) 2030 { 2031 /* We will change the small icon */ 2032 UserDereferenceObject(Class->spicnSm); 2033 IntDestroyCurIconObject(Class->spicnSm); 2034 Class->spicnSm = NULL; 2035 Class->CSF_flags &= ~CSF_CACHEDSMICON; 2036 } 2037 2038 if (NewLong && !Class->spicnSm) 2039 { 2040 /* Create the new small icon from the new large(?) one */ 2041 HICON SmallIconHandle = NULL; 2042 if((NewIcon->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 2043 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 2044 { 2045 SmallIconHandle = co_IntCopyImage( 2046 (HICON)NewLong, 2047 IMAGE_ICON, 2048 UserGetSystemMetrics( SM_CXSMICON ), 2049 UserGetSystemMetrics( SM_CYSMICON ), 2050 LR_COPYFROMRESOURCE); 2051 } 2052 if (!SmallIconHandle) 2053 { 2054 /* Retry without copying from resource */ 2055 SmallIconHandle = co_IntCopyImage( 2056 (HICON)NewLong, 2057 IMAGE_ICON, 2058 UserGetSystemMetrics( SM_CXSMICON ), 2059 UserGetSystemMetrics( SM_CYSMICON ), 2060 0); 2061 } 2062 if (SmallIconHandle) 2063 { 2064 /* So use it */ 2065 NewSmallIcon = Class->spicnSm = UserGetCurIconObject(SmallIconHandle); 2066 Class->CSF_flags |= CSF_CACHEDSMICON; 2067 } 2068 } 2069 2070 Class->spicn = NewIcon; 2071 2072 /* Update the clones */ 2073 Class = Class->pclsClone; 2074 while (Class != NULL) 2075 { 2076 if (Class->spicn) 2077 UserDereferenceObject(Class->spicn); 2078 if (NewIcon) 2079 UserReferenceObject(NewIcon); 2080 Class->spicn = NewIcon; 2081 if (NewSmallIcon) 2082 { 2083 if (Class->spicnSm) 2084 UserDereferenceObject(Class->spicnSm); 2085 UserReferenceObject(NewSmallIcon); 2086 Class->spicnSm = NewSmallIcon; 2087 Class->CSF_flags |= CSF_CACHEDSMICON; 2088 } 2089 Class = Class->pclsNext; 2090 } 2091 break; 2092 } 2093 2094 case GCLP_HICONSM: 2095 { 2096 PCURICON_OBJECT NewSmallIcon = NULL; 2097 BOOLEAN NewIconFromCache = FALSE; 2098 2099 if (NewLong) 2100 { 2101 NewSmallIcon = UserGetCurIconObject((HCURSOR)NewLong); 2102 if (!NewSmallIcon) 2103 { 2104 EngSetLastError(ERROR_INVALID_ICON_HANDLE); 2105 return 0; 2106 } 2107 } 2108 else 2109 { 2110 /* Create the new small icon from the large one */ 2111 HICON SmallIconHandle = NULL; 2112 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 2113 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 2114 { 2115 SmallIconHandle = co_IntCopyImage( 2116 UserHMGetHandle(Class->spicn), 2117 IMAGE_ICON, 2118 UserGetSystemMetrics( SM_CXSMICON ), 2119 UserGetSystemMetrics( SM_CYSMICON ), 2120 LR_COPYFROMRESOURCE); 2121 } 2122 if (!SmallIconHandle) 2123 { 2124 /* Retry without copying from resource */ 2125 SmallIconHandle = co_IntCopyImage( 2126 UserHMGetHandle(Class->spicn), 2127 IMAGE_ICON, 2128 UserGetSystemMetrics( SM_CXSMICON ), 2129 UserGetSystemMetrics( SM_CYSMICON ), 2130 0); 2131 } 2132 if (SmallIconHandle) 2133 { 2134 /* So use it */ 2135 NewSmallIcon = UserGetCurIconObject(SmallIconHandle); 2136 NewIconFromCache = TRUE; 2137 } 2138 else 2139 { 2140 ERR("Failed getting a small icon for the class.\n"); 2141 } 2142 } 2143 2144 if (Class->spicnSm) 2145 { 2146 if (Class->CSF_flags & CSF_CACHEDSMICON) 2147 { 2148 /* We must destroy the icon if we own it */ 2149 IntDestroyCurIconObject(Class->spicnSm); 2150 Ret = 0; 2151 } 2152 else 2153 { 2154 Ret = (ULONG_PTR)UserHMGetHandle(Class->spicnSm); 2155 } 2156 UserDereferenceObject(Class->spicnSm); 2157 } 2158 else 2159 { 2160 Ret = 0; 2161 } 2162 2163 if (NewIconFromCache) 2164 Class->CSF_flags |= CSF_CACHEDSMICON; 2165 else 2166 Class->CSF_flags &= ~CSF_CACHEDSMICON; 2167 Class->spicnSm = NewSmallIcon; 2168 2169 /* Update the clones */ 2170 Class = Class->pclsClone; 2171 while (Class != NULL) 2172 { 2173 if (Class->spicnSm) 2174 UserDereferenceObject(Class->spicnSm); 2175 if (NewSmallIcon) 2176 UserReferenceObject(NewSmallIcon); 2177 if (NewIconFromCache) 2178 Class->CSF_flags |= CSF_CACHEDSMICON; 2179 else 2180 Class->CSF_flags &= ~CSF_CACHEDSMICON; 2181 Class->spicnSm = NewSmallIcon; 2182 Class = Class->pclsNext; 2183 } 2184 } 2185 break; 2186 2187 case GCLP_HMODULE: 2188 Ret = (ULONG_PTR)Class->hModule; 2189 Class->hModule = (HINSTANCE)NewLong; 2190 2191 /* Update the clones */ 2192 Class = Class->pclsClone; 2193 while (Class != NULL) 2194 { 2195 Class->hModule = (HINSTANCE)NewLong; 2196 Class = Class->pclsNext; 2197 } 2198 break; 2199 2200 case GCLP_MENUNAME: 2201 { 2202 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong; 2203 2204 if (!IntSetClassMenuName(Class, 2205 Value)) 2206 { 2207 ERR("Setting the class menu name failed!\n"); 2208 } 2209 2210 /* FIXME: Really return NULL? Wine does so... */ 2211 break; 2212 } 2213 2214 case GCL_STYLE: 2215 Ret = (ULONG_PTR)Class->style; 2216 Class->style = (UINT)NewLong; 2217 2218 /* FIXME: What if the CS_GLOBALCLASS style is changed? should we 2219 move the class to the appropriate list? For now, we save 2220 the original value in Class->Global, so we can always 2221 locate the appropriate list */ 2222 2223 /* Update the clones */ 2224 Class = Class->pclsClone; 2225 while (Class != NULL) 2226 { 2227 Class->style = (UINT)NewLong; 2228 Class = Class->pclsNext; 2229 } 2230 break; 2231 2232 case GCLP_WNDPROC: 2233 Ret = (ULONG_PTR)IntSetClassWndProc(Class, 2234 (WNDPROC)NewLong, 2235 Ansi); 2236 break; 2237 2238 case GCW_ATOM: 2239 { 2240 PUNICODE_STRING Value = (PUNICODE_STRING)NewLong; 2241 2242 Ret = (ULONG_PTR)Class->atomNVClassName; 2243 if (!IntSetClassAtom(Class, 2244 Value)) 2245 { 2246 Ret = 0; 2247 } 2248 break; 2249 } 2250 2251 default: 2252 EngSetLastError(ERROR_INVALID_INDEX); 2253 break; 2254 } 2255 2256 return Ret; 2257 } 2258 2259 static BOOL 2260 UserGetClassInfo(IN PCLS Class, 2261 OUT PWNDCLASSEXW lpwcx, 2262 IN BOOL Ansi, 2263 HINSTANCE hInstance) 2264 { 2265 if (!Class) return FALSE; 2266 2267 lpwcx->style = Class->style; 2268 2269 // If fnId is set, clear the global bit. See wine class test check_style. 2270 if (Class->fnid) 2271 lpwcx->style &= ~CS_GLOBALCLASS; 2272 2273 lpwcx->lpfnWndProc = IntGetClassWndProc(Class, Ansi); 2274 2275 lpwcx->cbClsExtra = Class->cbclsExtra; 2276 lpwcx->cbWndExtra = Class->cbwndExtra; 2277 lpwcx->hIcon = Class->spicn ? UserHMGetHandle(Class->spicn) : NULL; 2278 lpwcx->hCursor = Class->spcur ? UserHMGetHandle(Class->spcur) : NULL; 2279 lpwcx->hIconSm = Class->spicnSm ? UserHMGetHandle(Class->spicnSm) : NULL; 2280 lpwcx->hbrBackground = Class->hbrBackground; 2281 2282 /* Copy non-string to user first. */ 2283 if (Ansi) 2284 ((PWNDCLASSEXA)lpwcx)->lpszMenuName = Class->lpszClientAnsiMenuName; 2285 else 2286 lpwcx->lpszMenuName = Class->lpszClientUnicodeMenuName; 2287 /* 2288 * FIXME: CLSMENUNAME has the answers! Copy the already made buffers from there! 2289 * Cls: lpszMenuName and lpszAnsiClassName should be used by kernel space. 2290 * lpszClientXxxMenuName should already be mapped to user space. 2291 */ 2292 /* Copy string ptr to user. */ 2293 if ( Class->lpszClientUnicodeMenuName != NULL && 2294 Class->MenuNameIsString) 2295 { 2296 lpwcx->lpszMenuName = UserHeapAddressToUser(Ansi ? 2297 (PVOID)Class->lpszClientAnsiMenuName : 2298 (PVOID)Class->lpszClientUnicodeMenuName); 2299 } 2300 2301 if (hInstance == hModClient) 2302 lpwcx->hInstance = NULL; 2303 else 2304 lpwcx->hInstance = hInstance; 2305 2306 /* FIXME: Return the string? Okay! This is performed in User32! */ 2307 //lpwcx->lpszClassName = (LPCWSTR)((ULONG_PTR)Class->atomClassName); 2308 2309 return TRUE; 2310 } 2311 2312 // 2313 // Register System Classes.... 2314 // 2315 BOOL 2316 FASTCALL 2317 UserRegisterSystemClasses(VOID) 2318 { 2319 UINT i; 2320 UNICODE_STRING ClassName, MenuName; 2321 PPROCESSINFO ppi = GetW32ProcessInfo(); 2322 WNDCLASSEXW wc; 2323 PCLS Class; 2324 BOOL Ret = TRUE; 2325 HBRUSH hBrush; 2326 DWORD Flags = 0; 2327 2328 if (ppi->W32PF_flags & W32PF_CLASSESREGISTERED) 2329 return TRUE; 2330 2331 if ( hModClient == NULL) 2332 return FALSE; 2333 2334 RtlZeroMemory(&ClassName, sizeof(ClassName)); 2335 RtlZeroMemory(&MenuName, sizeof(MenuName)); 2336 2337 for (i = 0; i != ARRAYSIZE(DefaultServerClasses); i++) 2338 { 2339 if (!IS_ATOM(DefaultServerClasses[i].ClassName)) 2340 { 2341 RtlInitUnicodeString(&ClassName, DefaultServerClasses[i].ClassName); 2342 } 2343 else 2344 { 2345 ClassName.Buffer = DefaultServerClasses[i].ClassName; 2346 ClassName.Length = 0; 2347 ClassName.MaximumLength = 0; 2348 } 2349 2350 wc.cbSize = sizeof(wc); 2351 wc.style = DefaultServerClasses[i].Style; 2352 2353 Flags |= CSF_SERVERSIDEPROC; 2354 2355 if (DefaultServerClasses[i].ProcW) 2356 { 2357 wc.lpfnWndProc = DefaultServerClasses[i].ProcW; 2358 wc.hInstance = hModuleWin; 2359 } 2360 else 2361 { 2362 wc.lpfnWndProc = GETPFNSERVER(DefaultServerClasses[i].fiId); 2363 wc.hInstance = hModClient; 2364 } 2365 2366 wc.cbClsExtra = 0; 2367 wc.cbWndExtra = DefaultServerClasses[i].ExtraBytes; 2368 wc.hIcon = NULL; 2369 2370 //// System Cursors should be initilized!!! 2371 wc.hCursor = NULL; 2372 if (DefaultServerClasses[i].hCursor == (HICON)OCR_NORMAL) 2373 { 2374 if (SYSTEMCUR(ARROW) == NULL) 2375 { 2376 ERR("SYSTEMCUR(ARROW) == NULL, should not happen!!\n"); 2377 } 2378 else 2379 { 2380 wc.hCursor = UserHMGetHandle(SYSTEMCUR(ARROW)); 2381 } 2382 } 2383 2384 hBrush = DefaultServerClasses[i].hBrush; 2385 if (hBrush <= (HBRUSH)COLOR_MENUBAR) 2386 { 2387 hBrush = IntGetSysColorBrush(HandleToUlong(hBrush)); 2388 } 2389 wc.hbrBackground = hBrush; 2390 wc.lpszMenuName = NULL; 2391 wc.lpszClassName = ClassName.Buffer; 2392 wc.hIconSm = NULL; 2393 2394 Class = IntCreateClass( &wc, 2395 &ClassName, 2396 &ClassName, 2397 &MenuName, 2398 DefaultServerClasses[i].fiId, 2399 Flags, 2400 NULL, 2401 ppi); 2402 if (Class != NULL) 2403 { 2404 Class->pclsNext = ppi->pclsPublicList; 2405 (void)InterlockedExchangePointer((PVOID*)&ppi->pclsPublicList, 2406 Class); 2407 2408 ppi->dwRegisteredClasses |= ICLASS_TO_MASK(DefaultServerClasses[i].iCls); 2409 } 2410 else 2411 { 2412 ERR("!!! Registering system class failed!\n"); 2413 Ret = FALSE; 2414 } 2415 } 2416 if (Ret) ppi->W32PF_flags |= W32PF_CLASSESREGISTERED; 2417 return Ret; 2418 } 2419 2420 /* SYSCALLS *****************************************************************/ 2421 2422 RTL_ATOM 2423 APIENTRY 2424 NtUserRegisterClassExWOW( 2425 WNDCLASSEXW* lpwcx, 2426 PUNICODE_STRING ClassName, 2427 PUNICODE_STRING ClsVersion, 2428 PCLSMENUNAME pClassMenuName, 2429 DWORD fnID, 2430 DWORD Flags, 2431 LPDWORD pWow) 2432 /* 2433 * FUNCTION: 2434 * Registers a new class with the window manager 2435 * ARGUMENTS: 2436 * lpwcx = Win32 extended window class structure 2437 * bUnicodeClass = Whether to send ANSI or unicode strings 2438 * to window procedures 2439 * RETURNS: 2440 * Atom identifying the new class 2441 */ 2442 { 2443 WNDCLASSEXW CapturedClassInfo = {0}; 2444 UNICODE_STRING CapturedName = {0}, CapturedMenuName = {0}, CapturedVersion = {0}; 2445 RTL_ATOM Ret = (RTL_ATOM)0; 2446 PPROCESSINFO ppi = GetW32ProcessInfo(); 2447 BOOL Exception = FALSE; 2448 2449 if (Flags & ~(CSF_ANSIPROC)) 2450 { 2451 ERR("NtUserRegisterClassExWOW Bad Flags!\n"); 2452 EngSetLastError(ERROR_INVALID_FLAGS); 2453 return Ret; 2454 } 2455 2456 UserEnterExclusive(); 2457 2458 TRACE("NtUserRegisterClassExWOW ClsN %wZ\n",ClassName); 2459 2460 if ( !(ppi->W32PF_flags & W32PF_CLASSESREGISTERED )) 2461 { 2462 UserRegisterSystemClasses(); 2463 } 2464 2465 _SEH2_TRY 2466 { 2467 /* Probe the parameters and basic parameter checks */ 2468 if (ProbeForReadUint(&lpwcx->cbSize) != sizeof(WNDCLASSEXW)) 2469 { 2470 ERR("NtUserRegisterClassExWOW Wrong cbSize!\n"); 2471 goto InvalidParameter; 2472 } 2473 2474 ProbeForRead(lpwcx, 2475 sizeof(WNDCLASSEXW), 2476 sizeof(ULONG)); 2477 RtlCopyMemory(&CapturedClassInfo, 2478 lpwcx, 2479 sizeof(WNDCLASSEXW)); 2480 2481 CapturedName = ProbeForReadUnicodeString(ClassName); 2482 CapturedVersion = ProbeForReadUnicodeString(ClsVersion); 2483 2484 ProbeForRead(pClassMenuName, 2485 sizeof(CLSMENUNAME), 2486 1); 2487 2488 CapturedMenuName = ProbeForReadUnicodeString(pClassMenuName->pusMenuName); 2489 2490 if ( (CapturedName.Length & 1) || 2491 (CapturedMenuName.Length & 1) || 2492 (CapturedClassInfo.cbClsExtra < 0) || 2493 ((CapturedClassInfo.cbClsExtra + CapturedName.Length + 2494 CapturedMenuName.Length + sizeof(CLS)) 2495 < (ULONG)CapturedClassInfo.cbClsExtra) || 2496 (CapturedClassInfo.cbWndExtra < 0) || 2497 (CapturedClassInfo.hInstance == NULL) ) 2498 { 2499 ERR("NtUserRegisterClassExWOW Invalid Parameter Error!\n"); 2500 goto InvalidParameter; 2501 } 2502 2503 if (CapturedName.Length != 0) 2504 { 2505 ProbeForRead(CapturedName.Buffer, 2506 CapturedName.Length, 2507 sizeof(WCHAR)); 2508 } 2509 else 2510 { 2511 if (!IS_ATOM(CapturedName.Buffer)) 2512 { 2513 ERR("NtUserRegisterClassExWOW ClassName Error!\n"); 2514 goto InvalidParameter; 2515 } 2516 } 2517 2518 if (CapturedVersion.Length != 0) 2519 { 2520 ProbeForRead(CapturedVersion.Buffer, 2521 CapturedVersion.Length, 2522 sizeof(WCHAR)); 2523 } 2524 else 2525 { 2526 if (!IS_ATOM(CapturedVersion.Buffer)) 2527 { 2528 ERR("NtUserRegisterClassExWOW ClassName Error!\n"); 2529 goto InvalidParameter; 2530 } 2531 } 2532 2533 if (CapturedMenuName.Length != 0) 2534 { 2535 ProbeForRead(CapturedMenuName.Buffer, 2536 CapturedMenuName.Length, 2537 sizeof(WCHAR)); 2538 } 2539 else if (CapturedMenuName.Buffer != NULL && 2540 !IS_INTRESOURCE(CapturedMenuName.Buffer)) 2541 { 2542 ERR("NtUserRegisterClassExWOW MenuName Error!\n"); 2543 InvalidParameter: 2544 EngSetLastError(ERROR_INVALID_PARAMETER); 2545 _SEH2_LEAVE; 2546 } 2547 2548 if (IsCallProcHandle(lpwcx->lpfnWndProc)) 2549 { // Never seen this yet, but I'm sure it's a little haxxy trick! 2550 // If this pops up we know what todo! 2551 ERR("NtUserRegisterClassExWOW WndProc is CallProc!!\n"); 2552 } 2553 2554 TRACE("NtUserRegisterClassExWOW MnuN %wZ\n",&CapturedMenuName); 2555 } 2556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2557 { 2558 ERR("NtUserRegisterClassExWOW Exception Error!\n"); 2559 SetLastNtError(_SEH2_GetExceptionCode()); 2560 Exception = TRUE; 2561 } 2562 _SEH2_END; 2563 2564 if (!Exception) 2565 { 2566 /* Register the class */ 2567 Ret = UserRegisterClass(&CapturedClassInfo, 2568 &CapturedName, 2569 &CapturedVersion, 2570 &CapturedMenuName, 2571 fnID, 2572 Flags); 2573 } 2574 2575 if (!Ret) 2576 { 2577 TRACE("NtUserRegisterClassExWOW Null Return!\n"); 2578 } 2579 2580 UserLeave(); 2581 2582 return Ret; 2583 } 2584 2585 ULONG_PTR APIENTRY 2586 NtUserSetClassLong(HWND hWnd, 2587 INT Offset, 2588 ULONG_PTR dwNewLong, 2589 BOOL Ansi) 2590 { 2591 PPROCESSINFO pi; 2592 PWND Window; 2593 ULONG_PTR Ret = 0; 2594 2595 UserEnterExclusive(); 2596 2597 pi = GetW32ProcessInfo(); 2598 2599 Window = UserGetWindowObject(hWnd); 2600 if (Window != NULL) 2601 { 2602 if (Window->head.pti->ppi != pi) 2603 { 2604 EngSetLastError(ERROR_ACCESS_DENIED); 2605 goto Cleanup; 2606 } 2607 2608 _SEH2_TRY 2609 { 2610 UNICODE_STRING Value; 2611 2612 /* Probe the parameters */ 2613 if (Offset == GCW_ATOM || Offset == GCLP_MENUNAME) 2614 { 2615 /* FIXME: Resource ID can be passed directly without UNICODE_STRING ? */ 2616 if (IS_ATOM(dwNewLong)) 2617 { 2618 Value.MaximumLength = 0; 2619 Value.Length = 0; 2620 Value.Buffer = (PWSTR)dwNewLong; 2621 } 2622 else 2623 { 2624 Value = ProbeForReadUnicodeString((PUNICODE_STRING)dwNewLong); 2625 } 2626 2627 if (Value.Length & 1) 2628 { 2629 goto InvalidParameter; 2630 } 2631 2632 if (Value.Length != 0) 2633 { 2634 ProbeForRead(Value.Buffer, 2635 Value.Length, 2636 sizeof(WCHAR)); 2637 } 2638 else 2639 { 2640 if (Offset == GCW_ATOM && !IS_ATOM(Value.Buffer)) 2641 { 2642 goto InvalidParameter; 2643 } 2644 else if (Offset == GCLP_MENUNAME && !IS_INTRESOURCE(Value.Buffer)) 2645 { 2646 InvalidParameter: 2647 EngSetLastError(ERROR_INVALID_PARAMETER); 2648 _SEH2_LEAVE; 2649 } 2650 } 2651 2652 dwNewLong = (ULONG_PTR)&Value; 2653 } 2654 2655 Ret = UserSetClassLongPtr(Window->pcls, 2656 Offset, 2657 dwNewLong, 2658 Ansi); 2659 switch(Offset) 2660 { 2661 case GCLP_HICONSM: 2662 case GCLP_HICON: 2663 { 2664 if (Ret && Ret != dwNewLong) 2665 UserPaintCaption(Window, DC_ICON); 2666 } 2667 } 2668 } 2669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2670 { 2671 SetLastNtError(_SEH2_GetExceptionCode()); 2672 } 2673 _SEH2_END; 2674 } 2675 2676 Cleanup: 2677 UserLeave(); 2678 2679 return Ret; 2680 } 2681 2682 WORD 2683 APIENTRY 2684 NtUserSetClassWord( 2685 HWND hWnd, 2686 INT nIndex, 2687 WORD wNewWord) 2688 { 2689 /* 2690 * NOTE: Obsoleted in 32-bit windows 2691 */ 2692 return(0); 2693 } 2694 2695 BOOL 2696 APIENTRY 2697 NtUserUnregisterClass( 2698 IN PUNICODE_STRING ClassNameOrAtom, 2699 IN HINSTANCE hInstance, 2700 OUT PCLSMENUNAME pClassMenuName) 2701 { 2702 UNICODE_STRING SafeClassName; 2703 NTSTATUS Status; 2704 BOOL Ret; 2705 2706 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassNameOrAtom); 2707 if (!NT_SUCCESS(Status)) 2708 { 2709 ERR("Error capturing the class name\n"); 2710 SetLastNtError(Status); 2711 return FALSE; 2712 } 2713 2714 UserEnterExclusive(); 2715 2716 /* Unregister the class */ 2717 Ret = UserUnregisterClass(&SafeClassName, hInstance, NULL); // Null for now~ 2718 2719 UserLeave(); 2720 2721 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer)) 2722 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING); 2723 2724 return Ret; 2725 } 2726 2727 2728 /* NOTE: For system classes hInstance is not NULL here, but User32Instance */ 2729 BOOL 2730 APIENTRY 2731 NtUserGetClassInfo( 2732 HINSTANCE hInstance, 2733 PUNICODE_STRING ClassName, 2734 LPWNDCLASSEXW lpWndClassEx, 2735 LPWSTR *ppszMenuName, 2736 BOOL bAnsi) 2737 { 2738 UNICODE_STRING SafeClassName; 2739 WNDCLASSEXW Safewcexw; 2740 PCLS Class; 2741 RTL_ATOM ClassAtom = 0; 2742 PPROCESSINFO ppi; 2743 BOOL Ret = TRUE; 2744 NTSTATUS Status; 2745 2746 _SEH2_TRY 2747 { 2748 ProbeForWrite( lpWndClassEx, sizeof(WNDCLASSEXW), sizeof(ULONG)); 2749 RtlCopyMemory( &Safewcexw, lpWndClassEx, sizeof(WNDCLASSEXW)); 2750 if (ppszMenuName) 2751 { 2752 ProbeForWrite(ppszMenuName, sizeof(*ppszMenuName), sizeof(PVOID)); 2753 } 2754 } 2755 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2756 { 2757 SetLastNtError(_SEH2_GetExceptionCode()); 2758 _SEH2_YIELD(return FALSE); 2759 } 2760 _SEH2_END; 2761 2762 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName); 2763 if (!NT_SUCCESS(Status)) 2764 { 2765 ERR("Error capturing the class name\n"); 2766 SetLastNtError(Status); 2767 return FALSE; 2768 } 2769 2770 // If null instance use client. 2771 if (!hInstance) hInstance = hModClient; 2772 2773 TRACE("GetClassInfo(%wZ, %p)\n", &SafeClassName, hInstance); 2774 2775 /* NOTE: Need exclusive lock because getting the wndproc might require the 2776 creation of a call procedure handle */ 2777 UserEnterExclusive(); 2778 2779 ppi = GetW32ProcessInfo(); 2780 if (!(ppi->W32PF_flags & W32PF_CLASSESREGISTERED)) 2781 { 2782 UserRegisterSystemClasses(); 2783 } 2784 2785 ClassAtom = IntGetClassAtom(&SafeClassName, 2786 hInstance, 2787 ppi, 2788 &Class, 2789 NULL); 2790 if (ClassAtom != (RTL_ATOM)0) 2791 { 2792 ClassAtom = Class->atomNVClassName; 2793 Ret = UserGetClassInfo(Class, &Safewcexw, bAnsi, hInstance); 2794 } 2795 else 2796 { 2797 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST); 2798 Ret = FALSE; 2799 } 2800 2801 UserLeave(); 2802 2803 if (Ret) 2804 { 2805 _SEH2_TRY 2806 { 2807 /* Emulate Function. */ 2808 if (ppszMenuName) *ppszMenuName = (LPWSTR)Safewcexw.lpszMenuName; 2809 2810 RtlCopyMemory(lpWndClassEx, &Safewcexw, sizeof(WNDCLASSEXW)); 2811 2812 // From Wine: 2813 /* We must return the atom of the class here instead of just TRUE. */ 2814 /* Undocumented behavior! Return the class atom as a BOOL! */ 2815 Ret = (BOOL)ClassAtom; 2816 } 2817 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2818 { 2819 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST); 2820 Ret = FALSE; 2821 } 2822 _SEH2_END; 2823 } 2824 2825 if (!IS_ATOM(SafeClassName.Buffer)) 2826 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING); 2827 2828 return Ret; 2829 } 2830 2831 2832 INT APIENTRY 2833 NtUserGetClassName (IN HWND hWnd, 2834 IN BOOL Real, 2835 OUT PUNICODE_STRING ClassName) 2836 { 2837 PWND Window; 2838 UNICODE_STRING CapturedClassName; 2839 INT iCls, Ret = 0; 2840 RTL_ATOM Atom = 0; 2841 2842 UserEnterShared(); 2843 2844 Window = UserGetWindowObject(hWnd); 2845 if (Window != NULL) 2846 { 2847 if (Real && Window->fnid && !(Window->fnid & FNID_DESTROY)) 2848 { 2849 if (LookupFnIdToiCls(Window->fnid, &iCls)) 2850 { 2851 Atom = gpsi->atomSysClass[iCls]; 2852 } 2853 } 2854 2855 _SEH2_TRY 2856 { 2857 ProbeForWriteUnicodeString(ClassName); 2858 CapturedClassName = *ClassName; 2859 if (CapturedClassName.Length != 0) 2860 { 2861 ProbeForRead(CapturedClassName.Buffer, 2862 CapturedClassName.Length, 2863 sizeof(WCHAR)); 2864 } 2865 2866 /* Get the class name */ 2867 Ret = UserGetClassName(Window->pcls, 2868 &CapturedClassName, 2869 Atom, 2870 FALSE); 2871 2872 if (Ret != 0) 2873 { 2874 /* Update the Length field */ 2875 ClassName->Length = CapturedClassName.Length; 2876 } 2877 } 2878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2879 { 2880 SetLastNtError(_SEH2_GetExceptionCode()); 2881 } 2882 _SEH2_END; 2883 } 2884 2885 UserLeave(); 2886 2887 return Ret; 2888 } 2889 2890 /* Return Pointer to Class structure. */ 2891 PCLS 2892 APIENTRY 2893 NtUserGetWOWClass( 2894 HINSTANCE hInstance, 2895 PUNICODE_STRING ClassName) 2896 { 2897 UNICODE_STRING SafeClassName; 2898 PPROCESSINFO pi; 2899 PCLS Class = NULL; 2900 RTL_ATOM ClassAtom = 0; 2901 NTSTATUS Status; 2902 2903 Status = ProbeAndCaptureUnicodeStringOrAtom(&SafeClassName, ClassName); 2904 if (!NT_SUCCESS(Status)) 2905 { 2906 ERR("Error capturing the class name\n"); 2907 SetLastNtError(Status); 2908 return FALSE; 2909 } 2910 2911 UserEnterExclusive(); 2912 2913 pi = GetW32ProcessInfo(); 2914 2915 ClassAtom = IntGetClassAtom(&SafeClassName, 2916 hInstance, 2917 pi, 2918 &Class, 2919 NULL); 2920 if (!ClassAtom) 2921 { 2922 EngSetLastError(ERROR_CLASS_DOES_NOT_EXIST); 2923 } 2924 2925 2926 if (SafeClassName.Buffer && !IS_ATOM(SafeClassName.Buffer)) 2927 ExFreePoolWithTag(SafeClassName.Buffer, TAG_STRING); 2928 2929 UserLeave(); 2930 // 2931 // Don't forget to use DesktopPtrToUser( ? ) with return pointer in user space. 2932 // 2933 return Class; 2934 } 2935 2936 /* EOF */ 2937