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