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 = 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 } 1138 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode); 1139 break; 1140 } 1141 default: 1142 WARN("Unknown offset %d\n", offset ); 1143 SetLastError( ERROR_INVALID_INDEX ); 1144 break; 1145 } 1146 return retvalue; 1147 1148 } 1149 /* 1150 * @implemented 1151 */ 1152 LONG 1153 WINAPI 1154 GetWindowLongA ( HWND hWnd, int nIndex ) 1155 { 1156 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE ); 1157 } 1158 1159 /* 1160 * @implemented 1161 */ 1162 LONG 1163 WINAPI 1164 GetWindowLongW(HWND hWnd, int nIndex) 1165 { 1166 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE ); 1167 } 1168 1169 #ifdef _WIN64 1170 /* 1171 * @implemented 1172 */ 1173 LONG_PTR 1174 WINAPI 1175 GetWindowLongPtrA(HWND hWnd, 1176 INT nIndex) 1177 { 1178 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE ); 1179 } 1180 1181 /* 1182 * @implemented 1183 */ 1184 LONG_PTR 1185 WINAPI 1186 GetWindowLongPtrW(HWND hWnd, 1187 INT nIndex) 1188 { 1189 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE ); 1190 1191 } 1192 #endif // _WIN64 1193 1194 /* 1195 * @implemented 1196 */ 1197 WORD 1198 WINAPI 1199 GetWindowWord(HWND hWnd, int nIndex) 1200 { 1201 switch(nIndex) 1202 { 1203 case GWLP_ID: 1204 case GWLP_HINSTANCE: 1205 case GWLP_HWNDPARENT: 1206 break; 1207 default: 1208 if (nIndex < 0) 1209 { 1210 WARN("Invalid offset %d\n", nIndex ); 1211 SetLastError( ERROR_INVALID_INDEX ); 1212 return 0; 1213 } 1214 break; 1215 } 1216 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE ); 1217 } 1218 1219 /* 1220 * @implemented 1221 */ 1222 UINT 1223 WINAPI 1224 RealGetWindowClassW( 1225 HWND hwnd, 1226 LPWSTR pszType, 1227 UINT cchType) 1228 { 1229 UNICODE_STRING ClassName; 1230 1231 RtlInitEmptyUnicodeString(&ClassName, 1232 pszType, 1233 cchType * sizeof(WCHAR)); 1234 1235 return NtUserGetClassName(hwnd,TRUE,&ClassName); 1236 } 1237 1238 1239 /* 1240 * @implemented 1241 */ 1242 UINT 1243 WINAPI 1244 RealGetWindowClassA( 1245 HWND hwnd, 1246 LPSTR pszType, 1247 UINT cchType) 1248 { 1249 WCHAR tmpbuf[MAX_ATOM_LEN + 1]; 1250 UINT len; 1251 1252 if ((INT)cchType <= 0) return 0; 1253 if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0; 1254 RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) ); 1255 pszType[len] = 0; 1256 return len; 1257 } 1258 1259 /* 1260 * Create a small icon based on a standard icon 1261 */ 1262 #if 0 // Keep vintage code from revision 18764 by GvG! 1263 static HICON 1264 CreateSmallIcon(HICON StdIcon) 1265 { 1266 HICON SmallIcon = NULL; 1267 ICONINFO StdInfo; 1268 int SmallIconWidth; 1269 int SmallIconHeight; 1270 BITMAP StdBitmapInfo; 1271 HDC hSourceDc = NULL; 1272 HDC hDestDc = NULL; 1273 ICONINFO SmallInfo; 1274 HBITMAP OldSourceBitmap = NULL; 1275 HBITMAP OldDestBitmap = NULL; 1276 1277 SmallInfo.hbmColor = NULL; 1278 SmallInfo.hbmMask = NULL; 1279 1280 /* We need something to work with... */ 1281 if (NULL == StdIcon) 1282 { 1283 goto cleanup; 1284 } 1285 1286 SmallIconWidth = GetSystemMetrics(SM_CXSMICON); 1287 SmallIconHeight = GetSystemMetrics(SM_CYSMICON); 1288 if (! GetIconInfo(StdIcon, &StdInfo)) 1289 { 1290 ERR("Failed to get icon info for icon 0x%x\n", StdIcon); 1291 goto cleanup; 1292 } 1293 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo)) 1294 { 1295 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n", 1296 StdIcon, StdInfo.hbmColor); 1297 goto cleanup; 1298 } 1299 if (StdBitmapInfo.bmWidth == SmallIconWidth && 1300 StdBitmapInfo.bmHeight == SmallIconHeight) 1301 { 1302 /* Icon already has the correct dimensions */ 1303 return StdIcon; 1304 } 1305 1306 hSourceDc = CreateCompatibleDC(NULL); 1307 if (NULL == hSourceDc) 1308 { 1309 ERR("Failed to create source DC\n"); 1310 goto cleanup; 1311 } 1312 hDestDc = CreateCompatibleDC(NULL); 1313 if (NULL == hDestDc) 1314 { 1315 ERR("Failed to create dest DC\n"); 1316 goto cleanup; 1317 } 1318 1319 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor); 1320 if (NULL == OldSourceBitmap) 1321 { 1322 ERR("Failed to select source color bitmap\n"); 1323 goto cleanup; 1324 } 1325 SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, 1326 SmallIconHeight); 1327 if (NULL == SmallInfo.hbmColor) 1328 { 1329 ERR("Failed to create color bitmap\n"); 1330 goto cleanup; 1331 } 1332 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor); 1333 if (NULL == OldDestBitmap) 1334 { 1335 ERR("Failed to select dest color bitmap\n"); 1336 goto cleanup; 1337 } 1338 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight, 1339 hSourceDc, 0, 0, StdBitmapInfo.bmWidth, 1340 StdBitmapInfo.bmHeight, SRCCOPY)) 1341 { 1342 ERR("Failed to stretch color bitmap\n"); 1343 goto cleanup; 1344 } 1345 1346 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask)) 1347 { 1348 ERR("Failed to select source mask bitmap\n"); 1349 goto cleanup; 1350 } 1351 SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight); 1352 if (NULL == SmallInfo.hbmMask) 1353 { 1354 ERR("Failed to create mask bitmap\n"); 1355 goto cleanup; 1356 } 1357 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask)) 1358 { 1359 ERR("Failed to select dest mask bitmap\n"); 1360 goto cleanup; 1361 } 1362 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight, 1363 hSourceDc, 0, 0, StdBitmapInfo.bmWidth, 1364 StdBitmapInfo.bmHeight, SRCCOPY)) 1365 { 1366 ERR("Failed to stretch mask bitmap\n"); 1367 goto cleanup; 1368 } 1369 1370 SmallInfo.fIcon = TRUE; 1371 SmallInfo.xHotspot = SmallIconWidth / 2; 1372 SmallInfo.yHotspot = SmallIconHeight / 2; 1373 SmallIcon = CreateIconIndirect(&SmallInfo); 1374 if (NULL == SmallIcon) 1375 { 1376 ERR("Failed to create icon\n"); 1377 goto cleanup; 1378 } 1379 1380 cleanup: 1381 if (NULL != SmallInfo.hbmMask) 1382 { 1383 DeleteObject(SmallInfo.hbmMask); 1384 } 1385 if (NULL != OldDestBitmap) 1386 { 1387 SelectObject(hDestDc, OldDestBitmap); 1388 } 1389 if (NULL != SmallInfo.hbmColor) 1390 { 1391 DeleteObject(SmallInfo.hbmColor); 1392 } 1393 if (NULL != hDestDc) 1394 { 1395 DeleteDC(hDestDc); 1396 } 1397 if (NULL != OldSourceBitmap) 1398 { 1399 SelectObject(hSourceDc, OldSourceBitmap); 1400 } 1401 if (NULL != hSourceDc) 1402 { 1403 DeleteDC(hSourceDc); 1404 } 1405 1406 return SmallIcon; 1407 } 1408 #endif 1409 1410 ATOM WINAPI 1411 RegisterClassExWOWW(WNDCLASSEXW *lpwcx, 1412 LPDWORD pdwWowData, 1413 WORD fnID, 1414 DWORD dwFlags, 1415 BOOL ChkRegCls) 1416 { 1417 ATOM Atom; 1418 WNDCLASSEXW WndClass; 1419 UNICODE_STRING ClassName; 1420 UNICODE_STRING ClassVersion; 1421 UNICODE_STRING MenuName = {0}; 1422 CLSMENUNAME clsMenuName; 1423 ANSI_STRING AnsiMenuName; 1424 LPCWSTR lpszClsVersion; 1425 1426 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) || 1427 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 || 1428 lpwcx->lpszClassName == NULL) 1429 { 1430 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n"); 1431 SetLastError(ERROR_INVALID_PARAMETER); 1432 return 0; 1433 } 1434 1435 if (ChkRegCls) 1436 { 1437 if (!RegisterDefaultClasses) RegisterSystemControls(); 1438 } 1439 /* 1440 * On real Windows this looks more like: 1441 * if (lpwcx->hInstance == User32Instance && 1442 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400) 1443 * But since I have no idea what the magic field in the 1444 * TEB structure means, I rather decided to omit that. 1445 * -- Filip Navara 1446 1447 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400) 1448 */ 1449 if (lpwcx->hInstance == User32Instance) 1450 { 1451 TRACE("RegisterClassExWOWW User32Instance!\n"); 1452 SetLastError(ERROR_INVALID_PARAMETER); 1453 return 0; 1454 } 1455 /* Yes, this is correct. We should modify the passed structure. */ 1456 if (lpwcx->hInstance == NULL) 1457 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL); 1458 1459 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW)); 1460 /* 1461 if (NULL == WndClass.hIconSm) 1462 { 1463 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon); 1464 } 1465 */ 1466 RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0); 1467 if (WndClass.lpszMenuName != NULL) 1468 { 1469 if (!IS_INTRESOURCE(WndClass.lpszMenuName)) 1470 { 1471 if (WndClass.lpszMenuName[0]) 1472 { 1473 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName); 1474 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE); 1475 } 1476 } 1477 else 1478 { 1479 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName; 1480 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName; 1481 } 1482 } 1483 1484 if (IS_ATOM(WndClass.lpszClassName)) 1485 { 1486 ClassName.Length = 1487 ClassName.MaximumLength = 0; 1488 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName; 1489 } 1490 else 1491 { 1492 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName); 1493 } 1494 1495 ClassVersion = ClassName; 1496 if (fnID == 0) 1497 { 1498 lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE); 1499 if (lpszClsVersion) 1500 { 1501 RtlInitUnicodeString(&ClassVersion, lpszClsVersion); 1502 } 1503 } 1504 1505 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer; 1506 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer; 1507 clsMenuName.pusMenuName = &MenuName; 1508 1509 Atom = NtUserRegisterClassExWOW( &WndClass, 1510 &ClassName, 1511 &ClassVersion, 1512 &clsMenuName, 1513 fnID, 1514 dwFlags, 1515 pdwWowData); 1516 1517 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n", 1518 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1519 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass); 1520 1521 return Atom; 1522 } 1523 1524 /* 1525 * @implemented 1526 */ 1527 ATOM WINAPI 1528 RegisterClassExA(CONST WNDCLASSEXA *lpwcx) 1529 { 1530 RTL_ATOM Atom; 1531 WNDCLASSEXW WndClass; 1532 WCHAR mname[MAX_BUFFER_LEN]; 1533 WCHAR cname[MAX_BUFFER_LEN]; 1534 1535 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA)); 1536 1537 if (WndClass.lpszMenuName != NULL) 1538 { 1539 if (!IS_INTRESOURCE(WndClass.lpszMenuName)) 1540 { 1541 if (WndClass.lpszMenuName[0]) 1542 { 1543 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0; 1544 1545 WndClass.lpszMenuName = mname; 1546 } 1547 } 1548 } 1549 1550 if (!IS_ATOM(WndClass.lpszClassName)) 1551 { 1552 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0; 1553 1554 WndClass.lpszClassName = cname; 1555 } 1556 1557 Atom = RegisterClassExWOWW( &WndClass, 1558 0, 1559 0, 1560 CSF_ANSIPROC, 1561 TRUE); 1562 1563 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n", 1564 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1565 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass); 1566 1567 return (ATOM)Atom; 1568 } 1569 1570 /* 1571 * @implemented 1572 */ 1573 ATOM WINAPI 1574 RegisterClassExW(CONST WNDCLASSEXW *lpwcx) 1575 { 1576 ATOM Atom; 1577 1578 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE); 1579 1580 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n", 1581 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground, 1582 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra); 1583 1584 return Atom; 1585 } 1586 1587 /* 1588 * @implemented 1589 */ 1590 ATOM WINAPI 1591 RegisterClassA(CONST WNDCLASSA *lpWndClass) 1592 { 1593 WNDCLASSEXA Class; 1594 1595 if (lpWndClass == NULL) 1596 return 0; 1597 1598 /* These MUST be copied manually, since on 64 bit architectures the 1599 alignment of the members is different between the 2 structs! */ 1600 Class.style = lpWndClass->style; 1601 Class.lpfnWndProc = lpWndClass->lpfnWndProc; 1602 Class.cbClsExtra = lpWndClass->cbClsExtra; 1603 Class.cbWndExtra = lpWndClass->cbWndExtra; 1604 Class.hInstance = lpWndClass->hInstance; 1605 Class.hIcon = lpWndClass->hIcon; 1606 Class.hCursor = lpWndClass->hCursor; 1607 Class.hbrBackground = lpWndClass->hbrBackground; 1608 Class.lpszMenuName = lpWndClass->lpszMenuName; 1609 Class.lpszClassName = lpWndClass->lpszClassName; 1610 1611 Class.cbSize = sizeof(WNDCLASSEXA); 1612 Class.hIconSm = NULL; 1613 1614 return RegisterClassExA(&Class); 1615 } 1616 1617 /* 1618 * @implemented 1619 */ 1620 ATOM WINAPI 1621 RegisterClassW(CONST WNDCLASSW *lpWndClass) 1622 { 1623 WNDCLASSEXW Class; 1624 1625 if (lpWndClass == NULL) 1626 return 0; 1627 1628 /* These MUST be copied manually, since on 64 bit architectures the 1629 alignment of the members is different between the 2 structs! */ 1630 Class.style = lpWndClass->style; 1631 Class.lpfnWndProc = lpWndClass->lpfnWndProc; 1632 Class.cbClsExtra = lpWndClass->cbClsExtra; 1633 Class.cbWndExtra = lpWndClass->cbWndExtra; 1634 Class.hInstance = lpWndClass->hInstance; 1635 Class.hIcon = lpWndClass->hIcon; 1636 Class.hCursor = lpWndClass->hCursor; 1637 Class.hbrBackground = lpWndClass->hbrBackground; 1638 Class.lpszMenuName = lpWndClass->lpszMenuName; 1639 Class.lpszClassName = lpWndClass->lpszClassName; 1640 1641 Class.cbSize = sizeof(WNDCLASSEXW); 1642 Class.hIconSm = NULL; 1643 1644 return RegisterClassExW(&Class); 1645 } 1646 1647 /* 1648 * @implemented 1649 */ 1650 DWORD 1651 WINAPI 1652 SetClassLongA (HWND hWnd, 1653 int nIndex, 1654 LONG dwNewLong) 1655 { 1656 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong; 1657 UNICODE_STRING Value = {0}; 1658 BOOL Allocated = FALSE; 1659 DWORD Ret; 1660 1661 /* FIXME - portability!!!! */ 1662 1663 if (nIndex == GCL_MENUNAME && lpStr != NULL) 1664 { 1665 if (!IS_INTRESOURCE(lpStr)) 1666 { 1667 if (!RtlCreateUnicodeStringFromAsciiz(&Value, 1668 lpStr)) 1669 { 1670 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1671 return 0; 1672 } 1673 1674 Allocated = TRUE; 1675 } 1676 else 1677 Value.Buffer = (PWSTR)lpStr; 1678 1679 dwNewLong = (LONG_PTR)&Value; 1680 } 1681 else if (nIndex == GCW_ATOM && lpStr != NULL) 1682 { 1683 if (!IS_ATOM(lpStr)) 1684 { 1685 if (!RtlCreateUnicodeStringFromAsciiz(&Value, 1686 lpStr)) 1687 { 1688 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1689 return 0; 1690 } 1691 1692 Allocated = TRUE; 1693 } 1694 else 1695 Value.Buffer = (PWSTR)lpStr; 1696 1697 dwNewLong = (LONG_PTR)&Value; 1698 } 1699 1700 Ret = (DWORD)NtUserSetClassLong(hWnd, 1701 nIndex, 1702 dwNewLong, 1703 TRUE); 1704 1705 if (Allocated) 1706 { 1707 RtlFreeUnicodeString(&Value); 1708 } 1709 1710 return Ret; 1711 } 1712 1713 1714 /* 1715 * @implemented 1716 */ 1717 DWORD 1718 WINAPI 1719 SetClassLongW(HWND hWnd, 1720 int nIndex, 1721 LONG dwNewLong) 1722 { 1723 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong; 1724 UNICODE_STRING Value = {0}; 1725 1726 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong); 1727 1728 /* FIXME - portability!!!! */ 1729 1730 if (nIndex == GCL_MENUNAME && lpStr != NULL) 1731 { 1732 if (!IS_INTRESOURCE(lpStr)) 1733 { 1734 RtlInitUnicodeString(&Value, 1735 lpStr); 1736 } 1737 else 1738 Value.Buffer = lpStr; 1739 1740 dwNewLong = (LONG_PTR)&Value; 1741 } 1742 else if (nIndex == GCW_ATOM && lpStr != NULL) 1743 { 1744 if (!IS_ATOM(lpStr)) 1745 { 1746 RtlInitUnicodeString(&Value, 1747 lpStr); 1748 } 1749 else 1750 Value.Buffer = lpStr; 1751 1752 dwNewLong = (LONG_PTR)&Value; 1753 } 1754 1755 return (DWORD)NtUserSetClassLong(hWnd, 1756 nIndex, 1757 dwNewLong, 1758 FALSE); 1759 } 1760 1761 #ifdef _WIN64 1762 /* 1763 * @unimplemented 1764 */ 1765 ULONG_PTR 1766 WINAPI 1767 SetClassLongPtrA(HWND hWnd, 1768 INT nIndex, 1769 LONG_PTR dwNewLong) 1770 { 1771 UNIMPLEMENTED; 1772 return 0; 1773 } 1774 1775 /* 1776 * @unimplemented 1777 */ 1778 ULONG_PTR 1779 WINAPI 1780 SetClassLongPtrW(HWND hWnd, 1781 INT nIndex, 1782 LONG_PTR dwNewLong) 1783 { 1784 UNIMPLEMENTED; 1785 return 0; 1786 } 1787 #endif // _WIN64 1788 1789 /* 1790 * @implemented 1791 */ 1792 WORD 1793 WINAPI 1794 SetClassWord( 1795 HWND hWnd, 1796 int nIndex, 1797 WORD wNewWord) 1798 /* 1799 * NOTE: Obsoleted in 32-bit windows 1800 */ 1801 { 1802 if ((nIndex < 0) && (nIndex != GCW_ATOM)) 1803 return 0; 1804 1805 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord ); 1806 } 1807 1808 /* 1809 * @implemented 1810 */ 1811 WORD 1812 WINAPI 1813 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord ) 1814 { 1815 switch(nIndex) 1816 { 1817 case GWLP_ID: 1818 case GWLP_HINSTANCE: 1819 case GWLP_HWNDPARENT: 1820 break; 1821 default: 1822 if (nIndex < 0) 1823 { 1824 WARN("Invalid offset %d\n", nIndex ); 1825 SetLastError( ERROR_INVALID_INDEX ); 1826 return 0; 1827 } 1828 break; 1829 } 1830 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE ); 1831 } 1832 1833 /* 1834 * @implemented 1835 */ 1836 LONG 1837 WINAPI 1838 DECLSPEC_HOTPATCH 1839 SetWindowLongA( 1840 HWND hWnd, 1841 int nIndex, 1842 LONG dwNewLong) 1843 { 1844 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE); 1845 } 1846 1847 /* 1848 * @implemented 1849 */ 1850 LONG 1851 WINAPI 1852 SetWindowLongW( 1853 HWND hWnd, 1854 int nIndex, 1855 LONG dwNewLong) 1856 { 1857 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE); 1858 } 1859 1860 #ifdef _WIN64 1861 /* 1862 * @implemented 1863 */ 1864 LONG_PTR 1865 WINAPI 1866 SetWindowLongPtrA(HWND hWnd, 1867 INT nIndex, 1868 LONG_PTR dwNewLong) 1869 { 1870 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE); 1871 } 1872 1873 /* 1874 * @implemented 1875 */ 1876 LONG_PTR 1877 WINAPI 1878 SetWindowLongPtrW(HWND hWnd, 1879 INT nIndex, 1880 LONG_PTR dwNewLong) 1881 { 1882 return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE); 1883 } 1884 #endif 1885 1886 /* 1887 * @implemented 1888 */ 1889 BOOL 1890 WINAPI 1891 UnregisterClassA( 1892 LPCSTR lpClassName, 1893 HINSTANCE hInstance) 1894 { 1895 UNICODE_STRING ClassName = {0}; 1896 BOOL Ret; 1897 LPCWSTR lpszClsVersion; 1898 BOOL ConvertedString = FALSE; 1899 1900 TRACE("class/atom: %s/%04x %p\n", 1901 IS_ATOM(lpClassName) ? NULL : lpClassName, 1902 IS_ATOM(lpClassName) ? lpClassName : 0, 1903 hInstance); 1904 1905 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE); 1906 if (lpszClsVersion) 1907 { 1908 RtlInitUnicodeString(&ClassName, lpszClsVersion); 1909 } 1910 else if (!IS_ATOM(lpClassName)) 1911 { 1912 ConvertedString = TRUE; 1913 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName)) 1914 { 1915 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1916 return 0; 1917 } 1918 } 1919 else 1920 { 1921 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); 1922 } 1923 1924 Ret = NtUserUnregisterClass(&ClassName, hInstance, 0); 1925 1926 if (ConvertedString) 1927 RtlFreeUnicodeString(&ClassName); 1928 1929 return Ret; 1930 } 1931 1932 1933 /* 1934 * @implemented 1935 */ 1936 BOOL 1937 WINAPI 1938 UnregisterClassW( 1939 LPCWSTR lpClassName, 1940 HINSTANCE hInstance) 1941 { 1942 UNICODE_STRING ClassName = {0}; 1943 LPCWSTR lpszClsVersion; 1944 1945 TRACE("class/atom: %S/%04x %p\n", 1946 IS_ATOM(lpClassName) ? NULL : lpClassName, 1947 IS_ATOM(lpClassName) ? lpClassName : 0, 1948 hInstance); 1949 1950 lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE); 1951 if (lpszClsVersion) 1952 { 1953 RtlInitUnicodeString(&ClassName, lpszClsVersion); 1954 } 1955 else if (!IS_ATOM(lpClassName)) 1956 { 1957 RtlInitUnicodeString(&ClassName, lpClassName); 1958 } 1959 else 1960 { 1961 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName); 1962 } 1963 1964 return NtUserUnregisterClass(&ClassName, hInstance, 0); 1965 } 1966 1967 /* EOF */ 1968