1 /* 2 * PROJECT: ReactOS user32.dll 3 * COPYRIGHT: GPL - See COPYING in the top level directory 4 * FILE: win32ss/user/user32/windows/class.c 5 * PURPOSE: Window classes 6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * UPDATE HISTORY: 8 * 09-05-2001 CSH Created 9 */ 10 11 #include <user32.h> 12 13 WINE_DEFAULT_DEBUG_CHANNEL(user32); 14 15 #define USE_VERSIONED_CLASSES 16 17 /* From rtl/actctx.c and must match! */ 18 struct strsection_header 19 { 20 DWORD magic; 21 ULONG size; 22 DWORD unk1[3]; 23 ULONG count; 24 ULONG index_offset; 25 DWORD unk2[2]; 26 ULONG global_offset; 27 ULONG global_len; 28 }; 29 30 struct wndclass_redirect_data 31 { 32 ULONG size; 33 DWORD res; 34 ULONG name_len; 35 ULONG name_offset; /* versioned name offset */ 36 ULONG module_len; 37 ULONG module_offset;/* container name offset */ 38 }; 39 40 // 41 // Use wine hack to process extended context classes. 42 // 43 /*********************************************************************** 44 * is_comctl32_class 45 */ 46 LPCWSTR is_comctl32_class( const WCHAR *name ) 47 { 48 static const WCHAR classesW[][20] = 49 { 50 {'C','o','m','b','o','B','o','x','E','x','3','2',0}, 51 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0}, 52 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0}, 53 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0}, 54 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0}, 55 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0}, 56 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0}, 57 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0}, 58 {'S','y','s','A','n','i','m','a','t','e','3','2',0}, 59 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0}, 60 {'S','y','s','H','e','a','d','e','r','3','2',0}, 61 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0}, 62 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0}, 63 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0}, 64 {'S','y','s','P','a','g','e','r',0}, 65 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0}, 66 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0}, 67 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0}, 68 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0}, 69 }; 70 71 int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1; 72 73 while (min <= max) 74 { 75 int res, pos = (min + max) / 2; 76 if (!(res = strcmpiW( name, classesW[pos] ))) return classesW[pos]; 77 if (res < 0) max = pos - 1; 78 else min = pos + 1; 79 } 80 return NULL; 81 } 82 83 LPCWSTR 84 FASTCALL 85 ClassNameToVersion( 86 const void* lpszClass, 87 LPCWSTR lpszMenuName, 88 LPCWSTR *plpLibFileName, 89 HANDLE *pContext, 90 BOOL bAnsi) 91 { 92 LPCWSTR VersionedClass = NULL; 93 #ifdef USE_VERSIONED_CLASSES 94 NTSTATUS Status; 95 #endif 96 UNICODE_STRING SectionName; 97 WCHAR SectionNameBuf[MAX_PATH] = {0}; 98 ACTCTX_SECTION_KEYED_DATA KeyedData = { sizeof(KeyedData) }; 99 100 if (!lpszClass) 101 { 102 ERR("Null class given !\n"); 103 return NULL; 104 } 105 106 if (IS_ATOM(lpszClass)) 107 { 108 RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf)); 109 if(!NtUserGetAtomName(LOWORD((DWORD_PTR)lpszClass), &SectionName)) 110 { 111 ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR)lpszClass)); 112 return NULL; 113 } 114 SectionName.Length = (USHORT)wcslen(SectionNameBuf) * sizeof(WCHAR); 115 TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName); 116 } 117 else 118 { 119 if (bAnsi) 120 { 121 ANSI_STRING AnsiString; 122 RtlInitAnsiString(&AnsiString, lpszClass); 123 RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf)); 124 RtlAnsiStringToUnicodeString(&SectionName, &AnsiString, FALSE); 125 } 126 else 127 { 128 RtlInitUnicodeString(&SectionName, lpszClass); 129 } 130 } 131 #ifdef USE_VERSIONED_CLASSES 132 Status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 133 NULL, 134 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, 135 &SectionName, 136 &KeyedData ); 137 138 if (NT_SUCCESS(Status) && KeyedData.ulDataFormatVersion == 1) 139 { 140 struct strsection_header *SectionHeader = KeyedData.lpSectionBase; 141 142 /* Find activation context */ 143 if(SectionHeader && SectionHeader->count > 0) 144 { 145 struct wndclass_redirect_data *WindowRedirectionData = KeyedData.lpData; 146 if(WindowRedirectionData && WindowRedirectionData->module_len) 147 { 148 LPCWSTR lpLibFileName; 149 150 VersionedClass = (WCHAR*)((BYTE*)WindowRedirectionData + WindowRedirectionData->name_offset); 151 lpLibFileName = (WCHAR*)((BYTE*)KeyedData.lpSectionBase + WindowRedirectionData->module_offset); 152 TRACE("Returning VersionedClass=%S, plpLibFileName=%S for class %S\n", VersionedClass, lpLibFileName, SectionName.Buffer); 153 154 if (pContext) *pContext = KeyedData.hActCtx; 155 if (plpLibFileName) *plpLibFileName = lpLibFileName; 156 157 } 158 } 159 } 160 161 if (KeyedData.hActCtx) 162 RtlReleaseActivationContext(KeyedData.hActCtx); 163 #endif 164 165 #ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED 166 /* This block is a hack! */ 167 if (!VersionedClass) 168 { 169 /* 170 * In windows the default activation context always contains comctl32v5 171 * In reactos we don't have a default activation context so we 172 * mimic wine here. 173 */ 174 VersionedClass = is_comctl32_class(SectionName.Buffer); 175 if (VersionedClass) 176 { 177 if (pContext) *pContext = 0; 178 if (plpLibFileName) *plpLibFileName = L"comctl32"; 179 } 180 } 181 #endif 182 183 /* 184 * The returned strings are pointers in the activation context and 185 * will get freed when the activation context gets freed 186 */ 187 return VersionedClass; 188 } 189 190 // 191 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html 192 // 193 BOOL 194 FASTCALL 195 VersionRegisterClass( 196 PCWSTR pszClass, 197 LPCWSTR lpLibFileName, 198 HANDLE Contex, 199 HMODULE * phLibModule) 200 { 201 BOOL Ret = FALSE; 202 HMODULE hLibModule = NULL; 203 PREGISTERCLASSNAMEW pRegisterClassNameW; 204 UNICODE_STRING ClassName; 205 WCHAR ClassNameBuf[MAX_PATH] = {0}; 206 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame = { sizeof(Frame), 1 }; 207 208 ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S.\n", lpLibFileName); 209 210 RtlActivateActivationContextUnsafeFast(&Frame, Contex); 211 212 _SEH2_TRY 213 { 214 hLibModule = LoadLibraryW(lpLibFileName); 215 if (hLibModule) 216 { 217 if ((pRegisterClassNameW = (void*)GetProcAddress(hLibModule, "RegisterClassNameW"))) 218 { 219 if (IS_ATOM(pszClass)) 220 { 221 RtlInitEmptyUnicodeString(&ClassName, ClassNameBuf, sizeof(ClassNameBuf)); 222 if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName)) 223 { 224 ERR("Error while verifying ATOM\n"); 225 _SEH2_YIELD(goto Error_Exit); 226 } 227 pszClass = ClassName.Buffer; 228 } 229 Ret = pRegisterClassNameW(pszClass); 230 } 231 else 232 { 233 WARN("No RegisterClassNameW PROC\n"); 234 } 235 } 236 } 237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 238 { 239 ERR("Got exception while trying to call RegisterClassNameW!\n"); 240 } 241 _SEH2_END 242 243 Error_Exit: 244 if (Ret || !hLibModule) 245 { 246 if (phLibModule) *phLibModule = hLibModule; 247 } 248 else 249 { 250 DWORD dwLastError = GetLastError(); 251 FreeLibrary(hLibModule); 252 SetLastError(dwLastError); 253 } 254 255 RtlDeactivateActivationContextUnsafeFast(&Frame); 256 return Ret; 257 } 258 259 /* 260 * @implemented 261 */ 262 BOOL 263 WINAPI 264 GetClassInfoExA( 265 HINSTANCE hInstance, 266 LPCSTR lpszClass, 267 LPWNDCLASSEXA lpwcx) 268 { 269 UNICODE_STRING ClassName = {0}; 270 LPCSTR pszMenuName; 271 HMODULE hLibModule = NULL; 272 DWORD dwLastError; 273 BOOL Ret, ClassFound = FALSE, ConvertedString = FALSE; 274 LPCWSTR lpszClsVersion; 275 HANDLE pCtx = NULL; 276 LPCWSTR lpLibFileName = NULL; 277 278 TRACE("%p class/atom: %s/%04x %p\n", hInstance, 279 IS_ATOM(lpszClass) ? NULL : lpszClass, 280 IS_ATOM(lpszClass) ? lpszClass : 0, 281 lpwcx); 282 283 if (!lpwcx) 284 { 285 SetLastError(ERROR_NOACCESS); 286 return FALSE; 287 } 288 289 if (hInstance == User32Instance) 290 { 291 hInstance = NULL; 292 } 293 294 if (lpszClass == NULL) 295 { 296 SetLastError(ERROR_INVALID_PARAMETER); 297 return FALSE; 298 } 299 300 lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, TRUE); 301 if (lpszClsVersion) 302 { 303 RtlInitUnicodeString(&ClassName, lpszClsVersion); 304 } 305 else if (IS_ATOM(lpszClass)) 306 { 307 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass); 308 } 309 else 310 { 311 ConvertedString = TRUE; 312 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass)) 313 { 314 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 315 return FALSE; 316 } 317 } 318 319 if (!RegisterDefaultClasses) 320 { 321 TRACE("RegisterSystemControls\n"); 322 RegisterSystemControls(); 323 } 324 325 for(;;) 326 { 327 Ret = NtUserGetClassInfo(hInstance, 328 &ClassName, 329 (LPWNDCLASSEXW)lpwcx, 330 (LPWSTR *)&pszMenuName, 331 TRUE); 332 if (Ret) break; 333 if (!lpLibFileName) break; 334 if (!ClassFound) 335 { 336 dwLastError = GetLastError(); 337 if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS || 338 dwLastError == ERROR_CLASS_DOES_NOT_EXIST ) 339 { 340 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule); 341 if (ClassFound) continue; 342 } 343 } 344 if (hLibModule) 345 { 346 dwLastError = GetLastError(); 347 FreeLibrary(hLibModule); 348 SetLastError(dwLastError); 349 hLibModule = 0; 350 } 351 break; 352 } 353 354 if (Ret) 355 { 356 lpwcx->lpszClassName = lpszClass; 357 // lpwcx->lpszMenuName = pszMenuName; 358 } 359 360 if (ConvertedString) 361 { 362 RtlFreeUnicodeString(&ClassName); 363 } 364 365 return Ret; 366 } 367 368 369 /* 370 * @implemented 371 */ 372 BOOL 373 WINAPI 374 GetClassInfoExW( 375 HINSTANCE hInstance, 376 LPCWSTR lpszClass, 377 LPWNDCLASSEXW lpwcx) 378 { 379 UNICODE_STRING ClassName = {0}; 380 LPWSTR pszMenuName; 381 HMODULE hLibModule = NULL; 382 DWORD dwLastError; 383 BOOL Ret, ClassFound = FALSE; 384 LPCWSTR lpszClsVersion; 385 HANDLE pCtx = NULL; 386 LPCWSTR lpLibFileName = NULL; 387 388 TRACE("%p class/atom: %S/%04x %p\n", hInstance, 389 IS_ATOM(lpszClass) ? NULL : lpszClass, 390 IS_ATOM(lpszClass) ? lpszClass : 0, 391 lpwcx); 392 393 /* From wine, for speed only, ReactOS supports the correct return in 394 * Win32k. cbSize is ignored. 395 */ 396 if (!lpwcx) 397 { 398 SetLastError( ERROR_NOACCESS ); 399 return FALSE; 400 } 401 402 if (hInstance == User32Instance) 403 { 404 hInstance = NULL; 405 } 406 407 if (lpszClass == NULL) 408 { 409 SetLastError(ERROR_INVALID_PARAMETER); 410 return FALSE; 411 } 412 413 lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, FALSE); 414 if (lpszClsVersion) 415 { 416 RtlInitUnicodeString(&ClassName, lpszClsVersion); 417 } 418 else if (IS_ATOM(lpszClass)) 419 { 420 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass); 421 } 422 else 423 { 424 RtlInitUnicodeString(&ClassName, lpszClass); 425 } 426 427 if (!RegisterDefaultClasses) 428 { 429 TRACE("RegisterSystemControls\n"); 430 RegisterSystemControls(); 431 } 432 433 for(;;) 434 { 435 Ret = NtUserGetClassInfo( hInstance, 436 &ClassName, 437 lpwcx, 438 &pszMenuName, 439 FALSE); 440 if (Ret) break; 441 if (!lpLibFileName) break; 442 if (!ClassFound) 443 { 444 dwLastError = GetLastError(); 445 if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS || 446 dwLastError == ERROR_CLASS_DOES_NOT_EXIST ) 447 { 448 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule); 449 if (ClassFound) continue; 450 } 451 } 452 if (hLibModule) 453 { 454 dwLastError = GetLastError(); 455 FreeLibrary(hLibModule); 456 SetLastError(dwLastError); 457 hLibModule = 0; 458 } 459 break; 460 } 461 462 if (Ret) 463 { 464 lpwcx->lpszClassName = lpszClass; 465 // lpwcx->lpszMenuName = pszMenuName; 466 } 467 return Ret; 468 } 469 470 471 /* 472 * @implemented 473 */ 474 BOOL 475 WINAPI 476 GetClassInfoA( 477 HINSTANCE hInstance, 478 LPCSTR lpClassName, 479 LPWNDCLASSA lpWndClass) 480 { 481 WNDCLASSEXA wcex; 482 BOOL retval; 483 484 retval = GetClassInfoExA(hInstance, lpClassName, &wcex); 485 if (retval) 486 { 487 lpWndClass->style = wcex.style; 488 lpWndClass->lpfnWndProc = wcex.lpfnWndProc; 489 lpWndClass->cbClsExtra = wcex.cbClsExtra; 490 lpWndClass->cbWndExtra = wcex.cbWndExtra; 491 lpWndClass->hInstance = wcex.hInstance; 492 lpWndClass->hIcon = wcex.hIcon; 493 lpWndClass->hCursor = wcex.hCursor; 494 lpWndClass->hbrBackground = wcex.hbrBackground; 495 lpWndClass->lpszMenuName = wcex.lpszMenuName; 496 lpWndClass->lpszClassName = wcex.lpszClassName; 497 } 498 499 return retval; 500 } 501 502 /* 503 * @implemented 504 */ 505 BOOL 506 WINAPI 507 GetClassInfoW( 508 HINSTANCE hInstance, 509 LPCWSTR lpClassName, 510 LPWNDCLASSW lpWndClass) 511 { 512 WNDCLASSEXW wcex; 513 BOOL retval; 514 515 retval = GetClassInfoExW(hInstance, lpClassName, &wcex); 516 if (retval) 517 { 518 lpWndClass->style = wcex.style; 519 lpWndClass->lpfnWndProc = wcex.lpfnWndProc; 520 lpWndClass->cbClsExtra = wcex.cbClsExtra; 521 lpWndClass->cbWndExtra = wcex.cbWndExtra; 522 lpWndClass->hInstance = wcex.hInstance; 523 lpWndClass->hIcon = wcex.hIcon; 524 lpWndClass->hCursor = wcex.hCursor; 525 lpWndClass->hbrBackground = wcex.hbrBackground; 526 lpWndClass->lpszMenuName = wcex.lpszMenuName; 527 lpWndClass->lpszClassName = wcex.lpszClassName; 528 } 529 return retval; 530 } 531 532 // 533 // Based on find_winproc... Fixes many whine tests...... 534 // 535 ULONG_PTR FASTCALL 536 IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi) 537 { 538 INT i; 539 ULONG_PTR gcpd, Ret = 0; 540 // If server side, sweep through proc list and return the client side proc. 541 if (Class->CSF_flags & CSF_SERVERSIDEPROC) 542 { // Always scan through the list due to wine class "deftest". 543 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++) 544 { 545 if (GETPFNSERVER(i) == Class->lpfnWndProc) 546 { 547 if (Ansi) 548 Ret = (ULONG_PTR)GETPFNCLIENTA(i); 549 else 550 Ret = (ULONG_PTR)GETPFNCLIENTW(i); 551 } 552 } 553 return Ret; 554 } 555 // Set return proc. 556 Ret = (ULONG_PTR)Class->lpfnWndProc; 557 // Return the proc if one of the FnId default class type. 558 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON) 559 { 560 if (Ansi) 561 { // If match return the right proc by type. 562 if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc) 563 Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid); 564 } 565 else 566 { 567 if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc) 568 Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid); 569 } 570 } 571 // Return on change or Ansi/Unicode proc equal. 572 if ( Ret != (ULONG_PTR)Class->lpfnWndProc || 573 Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) ) 574 return Ret; 575 576 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle. 577 This will force CallWindowProc to deal with it. */ 578 gcpd = NtUserGetCPD( UserHMGetHandle(pWnd), 579 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWndtoCls, 580 Ret); 581 582 return (gcpd ? gcpd : Ret); 583 } 584 585 // 586 // Based on IntGetClsWndProc 587 // 588 WNDPROC FASTCALL 589 IntGetWndProc(PWND pWnd, BOOL Ansi) 590 { 591 INT i; 592 WNDPROC gcpd, Ret = 0; 593 PCLS Class = DesktopPtrToUser(pWnd->pcls); 594 595 if (!Class) return Ret; 596 597 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC) 598 { 599 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++) 600 { 601 if (GETPFNSERVER(i) == pWnd->lpfnWndProc) 602 { 603 if (Ansi) 604 Ret = GETPFNCLIENTA(i); 605 else 606 Ret = GETPFNCLIENTW(i); 607 } 608 } 609 return Ret; 610 } 611 // Wine Class tests: 612 /* Edit controls are special - they return a wndproc handle when 613 GetWindowLongPtr is called with a different A/W. 614 On the other hand there is no W->A->W conversion so this control 615 is treated specially. 616 */ 617 if (Class->fnid == FNID_EDIT) 618 Ret = pWnd->lpfnWndProc; 619 else 620 { 621 // Set return proc. 622 Ret = pWnd->lpfnWndProc; 623 624 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON) 625 { 626 if (Ansi) 627 { 628 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc) 629 Ret = GETPFNCLIENTA(Class->fnid); 630 } 631 else 632 { 633 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc) 634 Ret = GETPFNCLIENTW(Class->fnid); 635 } 636 } 637 // Return on the change. 638 if ( Ret != pWnd->lpfnWndProc) 639 return Ret; 640 } 641 642 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) ) 643 return Ret; 644 645 gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd), 646 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow, 647 (ULONG_PTR)Ret); 648 649 return (gcpd ? gcpd : Ret); 650 } 651 652 static ULONG_PTR FASTCALL 653 IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex) 654 { 655 ULONG_PTR Ret = 0; 656 657 if (nIndex >= 0) 658 { 659 if (nIndex + sizeof(ULONG_PTR) < nIndex || 660 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra) 661 { 662 SetLastError(ERROR_INVALID_PARAMETER); 663 } 664 else 665 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex); 666 } 667 else 668 { 669 switch (nIndex) 670 { 671 case GCL_CBWNDEXTRA: 672 Ret = (ULONG_PTR)Class->cbwndExtra; 673 break; 674 675 case GCL_CBCLSEXTRA: 676 Ret = (ULONG_PTR)Class->cbclsExtra; 677 break; 678 679 case GCL_HBRBACKGROUND: 680 Ret = (ULONG_PTR)Class->hbrBackground; 681 if (Ret != 0 && Ret < 0x4000) 682 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1); 683 break; 684 685 case GCL_HMODULE: 686 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule); 687 Ret = (ULONG_PTR)Class->hModule; 688 break; 689 690 case GCL_MENUNAME: 691 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName; 692 break; 693 694 case GCL_STYLE: 695 Ret = (ULONG_PTR)Class->style; 696 break; 697 698 case GCW_ATOM: 699 Ret = (ULONG_PTR)Class->atomNVClassName; 700 break; 701 702 case GCLP_HCURSOR: 703 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0; 704 break; 705 706 case GCLP_HICON: 707 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0; 708 break; 709 710 case GCLP_HICONSM: 711 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0; 712 break; 713 714 case GCLP_WNDPROC: 715 Ret = IntGetClsWndProc(Wnd, Class, TRUE); 716 break; 717 718 default: 719 SetLastError(ERROR_INVALID_INDEX); 720 break; 721 } 722 } 723 724 return Ret; 725 } 726 727 static ULONG_PTR FASTCALL 728 IntGetClassLongW(PWND Wnd, PCLS Class, int nIndex) 729 { 730 ULONG_PTR Ret = 0; 731 732 if (nIndex >= 0) 733 { 734 if (nIndex + sizeof(ULONG_PTR) < nIndex || 735 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra) 736 { 737 SetLastError(ERROR_INVALID_PARAMETER); 738 } 739 else 740 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex); 741 } 742 else 743 { 744 switch (nIndex) 745 { 746 case GCL_CBWNDEXTRA: 747 Ret = (ULONG_PTR)Class->cbwndExtra; 748 break; 749 750 case GCL_CBCLSEXTRA: 751 Ret = (ULONG_PTR)Class->cbclsExtra; 752 break; 753 754 case GCLP_HBRBACKGROUND: 755 Ret = (ULONG_PTR)Class->hbrBackground; 756 if (Ret != 0 && Ret < 0x4000) 757 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1); 758 break; 759 760 case GCL_HMODULE: 761 Ret = (ULONG_PTR)Class->hModule; 762 break; 763 764 case GCLP_MENUNAME: 765 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName; 766 break; 767 768 case GCL_STYLE: 769 Ret = (ULONG_PTR)Class->style; 770 break; 771 772 case GCW_ATOM: 773 Ret = (ULONG_PTR)Class->atomNVClassName; 774 break; 775 776 case GCLP_HCURSOR: 777 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0; 778 break; 779 780 case GCLP_HICON: 781 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0; 782 break; 783 784 case GCLP_HICONSM: 785 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0; 786 break; 787 788 case GCLP_WNDPROC: 789 Ret = IntGetClsWndProc(Wnd, Class, FALSE); 790 break; 791 792 default: 793 SetLastError(ERROR_INVALID_INDEX); 794 break; 795 } 796 } 797 798 return Ret; 799 } 800 801 /* 802 * @implemented 803 */ 804 DWORD WINAPI 805 GetClassLongA(HWND hWnd, int nIndex) 806 { 807 PWND Wnd; 808 PCLS Class; 809 ULONG_PTR Ret = 0; 810 811 TRACE("%p %d\n", hWnd, nIndex); 812 813 Wnd = ValidateHwnd(hWnd); 814 if (!Wnd) 815 return 0; 816 817 _SEH2_TRY 818 { 819 Class = DesktopPtrToUser(Wnd->pcls); 820 if (Class != NULL) 821 { 822 #ifdef _WIN64 823 switch (nIndex) 824 { 825 case GCLP_HBRBACKGROUND: 826 case GCLP_HCURSOR: 827 case GCLP_HICON: 828 case GCLP_HICONSM: 829 case GCLP_HMODULE: 830 case GCLP_MENUNAME: 831 case GCLP_WNDPROC: 832 SetLastError(ERROR_INVALID_INDEX); 833 break; 834 835 default: 836 Ret = IntGetClassLongA(Wnd, Class, nIndex); 837 break; 838 } 839 #else 840 Ret = IntGetClassLongA(Wnd, Class, nIndex); 841 #endif 842 } 843 else 844 { 845 WARN("Invalid class for hwnd 0x%p!\n", hWnd); 846 } 847 } 848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 849 { 850 Ret = 0; 851 } 852 _SEH2_END; 853 854 return (DWORD)Ret; 855 } 856 857 /* 858 * @implemented 859 */ 860 DWORD WINAPI 861 GetClassLongW(HWND hWnd, int nIndex) 862 { 863 PWND Wnd; 864 PCLS Class; 865 ULONG_PTR Ret = 0; 866 867 TRACE("%p %d\n", hWnd, nIndex); 868 869 Wnd = ValidateHwnd(hWnd); 870 if (!Wnd) 871 return 0; 872 873 _SEH2_TRY 874 { 875 Class = DesktopPtrToUser(Wnd->pcls); 876 if (Class != NULL) 877 { 878 #ifdef _WIN64 879 switch (nIndex) 880 { 881 case GCLP_HBRBACKGROUND: 882 case GCLP_HCURSOR: 883 case GCLP_HICON: 884 case GCLP_HICONSM: 885 case GCLP_HMODULE: 886 case GCLP_MENUNAME: 887 case GCLP_WNDPROC: 888 SetLastError(ERROR_INVALID_INDEX); 889 break; 890 891 default: 892 Ret = IntGetClassLongW(Wnd, Class, nIndex); 893 break; 894 } 895 #else 896 Ret = IntGetClassLongW(Wnd, Class, nIndex); 897 #endif 898 } 899 else 900 { 901 WARN("Invalid class for hwnd 0x%p!\n", hWnd); 902 } 903 } 904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 905 { 906 Ret = 0; 907 } 908 _SEH2_END; 909 910 return (DWORD)Ret; 911 } 912 913 #ifdef _WIN64 914 /* 915 * @implemented 916 */ 917 ULONG_PTR 918 WINAPI 919 GetClassLongPtrA(HWND hWnd, 920 INT nIndex) 921 { 922 PWND Wnd; 923 PCLS Class; 924 ULONG_PTR Ret = 0; 925 926 TRACE("%p %d\n", hWnd, nIndex); 927 928 Wnd = ValidateHwnd(hWnd); 929 if (!Wnd) 930 return 0; 931 932 _SEH2_TRY 933 { 934 Class = DesktopPtrToUser(Wnd->pcls); 935 if (Class != NULL) 936 { 937 Ret = IntGetClassLongA(Wnd, Class, nIndex); 938 } 939 else 940 { 941 WARN("Invalid class for hwnd 0x%p!\n", hWnd); 942 } 943 } 944 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 945 { 946 Ret = 0; 947 } 948 _SEH2_END; 949 950 return Ret; 951 } 952 953 /* 954 * @implemented 955 */ 956 ULONG_PTR 957 WINAPI 958 GetClassLongPtrW(HWND hWnd, 959 INT nIndex) 960 { 961 PWND Wnd; 962 PCLS Class; 963 ULONG_PTR Ret = 0; 964 965 TRACE("%p %d\n", hWnd, nIndex); 966 967 Wnd = ValidateHwnd(hWnd); 968 if (!Wnd) 969 return 0; 970 971 _SEH2_TRY 972 { 973 Class = DesktopPtrToUser(Wnd->pcls); 974 if (Class != NULL) 975 { 976 Ret = IntGetClassLongW(Wnd, Class, nIndex); 977 } 978 else 979 { 980 WARN("Invalid class for hwnd 0x%p!\n", hWnd); 981 } 982 } 983 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 984 { 985 Ret = 0; 986 } 987 _SEH2_END; 988 989 return Ret; 990 } 991 #endif 992 993 994 /* 995 * @implemented 996 */ 997 int WINAPI 998 GetClassNameA( 999 HWND hWnd, 1000 LPSTR lpClassName, 1001 int nMaxCount) 1002 { 1003 WCHAR tmpbuf[MAX_ATOM_LEN + 1]; 1004 int len; 1005 1006 if (nMaxCount <= 0) return 0; 1007 if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0; 1008 RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) ); 1009 lpClassName[len] = 0; 1010 1011 TRACE("%p class/atom: %s/%04x %x\n", hWnd, 1012 IS_ATOM(lpClassName) ? NULL : lpClassName, 1013 IS_ATOM(lpClassName) ? lpClassName : 0, 1014 nMaxCount); 1015 1016 return len; 1017 } 1018 1019 1020 /* 1021 * @implemented 1022 */ 1023 int 1024 WINAPI 1025 GetClassNameW( 1026 HWND hWnd, 1027 LPWSTR lpClassName, 1028 int nMaxCount) 1029 { 1030 UNICODE_STRING ClassName; 1031 int Result; 1032 1033 RtlInitEmptyUnicodeString(&ClassName, 1034 lpClassName, 1035 nMaxCount * sizeof(WCHAR)); 1036 1037 Result = NtUserGetClassName(hWnd, 1038 FALSE, 1039 &ClassName); 1040 1041 TRACE("%p class/atom: %S/%04x %x\n", hWnd, 1042 IS_ATOM(lpClassName) ? NULL : lpClassName, 1043 IS_ATOM(lpClassName) ? lpClassName : 0, 1044 nMaxCount); 1045 1046 return Result; 1047 } 1048 1049 1050 /* 1051 * @implemented 1052 */ 1053 WORD 1054 WINAPI 1055 GetClassWord( 1056 HWND hwnd, 1057 int offset) 1058 { 1059 PWND Wnd; 1060 PCLS class; 1061 WORD retvalue = 0; 1062 1063 if (offset < 0) return GetClassLongA( hwnd, offset ); 1064 1065 Wnd = ValidateHwnd(hwnd); 1066 if (!Wnd) 1067 return 0; 1068 1069 class = DesktopPtrToUser(Wnd->pcls); 1070 if (class == NULL) return 0; 1071 1072 if (offset <= class->cbclsExtra - sizeof(WORD)) 1073 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) ); 1074 else 1075 SetLastError( ERROR_INVALID_INDEX ); 1076 1077 return retvalue; 1078 } 1079 1080 1081 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode ) 1082 { 1083 LONG_PTR retvalue = 0; 1084 WND *wndPtr; 1085 1086 if (offset == GWLP_HWNDPARENT) 1087 { 1088 HWND parent = GetAncestor( hwnd, GA_PARENT ); 1089 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER ); 1090 return (ULONG_PTR)parent; 1091 } 1092 1093 if (!(wndPtr = ValidateHwnd( hwnd ))) 1094 { 1095 SetLastError( ERROR_INVALID_WINDOW_HANDLE ); 1096 return 0; 1097 } 1098 1099 if (offset >= 0 && wndPtr->fnid != FNID_DESKTOP) 1100 { 1101 if (offset > (int)(wndPtr->cbwndExtra - size)) 1102 { 1103 WARN("Invalid offset %d\n", offset ); 1104 SetLastError( ERROR_INVALID_INDEX ); 1105 return 0; 1106 } 1107 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset)); 1108 1109 /* WINE: special case for dialog window procedure */ 1110 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG)) 1111 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode ); 1112 return retvalue; 1113 } 1114 1115 switch(offset) 1116 { 1117 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break; 1118 case GWL_STYLE: retvalue = wndPtr->style; break; 1119 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break; 1120 case GWLP_ID: retvalue = wndPtr->IDMenu; break; 1121 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break; 1122 #if 0 1123 /* -1 is an undocumented case which returns WW* */ 1124 /* source: http://www.geoffchappell.com/studies/windows/win32/user32/structs/wnd/index.htm*/ 1125 case -1: retvalue = (ULONG_PTR)&wndPtr->ww; break; 1126 #else 1127 /* We don't have a WW but WND already contains the same fields in the right order, */ 1128 /* so we can return a pointer to its first field */ 1129 case -1: retvalue = (ULONG_PTR)&wndPtr->state; break; 1130 #endif 1131 case GWLP_WNDPROC: 1132 { 1133 if (!TestWindowProcess(wndPtr)) 1134 { 1135 SetLastError(ERROR_ACCESS_DENIED); 1136 retvalue = 0; 1137 ERR("Outside Access and Denied!\n"); 1138 break; 1139 } 1140 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode); 1141 break; 1142 } 1143 default: 1144 WARN("Unknown offset %d\n", offset ); 1145 SetLastError( ERROR_INVALID_INDEX ); 1146 break; 1147 } 1148 return retvalue; 1149 1150 } 1151 /* 1152 * @implemented 1153 */ 1154 LONG 1155 WINAPI 1156 GetWindowLongA ( HWND hWnd, int nIndex ) 1157 { 1158 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE ); 1159 } 1160 1161 /* 1162 * @implemented 1163 */ 1164 LONG 1165 WINAPI 1166 GetWindowLongW(HWND hWnd, int nIndex) 1167 { 1168 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE ); 1169 } 1170 1171 #ifdef _WIN64 1172 /* 1173 * @implemented 1174 */ 1175 LONG_PTR 1176 WINAPI 1177 GetWindowLongPtrA(HWND hWnd, 1178 INT nIndex) 1179 { 1180 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE ); 1181 } 1182 1183 /* 1184 * @implemented 1185 */ 1186 LONG_PTR 1187 WINAPI 1188 GetWindowLongPtrW(HWND hWnd, 1189 INT nIndex) 1190 { 1191 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE ); 1192 1193 } 1194 #endif // _WIN64 1195 1196 /* 1197 * @implemented 1198 */ 1199 WORD 1200 WINAPI 1201 GetWindowWord(HWND hWnd, int nIndex) 1202 { 1203 switch(nIndex) 1204 { 1205 case GWLP_ID: 1206 case GWLP_HINSTANCE: 1207 case GWLP_HWNDPARENT: 1208 break; 1209 default: 1210 if (nIndex < 0) 1211 { 1212 WARN("Invalid offset %d\n", nIndex ); 1213 SetLastError( ERROR_INVALID_INDEX ); 1214 return 0; 1215 } 1216 break; 1217 } 1218 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE ); 1219 } 1220 1221 /* 1222 * @implemented 1223 */ 1224 UINT 1225 WINAPI 1226 RealGetWindowClassW( 1227 HWND hwnd, 1228 LPWSTR pszType, 1229 UINT cchType) 1230 { 1231 UNICODE_STRING ClassName; 1232 1233 RtlInitEmptyUnicodeString(&ClassName, 1234 pszType, 1235 cchType * sizeof(WCHAR)); 1236 1237 return NtUserGetClassName(hwnd,TRUE,&ClassName); 1238 } 1239 1240 1241 /* 1242 * @implemented 1243 */ 1244 UINT 1245 WINAPI 1246 RealGetWindowClassA( 1247 HWND hwnd, 1248 LPSTR pszType, 1249 UINT cchType) 1250 { 1251 WCHAR tmpbuf[MAX_ATOM_LEN + 1]; 1252 UINT len; 1253 1254 if ((INT)cchType <= 0) return 0; 1255 if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0; 1256 RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) ); 1257 pszType[len] = 0; 1258 return len; 1259 } 1260 1261 ATOM WINAPI 1262 RegisterClassExWOWW(WNDCLASSEXW *lpwcx, 1263 LPDWORD pdwWowData, 1264 WORD fnID, 1265 DWORD dwFlags, 1266 BOOL ChkRegCls) 1267 { 1268 ATOM Atom; 1269 WNDCLASSEXW WndClass; 1270 UNICODE_STRING ClassName; 1271 UNICODE_STRING ClassVersion; 1272 UNICODE_STRING MenuName = {0}; 1273 CLSMENUNAME clsMenuName; 1274 ANSI_STRING AnsiMenuName; 1275 LPCWSTR lpszClsVersion; 1276 1277 if (lpwcx == NULL || lpwcx->cbSize != sizeof(*lpwcx) || 1278 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 || 1279 lpwcx->lpszClassName == NULL) 1280 { 1281 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n"); 1282 SetLastError(ERROR_INVALID_PARAMETER); 1283 return 0; 1284 } 1285 1286 if (ChkRegCls) 1287 { 1288 if (!RegisterDefaultClasses) RegisterSystemControls(); 1289 } 1290 /* 1291 * On real Windows this looks more like: 1292 * if (lpwcx->hInstance == User32Instance && 1293 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400) 1294 * But since I have no idea what the magic field in the 1295 * TEB structure means, I rather decided to omit that. 1296 * -- Filip Navara 1297 1298 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400) 1299 */ 1300 if (lpwcx->hInstance == User32Instance) 1301 { 1302 TRACE("RegisterClassExWOWW User32Instance!\n"); 1303 SetLastError(ERROR_INVALID_PARAMETER); 1304 return 0; 1305 } 1306 /* Yes, this is correct. We should modify the passed structure. */ 1307 if (lpwcx->hInstance == NULL) 1308 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL); 1309 1310 RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx)); 1311 1312 RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0); 1313 if (!IS_INTRESOURCE(WndClass.lpszMenuName)) 1314 { 1315 if (WndClass.lpszMenuName[0]) 1316 { 1317 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName); 1318 RtlUnicodeStringToAnsiString(&AnsiMenuName, &MenuName, TRUE); 1319 } 1320 } 1321 else 1322 { 1323 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName; 1324 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName; 1325 } 1326 1327 if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName)) 1328 { 1329 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName); 1330 } 1331 else 1332 { 1333 ClassName.Length = ClassName.MaximumLength = 0; 1334 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName; 1335 } 1336 1337 ClassVersion = ClassName; 1338 if (fnID == 0) 1339 { 1340 lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE); 1341 if (lpszClsVersion) 1342 { 1343 RtlInitUnicodeString(&ClassVersion, lpszClsVersion); 1344 } 1345 } 1346 1347 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer; 1348 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer; 1349 clsMenuName.pusMenuName = &MenuName; 1350 1351 Atom = NtUserRegisterClassExWOW(&WndClass, 1352 &ClassName, 1353 &ClassVersion, 1354 &clsMenuName, 1355 fnID, 1356 dwFlags, 1357 pdwWowData); 1358 1359 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n", 1360 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1361 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass); 1362 1363 return Atom; 1364 } 1365 1366 /* 1367 * @implemented 1368 */ 1369 ATOM WINAPI 1370 RegisterClassExA(CONST WNDCLASSEXA *lpwcx) 1371 { 1372 ATOM Atom; 1373 WNDCLASSEXW WndClass; 1374 WCHAR mname[MAX_BUFFER_LEN]; 1375 WCHAR cname[MAX_BUFFER_LEN]; 1376 1377 C_ASSERT(sizeof(WndClass) == sizeof(*lpwcx)); 1378 1379 RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx)); 1380 1381 if (WndClass.lpszMenuName && !IS_INTRESOURCE(WndClass.lpszMenuName)) 1382 { 1383 if (WndClass.lpszMenuName[0]) 1384 { 1385 if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) 1386 return 0; 1387 1388 WndClass.lpszMenuName = mname; 1389 } 1390 } 1391 1392 if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName)) 1393 { 1394 if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) 1395 return 0; 1396 1397 WndClass.lpszClassName = cname; 1398 } 1399 1400 Atom = RegisterClassExWOWW(&WndClass, 1401 NULL, 1402 0, 1403 CSF_ANSIPROC, 1404 TRUE); 1405 1406 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n", 1407 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1408 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass); 1409 1410 return Atom; 1411 } 1412 1413 /* 1414 * @implemented 1415 */ 1416 ATOM WINAPI 1417 RegisterClassExW(CONST WNDCLASSEXW *lpwcx) 1418 { 1419 ATOM Atom; 1420 1421 Atom = RegisterClassExWOWW((WNDCLASSEXW *)lpwcx, NULL, 0, 0, TRUE); 1422 1423 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n", 1424 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1425 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra); 1426 1427 return Atom; 1428 } 1429 1430 /* 1431 * @implemented 1432 */ 1433 ATOM WINAPI 1434 RegisterClassA(CONST WNDCLASSA *lpWndClass) 1435 { 1436 WNDCLASSEXA Class; 1437 1438 if (lpWndClass == NULL) 1439 return 0; 1440 1441 /* These MUST be copied manually, since on 64 bit architectures the 1442 alignment of the members is different between the 2 structs! */ 1443 Class.style = lpWndClass->style; 1444 Class.lpfnWndProc = lpWndClass->lpfnWndProc; 1445 Class.cbClsExtra = lpWndClass->cbClsExtra; 1446 Class.cbWndExtra = lpWndClass->cbWndExtra; 1447 Class.hInstance = lpWndClass->hInstance; 1448 Class.hIcon = lpWndClass->hIcon; 1449 Class.hCursor = lpWndClass->hCursor; 1450 Class.hbrBackground = lpWndClass->hbrBackground; 1451 Class.lpszMenuName = lpWndClass->lpszMenuName; 1452 Class.lpszClassName = lpWndClass->lpszClassName; 1453 1454 Class.cbSize = sizeof(Class); 1455 Class.hIconSm = NULL; 1456 1457 return RegisterClassExA(&Class); 1458 } 1459 1460 /* 1461 * @implemented 1462 */ 1463 ATOM WINAPI 1464 RegisterClassW(CONST WNDCLASSW *lpWndClass) 1465 { 1466 WNDCLASSEXW Class; 1467 1468 if (lpWndClass == NULL) 1469 return 0; 1470 1471 /* These MUST be copied manually, since on 64 bit architectures the 1472 alignment of the members is different between the 2 structs! */ 1473 Class.style = lpWndClass->style; 1474 Class.lpfnWndProc = lpWndClass->lpfnWndProc; 1475 Class.cbClsExtra = lpWndClass->cbClsExtra; 1476 Class.cbWndExtra = lpWndClass->cbWndExtra; 1477 Class.hInstance = lpWndClass->hInstance; 1478 Class.hIcon = lpWndClass->hIcon; 1479 Class.hCursor = lpWndClass->hCursor; 1480 Class.hbrBackground = lpWndClass->hbrBackground; 1481 Class.lpszMenuName = lpWndClass->lpszMenuName; 1482 Class.lpszClassName = lpWndClass->lpszClassName; 1483 1484 Class.cbSize = sizeof(Class); 1485 Class.hIconSm = NULL; 1486 1487 return RegisterClassExW(&Class); 1488 } 1489 1490 /* 1491 * @implemented 1492 */ 1493 DWORD 1494 WINAPI 1495 SetClassLongA(HWND hWnd, 1496 int nIndex, 1497 LONG dwNewLong) 1498 { 1499 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong; 1500 UNICODE_STRING Value = {0}; 1501 BOOL Allocated = FALSE; 1502 DWORD Ret; 1503 1504 /* FIXME - portability!!!! */ 1505 1506 if (nIndex == GCL_MENUNAME && lpStr != NULL) 1507 { 1508 if (!IS_INTRESOURCE(lpStr)) 1509 { 1510 if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr)) 1511 { 1512 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1513 return 0; 1514 } 1515 1516 Allocated = TRUE; 1517 } 1518 else 1519 { 1520 Value.Buffer = (PWSTR)lpStr; 1521 } 1522 1523 dwNewLong = (LONG_PTR)&Value; 1524 } 1525 else if (nIndex == GCW_ATOM && lpStr != NULL) 1526 { 1527 if (!IS_ATOM(lpStr)) 1528 { 1529 if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr)) 1530 { 1531 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1532 return 0; 1533 } 1534 1535 Allocated = TRUE; 1536 } 1537 else 1538 { 1539 Value.Buffer = (PWSTR)lpStr; 1540 } 1541 1542 dwNewLong = (LONG_PTR)&Value; 1543 } 1544 1545 Ret = (DWORD)NtUserSetClassLong(hWnd, 1546 nIndex, 1547 dwNewLong, 1548 TRUE); 1549 1550 if (Allocated) 1551 { 1552 RtlFreeUnicodeString(&Value); 1553 } 1554 1555 return Ret; 1556 } 1557 1558 1559 /* 1560 * @implemented 1561 */ 1562 DWORD 1563 WINAPI 1564 SetClassLongW(HWND hWnd, 1565 int nIndex, 1566 LONG dwNewLong) 1567 { 1568 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong; 1569 UNICODE_STRING Value = {0}; 1570 1571 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong); 1572 1573 /* FIXME - portability!!!! */ 1574 1575 if (nIndex == GCL_MENUNAME && lpStr != NULL) 1576 { 1577 if (!IS_INTRESOURCE(lpStr)) 1578 RtlInitUnicodeString(&Value, lpStr); 1579 else 1580 Value.Buffer = lpStr; 1581 1582 dwNewLong = (LONG_PTR)&Value; 1583 } 1584 else if (nIndex == GCW_ATOM && lpStr != NULL) 1585 { 1586 if (!IS_ATOM(lpStr)) 1587 RtlInitUnicodeString(&Value, lpStr); 1588 else 1589 Value.Buffer = lpStr; 1590 1591 dwNewLong = (LONG_PTR)&Value; 1592 } 1593 1594 return (DWORD)NtUserSetClassLong(hWnd, 1595 nIndex, 1596 dwNewLong, 1597 FALSE); 1598 } 1599 1600 #ifdef _WIN64 1601 /* 1602 * @unimplemented 1603 */ 1604 ULONG_PTR 1605 WINAPI 1606 SetClassLongPtrA(HWND hWnd, 1607 INT nIndex, 1608 LONG_PTR dwNewLong) 1609 { 1610 UNIMPLEMENTED; 1611 return 0; 1612 } 1613 1614 /* 1615 * @unimplemented 1616 */ 1617 ULONG_PTR 1618 WINAPI 1619 SetClassLongPtrW(HWND hWnd, 1620 INT nIndex, 1621 LONG_PTR dwNewLong) 1622 { 1623 UNIMPLEMENTED; 1624 return 0; 1625 } 1626 #endif // _WIN64 1627 1628 /* 1629 * @implemented 1630 */ 1631 WORD 1632 WINAPI 1633 SetClassWord( 1634 HWND hWnd, 1635 int nIndex, 1636 WORD wNewWord) 1637 /* 1638 * NOTE: Obsoleted in 32-bit windows 1639 */ 1640 { 1641 if ((nIndex < 0) && (nIndex != GCW_ATOM)) 1642 return 0; 1643 1644 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord ); 1645 } 1646 1647 /* 1648 * @implemented 1649 */ 1650 WORD 1651 WINAPI 1652 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord ) 1653 { 1654 switch(nIndex) 1655 { 1656 case GWLP_ID: 1657 case GWLP_HINSTANCE: 1658 case GWLP_HWNDPARENT: 1659 break; 1660 default: 1661 if (nIndex < 0) 1662 { 1663 WARN("Invalid offset %d\n", nIndex ); 1664 SetLastError( ERROR_INVALID_INDEX ); 1665 return 0; 1666 } 1667 break; 1668 } 1669 /* DO NOT USE NtUserSetWindowLong(Ptr)! */ 1670 return NtUserSetWindowWord(hWnd, nIndex, wNewWord); 1671 } 1672 1673 /* 1674 * @implemented 1675 */ 1676 LONG 1677 WINAPI 1678 DECLSPEC_HOTPATCH 1679 SetWindowLongA( 1680 HWND hWnd, 1681 int nIndex, 1682 LONG dwNewLong) 1683 { 1684 /* DO NOT USE NtUserSetWindowLongPtr! */ 1685 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE); 1686 } 1687 1688 /* 1689 * @implemented 1690 */ 1691 LONG 1692 WINAPI 1693 SetWindowLongW( 1694 HWND hWnd, 1695 int nIndex, 1696 LONG dwNewLong) 1697 { 1698 /* DO NOT USE NtUserSetWindowLongPtr! */ 1699 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE); 1700 } 1701 1702 #ifdef _WIN64 1703 /* 1704 * @implemented 1705 */ 1706 LONG_PTR 1707 WINAPI 1708 SetWindowLongPtrA(HWND hWnd, 1709 INT nIndex, 1710 LONG_PTR dwNewLong) 1711 { 1712 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE); 1713 } 1714 1715 /* 1716 * @implemented 1717 */ 1718 LONG_PTR 1719 WINAPI 1720 SetWindowLongPtrW(HWND hWnd, 1721 INT nIndex, 1722 LONG_PTR dwNewLong) 1723 { 1724 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE); 1725 } 1726 #endif 1727 1728 /* 1729 * @implemented 1730 */ 1731 BOOL 1732 WINAPI 1733 UnregisterClassA( 1734 LPCSTR lpClassName, 1735 HINSTANCE hInstance) 1736 { 1737 UNICODE_STRING ClassName = {0}; 1738 BOOL Ret; 1739 LPCWSTR lpszClsVersion; 1740 BOOL ConvertedString = FALSE; 1741 1742 TRACE("class/atom: %s/%04x %p\n", 1743 IS_ATOM(lpClassName) ? NULL : lpClassName, 1744 IS_ATOM(lpClassName) ? lpClassName : 0, 1745 hInstance); 1746 1747 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE); 1748 if (lpszClsVersion) 1749 { 1750 RtlInitUnicodeString(&ClassName, lpszClsVersion); 1751 } 1752 else if (!IS_ATOM(lpClassName)) 1753 { 1754 ConvertedString = TRUE; 1755 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName)) 1756 { 1757 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1758 return 0; 1759 } 1760 } 1761 else 1762 { 1763 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); 1764 } 1765 1766 Ret = NtUserUnregisterClass(&ClassName, hInstance, 0); 1767 1768 if (ConvertedString) 1769 RtlFreeUnicodeString(&ClassName); 1770 1771 return Ret; 1772 } 1773 1774 /* 1775 * @implemented 1776 */ 1777 BOOL 1778 WINAPI 1779 UnregisterClassW( 1780 LPCWSTR lpClassName, 1781 HINSTANCE hInstance) 1782 { 1783 UNICODE_STRING ClassName = {0}; 1784 LPCWSTR lpszClsVersion; 1785 1786 TRACE("class/atom: %S/%04x %p\n", 1787 IS_ATOM(lpClassName) ? NULL : lpClassName, 1788 IS_ATOM(lpClassName) ? lpClassName : 0, 1789 hInstance); 1790 1791 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE); 1792 if (lpszClsVersion) 1793 { 1794 RtlInitUnicodeString(&ClassName, lpszClsVersion); 1795 } 1796 else if (!IS_ATOM(lpClassName)) 1797 { 1798 RtlInitUnicodeString(&ClassName, lpClassName); 1799 } 1800 else 1801 { 1802 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); 1803 } 1804 1805 return NtUserUnregisterClass(&ClassName, hInstance, 0); 1806 } 1807 1808 /* EOF */ 1809