1 /* Unit test suite for window classes. 2 * 3 * Copyright 2002 Mike McCormack 4 * Copyright 2003 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "precomp.h" 22 23 #include <commctrl.h> 24 25 #define NUMCLASSWORDS 4 26 27 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16)) 28 29 static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 30 { 31 if (msg == WM_NCCREATE) return 1; 32 return DefWindowProcW (hWnd, msg, wParam, lParam); 33 } 34 35 static LRESULT WINAPI ClassTest_WndProc2 (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 36 { 37 if (msg == WM_NCCREATE) return 1; 38 return DefWindowProcA (hWnd, msg, wParam, lParam); 39 } 40 41 /*********************************************************************** 42 */ 43 static void ClassTest(HINSTANCE hInstance, BOOL global) 44 { 45 WNDCLASSW cls, wc; 46 static const WCHAR className[] = {'T','e','s','t','C','l','a','s','s',0}; 47 static const WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0}; 48 ATOM test_atom; 49 HWND hTestWnd; 50 LONG i; 51 WCHAR str[20]; 52 ATOM classatom; 53 54 cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0); 55 cls.lpfnWndProc = ClassTest_WndProc; 56 cls.cbClsExtra = NUMCLASSWORDS*sizeof(DWORD); 57 cls.cbWndExtra = 12; 58 cls.hInstance = hInstance; 59 cls.hIcon = LoadIconW (0, (LPWSTR)IDI_APPLICATION); 60 cls.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 61 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 62 cls.lpszMenuName = 0; 63 cls.lpszClassName = className; 64 65 classatom=RegisterClassW(&cls); 66 if (!classatom && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) 67 return; 68 ok(classatom, "failed to register class\n"); 69 70 ok(!RegisterClassW (&cls), 71 "RegisterClass of the same class should fail for the second time\n"); 72 73 /* Setup windows */ 74 hTestWnd = CreateWindowW (className, winName, 75 WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL, 76 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 77 0, hInstance, 0); 78 79 ok(hTestWnd!=0, "Failed to create window\n"); 80 81 /* test initial values of valid classwords */ 82 for(i=0; i<NUMCLASSWORDS; i++) 83 { 84 SetLastError(0); 85 ok(!GetClassLongW(hTestWnd,i*sizeof (DWORD)), 86 "GetClassLongW initial value nonzero!\n"); 87 ok(!GetLastError(), 88 "GetClassLongW failed!\n"); 89 } 90 91 if (0) 92 { 93 /* 94 * GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD)) 95 * does not fail on Win 98, though MSDN says it should 96 */ 97 SetLastError(0); 98 GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD)); 99 ok(GetLastError(), 100 "GetClassLongW() with invalid offset did not fail\n"); 101 } 102 103 /* set values of valid class words */ 104 for(i=0; i<NUMCLASSWORDS; i++) 105 { 106 SetLastError(0); 107 ok(!SetClassLongW(hTestWnd,i*sizeof(DWORD),i+1), 108 "GetClassLongW(%d) initial value nonzero!\n",i); 109 ok(!GetLastError(), 110 "SetClassLongW(%d) failed!\n",i); 111 } 112 113 /* test values of valid classwords that we set */ 114 for(i=0; i<NUMCLASSWORDS; i++) 115 { 116 SetLastError(0); 117 ok( (i+1) == GetClassLongW(hTestWnd,i*sizeof (DWORD)), 118 "GetClassLongW value doesn't match what was set!\n"); 119 ok(!GetLastError(), 120 "GetClassLongW failed!\n"); 121 } 122 123 /* check GetClassName */ 124 i = GetClassNameW(hTestWnd, str, sizeof(str)/sizeof(str[0])); 125 ok(i == lstrlenW(className), 126 "GetClassName returned incorrect length\n"); 127 ok(!lstrcmpW(className,str), 128 "GetClassName returned incorrect name for this window's class\n"); 129 130 /* check GetClassInfo with our hInstance */ 131 if((test_atom = GetClassInfoW(hInstance, str, &wc))) 132 { 133 ok(test_atom == classatom, 134 "class atom did not match\n"); 135 ok(wc.cbClsExtra == cls.cbClsExtra, 136 "cbClsExtra did not match\n"); 137 ok(wc.cbWndExtra == cls.cbWndExtra, 138 "cbWndExtra did not match\n"); 139 ok(wc.hbrBackground == cls.hbrBackground, 140 "hbrBackground did not match\n"); 141 ok(wc.hCursor== cls.hCursor, 142 "hCursor did not match\n"); 143 ok(wc.hInstance== cls.hInstance, 144 "hInstance did not match\n"); 145 } 146 else 147 ok(FALSE,"GetClassInfo (hinstance) failed!\n"); 148 149 /* check GetClassInfo with zero hInstance */ 150 if(global) 151 { 152 if((test_atom = GetClassInfoW(0, str, &wc))) 153 { 154 ok(test_atom == classatom, 155 "class atom did not match %x != %x\n", test_atom, classatom); 156 ok(wc.cbClsExtra == cls.cbClsExtra, 157 "cbClsExtra did not match %x!=%x\n",wc.cbClsExtra,cls.cbClsExtra); 158 ok(wc.cbWndExtra == cls.cbWndExtra, 159 "cbWndExtra did not match %x!=%x\n",wc.cbWndExtra,cls.cbWndExtra); 160 ok(wc.hbrBackground == cls.hbrBackground, 161 "hbrBackground did not match %p!=%p\n",wc.hbrBackground,cls.hbrBackground); 162 ok(wc.hCursor== cls.hCursor, 163 "hCursor did not match %p!=%p\n",wc.hCursor,cls.hCursor); 164 ok(!wc.hInstance, 165 "hInstance not zero for global class %p\n",wc.hInstance); 166 } 167 else 168 ok(FALSE,"GetClassInfo (0) failed for global class!\n"); 169 } 170 else 171 { 172 ok(!GetClassInfoW(0, str, &wc), 173 "GetClassInfo (0) succeeded for local class!\n"); 174 } 175 176 ok(!UnregisterClassW(className, hInstance), 177 "Unregister class succeeded with window existing\n"); 178 179 ok(DestroyWindow(hTestWnd), 180 "DestroyWindow() failed!\n"); 181 182 ok(UnregisterClassW(className, hInstance), 183 "UnregisterClass() failed\n"); 184 185 return; 186 } 187 188 static void check_style( const char *name, int must_exist, UINT style, UINT ignore ) 189 { 190 WNDCLASSA wc; 191 192 if (GetClassInfoA( 0, name, &wc )) 193 { 194 ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n", 195 name, ~wc.style & style, wc.style, style ); 196 ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n", 197 name, wc.style & ~style, wc.style, style ); 198 } 199 else 200 ok( !must_exist, "System class %s does not exist\n", name ); 201 } 202 203 /* test styles of system classes */ 204 static void test_styles(void) 205 { 206 /* check style bits */ 207 check_style( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 208 check_style( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 209 check_style( "Edit", 1, CS_PARENTDC | CS_DBLCLKS, 0 ); 210 check_style( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS, CS_PARENTDC /*FIXME*/ ); 211 check_style( "MDIClient", 1, 0, 0 ); 212 check_style( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 213 check_style( "Static", 1, CS_PARENTDC | CS_DBLCLKS, 0 ); 214 check_style( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); 215 check_style( "DDEMLEvent", 0, 0, 0 ); 216 check_style( "Message", 0, 0, 0 ); 217 check_style( "#32768", 1, CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, CS_DROPSHADOW ); /* menu */ 218 check_style( "#32769", 1, CS_DBLCLKS, 0 ); /* desktop */ 219 check_style( "#32770", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); /* dialog */ 220 todo_wine { check_style( "#32771", 1, CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW, 0 ); } /* task switch */ 221 check_style( "#32772", 1, 0, 0 ); /* icon title */ 222 } 223 224 static void check_class_(int line, HINSTANCE inst, const char *name, const char *menu_name) 225 { 226 WNDCLASSA wc; 227 UINT atom = GetClassInfoA(inst,name,&wc); 228 ok_(__FILE__,line)( atom, "Class %s %p not found\n", name, inst ); 229 if (atom) 230 { 231 if (wc.lpszMenuName && menu_name) 232 ok_(__FILE__,line)( !strcmp( menu_name, wc.lpszMenuName ), 233 "Wrong name %s/%s for class %s %p\n", 234 wc.lpszMenuName, menu_name, name, inst ); 235 else 236 ok_(__FILE__,line)( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n", 237 wc.lpszMenuName, menu_name, name, inst ); 238 } 239 } 240 #define check_class(inst,name,menu) check_class_(__LINE__,inst,name,menu) 241 242 static void check_instance_( int line, const char *name, HINSTANCE inst, 243 HINSTANCE info_inst, HINSTANCE gcl_inst ) 244 { 245 WNDCLASSA wc; 246 HWND hwnd; 247 248 ok_(__FILE__,line)( GetClassInfoA( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst ); 249 ok_(__FILE__,line)( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n", 250 wc.hInstance, info_inst, name ); 251 hwnd = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, inst, 0 ); 252 ok_(__FILE__,line)( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst ); 253 ok_(__FILE__,line)( (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ) == gcl_inst, 254 "Wrong GCL instance %p/%p for class %s\n", 255 (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ), gcl_inst, name ); 256 ok_(__FILE__,line)( (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ) == inst, 257 "Wrong GWL instance %p/%p for window %s\n", 258 (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ), inst, name ); 259 ok_(__FILE__,line)(!UnregisterClassA(name, inst), 260 "UnregisterClassA should fail while exists a class window\n"); 261 ok_(__FILE__,line)(GetLastError() == ERROR_CLASS_HAS_WINDOWS, 262 "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %d\n", GetLastError()); 263 DestroyWindow(hwnd); 264 } 265 #define check_instance(name,inst,info_inst,gcl_inst) check_instance_(__LINE__,name,inst,info_inst,gcl_inst) 266 267 struct class_info 268 { 269 const char *name; 270 HINSTANCE inst, info_inst, gcl_inst; 271 }; 272 273 static DWORD WINAPI thread_proc(void *param) 274 { 275 struct class_info *class_info = param; 276 277 check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst); 278 279 return 0; 280 } 281 282 static void check_thread_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst ) 283 { 284 HANDLE hThread; 285 DWORD tid; 286 struct class_info class_info; 287 288 class_info.name = name; 289 class_info.inst = inst; 290 class_info.info_inst = info_inst; 291 class_info.gcl_inst = gcl_inst; 292 293 hThread = CreateThread(NULL, 0, thread_proc, &class_info, 0, &tid); 294 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); 295 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); 296 CloseHandle(hThread); 297 } 298 299 /* test various instance parameters */ 300 static void test_instances(void) 301 { 302 WNDCLASSA cls, wc; 303 WNDCLASSEXA wcexA; 304 HWND hwnd, hwnd2; 305 const char *name = "__test__"; 306 HINSTANCE kernel32 = GetModuleHandleA("kernel32"); 307 HINSTANCE user32 = GetModuleHandleA("user32"); 308 HINSTANCE main_module = GetModuleHandleA(NULL); 309 HINSTANCE zero_instance = 0; 310 DWORD r; 311 char buffer[0x10]; 312 313 memset( &cls, 0, sizeof(cls) ); 314 cls.style = CS_HREDRAW | CS_VREDRAW; 315 cls.lpfnWndProc = ClassTest_WndProc; 316 cls.cbClsExtra = 0; 317 cls.cbWndExtra = 0; 318 cls.lpszClassName = name; 319 320 cls.lpszMenuName = "main_module"; 321 cls.hInstance = main_module; 322 323 ok( RegisterClassA( &cls ), "Failed to register local class for main module\n" ); 324 check_class( main_module, name, "main_module" ); 325 check_instance( name, main_module, main_module, main_module ); 326 check_thread_instance( name, main_module, main_module, main_module ); 327 328 cls.lpszMenuName = "kernel32"; 329 cls.hInstance = kernel32; 330 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 331 check_class( kernel32, name, "kernel32" ); 332 check_class( main_module, name, "main_module" ); 333 check_instance( name, kernel32, kernel32, kernel32 ); 334 check_thread_instance( name, kernel32, kernel32, kernel32 ); 335 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 336 337 ZeroMemory(&wcexA, sizeof(wcexA)); 338 wcexA.lpfnWndProc = DefWindowProcA; 339 wcexA.lpszClassName = "__classex_test__"; 340 SetLastError(0xdeadbeef); 341 wcexA.cbSize = sizeof(wcexA) - 1; 342 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 343 "Succeeded with invalid number of cbSize bytes\n"); 344 SetLastError(0xdeadbeef); 345 wcexA.cbSize = sizeof(wcexA) + 1; 346 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 347 "Succeeded with invalid number of cbSize bytes\n"); 348 SetLastError(0xdeadbeef); 349 wcexA.cbSize = sizeof(wcexA); 350 ok( RegisterClassExA( &wcexA ), "Failed with valid number of cbSize bytes\n"); 351 wcexA.cbSize = 0xdeadbeef; 352 ok( GetClassInfoExA(main_module, wcexA.lpszClassName, &wcexA), "GetClassInfoEx failed\n"); 353 ok( wcexA.cbSize == 0xdeadbeef, "GetClassInfoEx returned wrong cbSize value %d\n", wcexA.cbSize); 354 UnregisterClassA(wcexA.lpszClassName, main_module); 355 356 /* Bug 2631 - Supplying an invalid number of bytes fails */ 357 cls.cbClsExtra = 0; 358 cls.cbWndExtra = -1; 359 SetLastError(0xdeadbeef); 360 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 361 "Failed with invalid number of WndExtra bytes\n"); 362 363 cls.cbClsExtra = -1; 364 cls.cbWndExtra = 0; 365 SetLastError(0xdeadbeef); 366 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 367 "Failed with invalid number of ClsExtra bytes\n"); 368 369 cls.cbClsExtra = -1; 370 cls.cbWndExtra = -1; 371 SetLastError(0xdeadbeef); 372 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 373 "Failed with invalid number of ClsExtra and cbWndExtra bytes\n"); 374 375 cls.cbClsExtra = 0; 376 cls.cbWndExtra = 0; 377 SetLastError(0xdeadbeef); 378 379 /* setting global flag doesn't change status of class */ 380 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 381 ok( hwnd != 0, "CreateWindow failed error %u\n", GetLastError()); 382 SetClassLongA( hwnd, GCL_STYLE, CS_GLOBALCLASS ); 383 cls.lpszMenuName = "kernel32"; 384 cls.hInstance = kernel32; 385 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 386 check_class( kernel32, name, "kernel32" ); 387 check_class( main_module, name, "main_module" ); 388 check_instance( name, kernel32, kernel32, kernel32 ); 389 check_instance( name, main_module, main_module, main_module ); 390 check_thread_instance( name, kernel32, kernel32, kernel32 ); 391 check_thread_instance( name, main_module, main_module, main_module ); 392 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 393 394 /* changing the instance doesn't make it global */ 395 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0 ); 396 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 397 check_class( kernel32, name, "kernel32" ); 398 check_instance( name, kernel32, kernel32, kernel32 ); 399 check_thread_instance( name, kernel32, kernel32, kernel32 ); 400 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 401 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 402 403 /* GetClassInfo with instance 0 finds user32 instance */ 404 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)user32 ); 405 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 406 if (!GetClassInfoA( 0, name, &wc )) zero_instance = user32; /* instance 0 not supported on wow64 */ 407 else 408 { 409 check_instance( name, 0, 0, kernel32 ); 410 check_thread_instance( name, 0, 0, kernel32 ); 411 } 412 check_class( kernel32, name, "kernel32" ); 413 check_class( user32, name, "main_module" ); 414 check_class( zero_instance, name, "main_module" ); 415 check_instance( name, kernel32, kernel32, kernel32 ); 416 check_instance( name, user32, zero_instance, user32 ); 417 check_thread_instance( name, kernel32, kernel32, kernel32 ); 418 check_thread_instance( name, user32, zero_instance, user32 ); 419 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 420 421 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0x12345678 ); 422 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 423 check_class( kernel32, name, "kernel32" ); 424 check_class( (HINSTANCE)0x12345678, name, "main_module" ); 425 check_instance( name, kernel32, kernel32, kernel32 ); 426 check_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 ); 427 check_thread_instance( name, kernel32, kernel32, kernel32 ); 428 check_thread_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 ); 429 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 430 431 /* creating a window with instance 0 uses the first class found */ 432 cls.hInstance = (HINSTANCE)0xdeadbeef; 433 cls.lpszMenuName = "deadbeef"; 434 cls.style = 3; 435 ok( RegisterClassA( &cls ), "Failed to register local class for deadbeef\n" ); 436 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 437 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0xdeadbeef, 438 "Didn't get deadbeef class for null instance\n" ); 439 DestroyWindow( hwnd2 ); 440 ok( UnregisterClassA( name, (HINSTANCE)0xdeadbeef ), "Unregister failed for deadbeef\n" ); 441 442 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 443 ok( (HINSTANCE)GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == kernel32, 444 "Didn't get kernel32 class for null instance\n" ); 445 DestroyWindow( hwnd2 ); 446 447 r = GetClassNameA( hwnd, buffer, 4 ); 448 ok( r == 3, "expected 3, got %d\n", r ); 449 ok( !strcmp( buffer, "__t"), "name wrong: %s\n", buffer ); 450 451 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 452 453 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 454 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0x12345678, 455 "Didn't get 12345678 class for null instance\n" ); 456 DestroyWindow( hwnd2 ); 457 458 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)main_module ); 459 DestroyWindow( hwnd ); 460 461 /* null handle means the same thing as main module */ 462 cls.lpszMenuName = "null"; 463 cls.hInstance = 0; 464 ok( !RegisterClassA( &cls ), "Succeeded registering local class for null instance\n" ); 465 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 466 ok( UnregisterClassA( name, main_module ), "Unregister failed for main module\n" ); 467 468 ok( RegisterClassA( &cls ), "Failed to register local class for null instance\n" ); 469 /* must be found with main module handle */ 470 check_class( main_module, name, "null" ); 471 check_instance( name, main_module, main_module, main_module ); 472 check_thread_instance( name, main_module, main_module, main_module ); 473 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 474 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 475 ok( UnregisterClassA( name, 0 ), "Unregister failed for null instance\n" ); 476 477 /* registering for user32 always fails */ 478 cls.lpszMenuName = "user32"; 479 cls.hInstance = user32; 480 ok( !RegisterClassA( &cls ), "Succeeded registering local class for user32\n" ); 481 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() ); 482 cls.style |= CS_GLOBALCLASS; 483 ok( !RegisterClassA( &cls ), "Succeeded registering global class for user32\n" ); 484 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() ); 485 486 /* unregister is OK though */ 487 cls.hInstance = main_module; 488 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" ); 489 ok( UnregisterClassA( name, user32 ), "Unregister failed for user32\n" ); 490 491 /* instance doesn't matter for global class */ 492 cls.style |= CS_GLOBALCLASS; 493 cls.lpszMenuName = "main_module"; 494 cls.hInstance = main_module; 495 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" ); 496 cls.lpszMenuName = "kernel32"; 497 cls.hInstance = kernel32; 498 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" ); 499 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 500 /* even if global flag is cleared */ 501 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 502 SetClassLongA( hwnd, GCL_STYLE, 0 ); 503 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" ); 504 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 505 506 check_class( main_module, name, "main_module" ); 507 check_class( kernel32, name, "main_module" ); 508 check_class( 0, name, "main_module" ); 509 check_class( (HINSTANCE)0x12345678, name, "main_module" ); 510 check_instance( name, main_module, main_module, main_module ); 511 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module ); 512 check_thread_instance( name, main_module, main_module, main_module ); 513 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module ); 514 515 /* changing the instance for global class doesn't make much difference */ 516 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef ); 517 check_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef ); 518 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef ); 519 check_thread_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef ); 520 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef ); 521 522 DestroyWindow( hwnd ); 523 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" ); 524 ok( !UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister succeeded the second time\n" ); 525 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 526 527 cls.hInstance = (HINSTANCE)0x12345678; 528 ok( RegisterClassA( &cls ), "Failed to register global class for dummy instance\n" ); 529 check_instance( name, main_module, main_module, (HINSTANCE)0x12345678 ); 530 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 ); 531 check_thread_instance( name, main_module, main_module, (HINSTANCE)0x12345678 ); 532 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 ); 533 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" ); 534 535 /* check system classes */ 536 537 /* we cannot register a global class with the name of a system class */ 538 cls.style |= CS_GLOBALCLASS; 539 cls.lpszMenuName = "button_main_module"; 540 cls.lpszClassName = "BUTTON"; 541 cls.hInstance = main_module; 542 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for main module\n" ); 543 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 544 cls.hInstance = kernel32; 545 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for kernel32\n" ); 546 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 547 548 /* local class is OK however */ 549 cls.style &= ~CS_GLOBALCLASS; 550 cls.lpszMenuName = "button_main_module"; 551 cls.hInstance = main_module; 552 ok( RegisterClassA( &cls ), "Failed to register local button class for main module\n" ); 553 check_class( main_module, "BUTTON", "button_main_module" ); 554 cls.lpszMenuName = "button_kernel32"; 555 cls.hInstance = kernel32; 556 ok( RegisterClassA( &cls ), "Failed to register local button class for kernel32\n" ); 557 check_class( kernel32, "BUTTON", "button_kernel32" ); 558 check_class( main_module, "BUTTON", "button_main_module" ); 559 ok( UnregisterClassA( "BUTTON", kernel32 ), "Unregister failed for kernel32 button\n" ); 560 ok( UnregisterClassA( "BUTTON", main_module ), "Unregister failed for main module button\n" ); 561 /* GetClassInfo sets instance to passed value for global classes */ 562 check_instance( "BUTTON", 0, 0, user32 ); 563 check_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 564 check_instance( "BUTTON", user32, zero_instance, user32 ); 565 check_thread_instance( "BUTTON", 0, 0, user32 ); 566 check_thread_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 567 check_thread_instance( "BUTTON", user32, zero_instance, user32 ); 568 569 /* we can unregister system classes */ 570 ok( GetClassInfoA( 0, "BUTTON", &wc ), "Button class not found with null instance\n" ); 571 ok( GetClassInfoA( kernel32, "BUTTON", &wc ), "Button class not found with kernel32\n" ); 572 ok( UnregisterClassA( "BUTTON", (HINSTANCE)0x12345678 ), "Failed to unregister button\n" ); 573 ok( !UnregisterClassA( "BUTTON", (HINSTANCE)0x87654321 ), "Unregistered button a second time\n" ); 574 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 575 ok( !GetClassInfoA( 0, "BUTTON", &wc ), "Button still exists\n" ); 576 /* last error not set reliably */ 577 578 /* we can change the instance of a system class */ 579 check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 580 check_thread_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 581 hwnd = CreateWindowExA( 0, "EDIT", "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 582 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef ); 583 check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); 584 check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); 585 DestroyWindow(hwnd); 586 } 587 588 static void test_builtinproc(void) 589 { 590 /* Edit behaves differently */ 591 static const CHAR NORMAL_CLASSES[][10] = { 592 "Button", 593 "Static", 594 "ComboBox", 595 "ComboLBox", 596 "ListBox", 597 "ScrollBar", 598 "#32770", /* dialog */ 599 }; 600 static const int NUM_NORMAL_CLASSES = (sizeof(NORMAL_CLASSES)/sizeof(NORMAL_CLASSES[0])); 601 static const char classA[] = "deftest"; 602 static const WCHAR classW[] = {'d','e','f','t','e','s','t',0}; 603 WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0}; /* a string that would be destroyed by a W->A->W conversion */ 604 WNDPROC pDefWindowProcA, pDefWindowProcW; 605 WNDPROC pNtdllDefWindowProcA, pNtdllDefWindowProcW; 606 WNDPROC oldproc; 607 WNDCLASSEXA cls; /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */ 608 WCHAR buf[128]; 609 ATOM atom; 610 HWND hwnd; 611 int i; 612 613 pDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA"); 614 pDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW"); 615 pNtdllDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_A"); 616 pNtdllDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_W"); 617 618 /* On Vista+, the user32.dll export DefWindowProcA/W is forwarded to */ 619 /* ntdll.NtdllDefWindowProc_A/W. However, the wndproc returned by */ 620 /* GetClassLong/GetWindowLong points to an unexported user32 function */ 621 if (pDefWindowProcA == pNtdllDefWindowProcA && 622 pDefWindowProcW == pNtdllDefWindowProcW) 623 skip("user32.DefWindowProcX forwarded to ntdll.NtdllDefWindowProc_X\n"); 624 else 625 { 626 for (i = 0; i < 4; i++) 627 { 628 ZeroMemory(&cls, sizeof(cls)); 629 cls.cbSize = sizeof(cls); 630 cls.hInstance = GetModuleHandleA(NULL); 631 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 632 if (i & 1) 633 cls.lpfnWndProc = pDefWindowProcA; 634 else 635 cls.lpfnWndProc = pDefWindowProcW; 636 637 if (i & 2) 638 { 639 cls.lpszClassName = classA; 640 atom = RegisterClassExA(&cls); 641 } 642 else 643 { 644 cls.lpszClassName = (LPCSTR)classW; 645 atom = RegisterClassExW((WNDCLASSEXW *)&cls); 646 } 647 ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError()); 648 649 hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL); 650 ok(hwnd != NULL, "Couldn't create window i=%d\n", i); 651 652 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", 653 (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA); 654 ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", 655 (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA); 656 657 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", 658 (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW); 659 ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", 660 (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW); 661 662 DestroyWindow(hwnd); 663 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 664 } 665 } 666 667 /* built-in winproc - window A/W type automatically detected */ 668 ZeroMemory(&cls, sizeof(cls)); 669 cls.cbSize = sizeof(cls); 670 cls.hInstance = GetModuleHandleA(NULL); 671 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 672 cls.lpszClassName = classA; 673 cls.lpfnWndProc = pDefWindowProcW; 674 atom = RegisterClassExA(&cls); 675 676 hwnd = CreateWindowExW(0, classW, unistring, WS_OVERLAPPEDWINDOW, 677 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleW(NULL), 0); 678 ok(IsWindowUnicode(hwnd) || 679 broken(!IsWindowUnicode(hwnd)) /* Windows 8 and 10 */, 680 "Windows should be Unicode\n"); 681 SendMessageW(hwnd, WM_GETTEXT, sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); 682 if (IsWindowUnicode(hwnd)) 683 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 684 else 685 ok(memcmp(buf, unistring, sizeof(unistring)) != 0, "WM_GETTEXT invalid return\n"); 686 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pDefWindowProcA); 687 ok(IsWindowUnicode(hwnd), "Windows should have remained Unicode\n"); 688 if (GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA) 689 { 690 /* DefWindowProc isn't magic on wow64 */ 691 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Ansi winproc is not a handle\n"); 692 } 693 else 694 { 695 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Invalid Unicode winproc\n"); 696 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Invalid Ansi winproc\n"); 697 } 698 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 699 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have switched window to ANSI\n"); 700 701 DestroyWindow(hwnd); 702 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 703 704 /* custom winproc - the same function can be used as both A and W*/ 705 ZeroMemory(&cls, sizeof(cls)); 706 cls.cbSize = sizeof(cls); 707 cls.hInstance = GetModuleHandleA(NULL); 708 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 709 cls.lpszClassName = classA; 710 cls.lpfnWndProc = ClassTest_WndProc2; 711 atom = RegisterClassExA(&cls); 712 713 hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW, 714 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); 715 ok(IsWindowUnicode(hwnd) == FALSE, "Window should be ANSI\n"); 716 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 717 ok(IsWindowUnicode(hwnd), "SetWindowLongPtrW should have changed window to Unicode\n"); 718 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 719 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n"); 720 721 DestroyWindow(hwnd); 722 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 723 724 /* For most of the builtin controls both GetWindowLongPtrA and W returns a pointer that is executed directly 725 * by CallWindowProcA/W */ 726 for (i = 0; i < NUM_NORMAL_CLASSES; i++) 727 { 728 WNDPROC procA, procW; 729 hwnd = CreateWindowExA(0, NORMAL_CLASSES[i], classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, 730 NULL, NULL, NULL, 0); 731 ok(hwnd != NULL, "Couldn't create window of class %s\n", NORMAL_CLASSES[i]); 732 SetWindowTextA(hwnd, classA); /* ComboBox needs this */ 733 procA = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); 734 procW = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); 735 ok(!IS_WNDPROC_HANDLE(procA), "procA should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procA); 736 ok(!IS_WNDPROC_HANDLE(procW), "procW should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procW); 737 CallWindowProcA(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 738 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT A/A invalid return for class %s\n", NORMAL_CLASSES[i]); 739 CallWindowProcA(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 740 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT A/W invalid return for class %s\n", NORMAL_CLASSES[i]); 741 CallWindowProcW(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 742 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT W/A invalid return for class %s\n", NORMAL_CLASSES[i]); 743 CallWindowProcW(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 744 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT W/W invalid return for class %s\n", NORMAL_CLASSES[i]); 745 746 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 747 ok(IS_WNDPROC_HANDLE(oldproc) == FALSE, "Class %s shouldn't return a handle\n", NORMAL_CLASSES[i]); 748 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 749 DestroyWindow(hwnd); 750 } 751 752 /* Edit controls are special - they return a wndproc handle when GetWindowLongPtr is called with a different A/W. 753 * On the other hand there is no W->A->W conversion so this control is treated specially. */ 754 hwnd = CreateWindowW(WC_EDITW, unistring, WS_OVERLAPPEDWINDOW, 755 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); 756 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */ 757 ok(IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a Unicode wndproc\n"); 758 ok(IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a ANSI wndproc\n"); 759 /* But GetWindowLongPtr returns only a handle for the ANSI one */ 760 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 761 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return a W wndproc handle\n"); 762 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 763 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 764 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 765 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 766 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 767 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 768 769 SetWindowTextW(hwnd, classW); 770 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 771 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 772 773 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc2); 774 /* SetWindowLongPtr returns a wndproc handle - like GetWindowLongPtr */ 775 ok(IS_WNDPROC_HANDLE(oldproc), "Edit control should return a wndproc handle\n"); 776 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n"); 777 SetWindowTextA(hwnd, classA); /* Windows resets the title to WideStringToMultiByte(unistring) */ 778 memset(buf, 0, sizeof(buf)); 779 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 780 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 781 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 782 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 783 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 784 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 785 786 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 787 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); 788 789 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 790 791 DestroyWindow(hwnd); 792 793 hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW, 794 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); 795 796 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */ 797 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)), "Edit control class should have a Unicode wndproc\n"); 798 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)), "Edit control class should have a ANSI wndproc\n"); 799 /* But GetWindowLongPtr returns only a handle for the Unicode one */ 800 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return an A wndproc handle\n"); 801 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 802 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 803 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 804 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 805 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 806 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 807 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 808 809 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 810 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); 811 812 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 813 SetWindowTextW(hwnd, unistring); 814 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 815 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 816 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 817 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 818 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 819 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 820 821 SetWindowTextW(hwnd, classW); 822 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 823 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 824 825 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 826 827 DestroyWindow(hwnd); 828 } 829 830 831 static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 832 { 833 return DefWindowProcA(hWnd, uMsg, wParam, lParam); 834 } 835 836 static BOOL RegisterTestDialog(HINSTANCE hInstance) 837 { 838 WNDCLASSEXA wcx; 839 ATOM atom = 0; 840 841 ZeroMemory(&wcx, sizeof(WNDCLASSEXA)); 842 wcx.cbSize = sizeof(wcx); 843 wcx.lpfnWndProc = TestDlgProc; 844 wcx.cbClsExtra = 0; 845 wcx.cbWndExtra = DLGWINDOWEXTRA; 846 wcx.hInstance = hInstance; 847 wcx.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); 848 wcx.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); 849 wcx.hbrBackground = GetStockObject(WHITE_BRUSH); 850 wcx.lpszClassName = "TestDialog"; 851 wcx.lpszMenuName = "TestDialog"; 852 wcx.hIconSm = LoadImageA(hInstance, (LPCSTR)MAKEINTRESOURCE(5), IMAGE_ICON, 853 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 854 LR_DEFAULTCOLOR); 855 856 atom = RegisterClassExA(&wcx); 857 ok(atom != 0, "RegisterClassEx returned 0\n"); 858 859 return atom; 860 } 861 862 /* test registering a dialog box created by using the CLASS directive in a 863 resource file, then test creating the dialog using CreateDialogParam. */ 864 static void CreateDialogParamTest(HINSTANCE hInstance) 865 { 866 HWND hWndMain; 867 868 if (RegisterTestDialog(hInstance)) 869 { 870 hWndMain = CreateDialogParamA(hInstance, "CLASS_TEST_DIALOG", NULL, 0, 0); 871 ok(hWndMain != NULL, "CreateDialogParam returned NULL\n"); 872 ShowWindow(hWndMain, SW_SHOW); 873 DestroyWindow(hWndMain); 874 } 875 } 876 877 static const struct 878 { 879 const char name[9]; 880 int value; 881 int badvalue; 882 } extra_values[] = 883 { 884 {"#32770",30,30}, /* Dialog */ 885 #ifdef _WIN64 886 {"Edit",8,8}, 887 #else 888 {"Edit",6,8}, /* Windows XP 64-bit returns 8 also to 32-bit applications */ 889 #endif 890 }; 891 892 static void test_extra_values(void) 893 { 894 int i; 895 for(i=0; i< sizeof(extra_values)/sizeof(extra_values[0]); i++) 896 { 897 WNDCLASSEXA wcx; 898 BOOL ret = GetClassInfoExA(NULL,extra_values[i].name,&wcx); 899 900 ok( ret, "GetClassInfo (0) failed for global class %s\n", extra_values[i].name); 901 if (!ret) continue; 902 ok(extra_values[i].value == wcx.cbWndExtra || broken(extra_values[i].badvalue == wcx.cbWndExtra), 903 "expected %d, got %d\n", extra_values[i].value, wcx.cbWndExtra); 904 } 905 } 906 907 static void test_GetClassInfo(void) 908 { 909 static const WCHAR staticW[] = {'s','t','a','t','i','c',0}; 910 WNDCLASSA wc; 911 WNDCLASSEXA wcx; 912 BOOL ret; 913 914 SetLastError(0xdeadbeef); 915 ret = GetClassInfoA(0, "static", &wc); 916 ok(ret, "GetClassInfoA() error %d\n", GetLastError()); 917 918 if (0) { /* crashes under XP */ 919 SetLastError(0xdeadbeef); 920 ret = GetClassInfoA(0, "static", NULL); 921 ok(ret, "GetClassInfoA() error %d\n", GetLastError()); 922 923 SetLastError(0xdeadbeef); 924 ret = GetClassInfoW(0, staticW, NULL); 925 ok(ret, "GetClassInfoW() error %d\n", GetLastError()); 926 } 927 928 wcx.cbSize = sizeof(wcx); 929 SetLastError(0xdeadbeef); 930 ret = GetClassInfoExA(0, "static", &wcx); 931 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 932 933 SetLastError(0xdeadbeef); 934 ret = GetClassInfoExA(0, "static", NULL); 935 ok(!ret, "GetClassInfoExA() should fail\n"); 936 ok(GetLastError() == ERROR_NOACCESS || 937 broken(GetLastError() == 0xdeadbeef), /* win9x */ 938 "expected ERROR_NOACCESS, got %d\n", GetLastError()); 939 940 SetLastError(0xdeadbeef); 941 ret = GetClassInfoExW(0, staticW, NULL); 942 ok(!ret, "GetClassInfoExW() should fail\n"); 943 ok(GetLastError() == ERROR_NOACCESS || 944 broken(GetLastError() == 0xdeadbeef) /* NT4 */ || 945 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ 946 "expected ERROR_NOACCESS, got %d\n", GetLastError()); 947 948 wcx.cbSize = 0; 949 wcx.lpfnWndProc = NULL; 950 SetLastError(0xdeadbeef); 951 ret = GetClassInfoExA(0, "static", &wcx); 952 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 953 ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize); 954 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 955 956 wcx.cbSize = sizeof(wcx) - 1; 957 wcx.lpfnWndProc = NULL; 958 SetLastError(0xdeadbeef); 959 ret = GetClassInfoExA(0, "static", &wcx); 960 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 961 ok(wcx.cbSize == sizeof(wcx) - 1, "expected sizeof(wcx)-1, got %u\n", wcx.cbSize); 962 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 963 964 wcx.cbSize = sizeof(wcx) + 1; 965 wcx.lpfnWndProc = NULL; 966 SetLastError(0xdeadbeef); 967 ret = GetClassInfoExA(0, "static", &wcx); 968 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 969 ok(wcx.cbSize == sizeof(wcx) + 1, "expected sizeof(wcx)+1, got %u\n", wcx.cbSize); 970 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 971 } 972 973 static void test_icons(void) 974 { 975 WNDCLASSEXW wcex, ret_wcex; 976 WCHAR cls_name[] = {'I','c','o','n','T','e','s','t','C','l','a','s','s',0}; 977 HWND hwnd; 978 HINSTANCE hinst = GetModuleHandleW(0); 979 HICON hsmicon, hsmallnew; 980 ICONINFO icinf; 981 982 memset(&wcex, 0, sizeof wcex); 983 wcex.cbSize = sizeof wcex; 984 wcex.lpfnWndProc = ClassTest_WndProc; 985 wcex.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); 986 wcex.hInstance = hinst; 987 wcex.lpszClassName = cls_name; 988 ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n"); 989 hwnd = CreateWindowExW(0, cls_name, NULL, WS_OVERLAPPEDWINDOW, 990 0, 0, 0, 0, NULL, NULL, hinst, 0); 991 ok(hwnd != NULL, "Window was not created\n"); 992 993 ok(GetClassInfoExW(hinst, cls_name, &ret_wcex), "Class info was not retrieved\n"); 994 ok(wcex.hIcon == ret_wcex.hIcon, "Icons don't match\n"); 995 ok(ret_wcex.hIconSm != NULL, "hIconSm should be non-zero handle\n"); 996 997 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 998 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 999 1000 ok(SendMessageA(hwnd, WM_GETICON, ICON_BIG, 0) == 0, 1001 "WM_GETICON with ICON_BIG should not return the class icon\n"); 1002 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL, 0) == 0, 1003 "WM_GETICON with ICON_SMALL should not return the class icon\n"); 1004 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL2, 0) == 0, 1005 "WM_GETICON with ICON_SMALL2 should not return the class icon\n"); 1006 1007 hsmallnew = CopyImage(wcex.hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), 1008 GetSystemMetrics(SM_CYSMICON), 0); 1009 ok(!SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hsmallnew), 1010 "Previous hIconSm should be zero\n"); 1011 ok(hsmallnew == (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM), 1012 "Should return explicitly assigned small icon\n"); 1013 ok(!GetIconInfo(hsmicon, &icinf), "Previous small icon should be destroyed\n"); 1014 1015 SetClassLongPtrW(hwnd, GCLP_HICONSM, 0); 1016 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 1017 ok( hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 1018 1019 SetClassLongPtrW(hwnd, GCLP_HICON, 0); 1020 ok(!GetClassLongPtrW(hwnd, GCLP_HICONSM), "GetClassLong should return zero handle\n"); 1021 1022 SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)LoadIconW(NULL, (LPCWSTR)IDI_QUESTION)); 1023 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 1024 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 1025 UnregisterClassW(cls_name, hinst); 1026 ok(GetIconInfo(hsmicon, &icinf), "Icon should NOT be destroyed\n"); 1027 1028 DestroyIcon(hsmallnew); 1029 DestroyWindow(hwnd); 1030 } 1031 1032 static void test_comctl32_class( const char *name ) 1033 { 1034 WNDCLASSA wcA; 1035 WNDCLASSW wcW; 1036 BOOL ret; 1037 HMODULE module; 1038 WCHAR nameW[20]; 1039 HWND hwnd; 1040 1041 module = GetModuleHandleA( "comctl32" ); 1042 ok( !module, "comctl32 already loaded\n" ); 1043 ret = GetClassInfoA( 0, name, &wcA ); 1044 ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name ); 1045 if (!ret) return; 1046 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); 1047 ret = GetClassInfoW( 0, nameW, &wcW ); 1048 ok( ret, "GetClassInfoW failed for %s\n", name ); 1049 module = GetModuleHandleA( "comctl32" ); 1050 ok( module != 0, "comctl32 not loaded\n" ); 1051 FreeLibrary( module ); 1052 module = GetModuleHandleA( "comctl32" ); 1053 ok( !module, "comctl32 still loaded\n" ); 1054 hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); 1055 ok( hwnd != 0, "failed to create window for %s\n", name ); 1056 module = GetModuleHandleA( "comctl32" ); 1057 ok( module != 0, "comctl32 not loaded\n" ); 1058 } 1059 1060 /* verify that comctl32 classes are automatically loaded by user32 */ 1061 static void test_comctl32_classes(void) 1062 { 1063 char path_name[MAX_PATH]; 1064 PROCESS_INFORMATION info; 1065 STARTUPINFOA startup; 1066 char **argv; 1067 int i; 1068 1069 static const char *classes[] = 1070 { 1071 ANIMATE_CLASSA, 1072 WC_COMBOBOXEXA, 1073 DATETIMEPICK_CLASSA, 1074 WC_HEADERA, 1075 HOTKEY_CLASSA, 1076 WC_IPADDRESSA, 1077 WC_LISTVIEWA, 1078 MONTHCAL_CLASSA, 1079 WC_NATIVEFONTCTLA, 1080 WC_PAGESCROLLERA, 1081 PROGRESS_CLASSA, 1082 REBARCLASSNAMEA, 1083 STATUSCLASSNAMEA, 1084 WC_TABCONTROLA, 1085 TOOLBARCLASSNAMEA, 1086 TOOLTIPS_CLASSA, 1087 TRACKBAR_CLASSA, 1088 WC_TREEVIEWA, 1089 UPDOWN_CLASSA 1090 }; 1091 1092 winetest_get_mainargs( &argv ); 1093 for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) 1094 { 1095 memset( &startup, 0, sizeof(startup) ); 1096 startup.cb = sizeof( startup ); 1097 sprintf( path_name, "%s class %s", argv[0], classes[i] ); 1098 ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ), 1099 "CreateProcess failed.\n" ); 1100 winetest_wait_child_process( info.hProcess ); 1101 CloseHandle( info.hProcess ); 1102 CloseHandle( info.hThread ); 1103 } 1104 } 1105 1106 static void test_IME(void) 1107 { 1108 static const WCHAR ime_classW[] = {'I','M','E',0}; 1109 1110 char module_name[MAX_PATH], *ptr; 1111 MEMORY_BASIC_INFORMATION mbi; 1112 WNDCLASSW wnd_classw; 1113 WNDCLASSA wnd_class; 1114 SIZE_T size; 1115 BOOL ret; 1116 1117 if (!GetProcAddress(GetModuleHandleA("user32.dll"), "BroadcastSystemMessageExA")) 1118 { 1119 win_skip("BroadcastSystemMessageExA not available, skipping IME class test\n"); 1120 return; 1121 } 1122 1123 ok(GetModuleHandleA("imm32") != 0, "imm32.dll is not loaded\n"); 1124 1125 ret = GetClassInfoA(NULL, "IME", &wnd_class); 1126 ok(ret, "GetClassInfo failed: %d\n", GetLastError()); 1127 1128 size = VirtualQuery(wnd_class.lpfnWndProc, &mbi, sizeof(mbi)); 1129 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); 1130 if (size == sizeof(mbi)) { 1131 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); 1132 ok(size, "GetModuleFileName failed\n"); 1133 for (ptr = module_name+size-1; ptr > module_name; ptr--) 1134 if (*ptr == '\\' || *ptr == '/') break; 1135 if (*ptr == '\\' || *ptr=='/') ptr++; 1136 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr); 1137 } 1138 1139 ret = GetClassInfoW(NULL, ime_classW, &wnd_classw); 1140 ok(ret, "GetClassInfo failed: %d\n", GetLastError()); 1141 1142 size = VirtualQuery(wnd_classw.lpfnWndProc, &mbi, sizeof(mbi)); 1143 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); 1144 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); 1145 ok(size, "GetModuleFileName failed\n"); 1146 for (ptr = module_name+size-1; ptr > module_name; ptr--) 1147 if (*ptr == '\\' || *ptr == '/') break; 1148 if (*ptr == '\\' || *ptr=='/') ptr++; 1149 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr); 1150 } 1151 1152 START_TEST(class) 1153 { 1154 char **argv; 1155 HANDLE hInstance = GetModuleHandleA( NULL ); 1156 int argc = winetest_get_mainargs( &argv ); 1157 1158 if (argc >= 3) 1159 { 1160 test_comctl32_class( argv[2] ); 1161 return; 1162 } 1163 1164 test_IME(); 1165 test_GetClassInfo(); 1166 test_extra_values(); 1167 1168 if (!GetModuleHandleW(0)) 1169 { 1170 trace("Class test is incompatible with Win9x implementation, skipping\n"); 1171 return; 1172 } 1173 1174 ClassTest(hInstance,FALSE); 1175 ClassTest(hInstance,TRUE); 1176 CreateDialogParamTest(hInstance); 1177 test_styles(); 1178 test_builtinproc(); 1179 test_icons(); 1180 test_comctl32_classes(); 1181 1182 /* this test unregisters the Button class so it should be executed at the end */ 1183 test_instances(); 1184 } 1185