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 <stdlib.h> 22 #include <stdarg.h> 23 #include <stdio.h> 24 25 #include "wine/test.h" 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winnls.h" 29 #include "winreg.h" 30 #include "wingdi.h" 31 #include "winuser.h" 32 #include "commctrl.h" 33 34 #define NUMCLASSWORDS 4 35 36 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16)) 37 38 #ifdef __i386__ 39 #define ARCH "x86" 40 #elif defined __x86_64__ 41 #define ARCH "amd64" 42 #elif defined __arm__ 43 #define ARCH "arm" 44 #elif defined __aarch64__ 45 #define ARCH "arm64" 46 #else 47 #define ARCH "none" 48 #endif 49 50 static const char comctl32_manifest[] = 51 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" 52 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n" 53 " <assemblyIdentity\n" 54 " type=\"win32\"\n" 55 " name=\"Wine.User32.Tests\"\n" 56 " version=\"1.0.0.0\"\n" 57 " processorArchitecture=\"" ARCH "\"\n" 58 " />\n" 59 "<description>Wine comctl32 test suite</description>\n" 60 "<dependency>\n" 61 " <dependentAssembly>\n" 62 " <assemblyIdentity\n" 63 " type=\"win32\"\n" 64 " name=\"microsoft.windows.common-controls\"\n" 65 " version=\"6.0.0.0\"\n" 66 " processorArchitecture=\"" ARCH "\"\n" 67 " publicKeyToken=\"6595b64144ccf1df\"\n" 68 " language=\"*\"\n" 69 " />\n" 70 "</dependentAssembly>\n" 71 "</dependency>\n" 72 "</assembly>\n"; 73 74 static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 75 { 76 if (msg == WM_NCCREATE) return 1; 77 return DefWindowProcW (hWnd, msg, wParam, lParam); 78 } 79 80 static LRESULT WINAPI ClassTest_WndProc2 (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 81 { 82 if (msg == WM_NCCREATE) return 1; 83 return DefWindowProcA (hWnd, msg, wParam, lParam); 84 } 85 86 /*********************************************************************** 87 */ 88 static void ClassTest(HINSTANCE hInstance, BOOL global) 89 { 90 WNDCLASSW cls, wc; 91 static const WCHAR className[] = {'T','e','s','t','C','l','a','s','s',0}; 92 static const WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0}; 93 ATOM test_atom; 94 HWND hTestWnd; 95 LONG i; 96 WCHAR str[20]; 97 ATOM classatom; 98 99 cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0); 100 cls.lpfnWndProc = ClassTest_WndProc; 101 cls.cbClsExtra = NUMCLASSWORDS*sizeof(DWORD); 102 cls.cbWndExtra = 12; 103 cls.hInstance = hInstance; 104 cls.hIcon = LoadIconW (0, (LPWSTR)IDI_APPLICATION); 105 cls.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 106 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 107 cls.lpszMenuName = 0; 108 cls.lpszClassName = className; 109 110 classatom=RegisterClassW(&cls); 111 if (!classatom && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) 112 return; 113 ok(classatom, "failed to register class\n"); 114 115 ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) != 0, "atom not found\n"); 116 117 ok(!RegisterClassW (&cls), 118 "RegisterClass of the same class should fail for the second time\n"); 119 120 /* Setup windows */ 121 hTestWnd = CreateWindowW (className, winName, 122 WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL, 123 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 124 0, hInstance, 0); 125 126 ok(hTestWnd!=0, "Failed to create window\n"); 127 128 /* test initial values of valid classwords */ 129 for(i=0; i<NUMCLASSWORDS; i++) 130 { 131 SetLastError(0); 132 ok(!GetClassLongW(hTestWnd,i*sizeof (DWORD)), 133 "GetClassLongW initial value nonzero!\n"); 134 ok(!GetLastError(), 135 "GetClassLongW failed!\n"); 136 } 137 138 if (0) 139 { 140 /* 141 * GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD)) 142 * does not fail on Win 98, though MSDN says it should 143 */ 144 SetLastError(0); 145 GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD)); 146 ok(GetLastError(), 147 "GetClassLongW() with invalid offset did not fail\n"); 148 } 149 150 /* set values of valid class words */ 151 for(i=0; i<NUMCLASSWORDS; i++) 152 { 153 SetLastError(0); 154 ok(!SetClassLongW(hTestWnd,i*sizeof(DWORD),i+1), 155 "GetClassLongW(%d) initial value nonzero!\n",i); 156 ok(!GetLastError(), 157 "SetClassLongW(%d) failed!\n",i); 158 } 159 160 /* test values of valid classwords that we set */ 161 for(i=0; i<NUMCLASSWORDS; i++) 162 { 163 SetLastError(0); 164 ok( (i+1) == GetClassLongW(hTestWnd,i*sizeof (DWORD)), 165 "GetClassLongW value doesn't match what was set!\n"); 166 ok(!GetLastError(), 167 "GetClassLongW failed!\n"); 168 } 169 170 /* check GetClassName */ 171 i = GetClassNameW(hTestWnd, str, ARRAY_SIZE(str)); 172 ok(i == lstrlenW(className), 173 "GetClassName returned incorrect length\n"); 174 ok(!lstrcmpW(className,str), 175 "GetClassName returned incorrect name for this window's class\n"); 176 177 /* check GetClassInfo with our hInstance */ 178 if((test_atom = GetClassInfoW(hInstance, str, &wc))) 179 { 180 ok(test_atom == classatom, 181 "class atom did not match\n"); 182 ok(wc.cbClsExtra == cls.cbClsExtra, 183 "cbClsExtra did not match\n"); 184 ok(wc.cbWndExtra == cls.cbWndExtra, 185 "cbWndExtra did not match\n"); 186 ok(wc.hbrBackground == cls.hbrBackground, 187 "hbrBackground did not match\n"); 188 ok(wc.hCursor== cls.hCursor, 189 "hCursor did not match\n"); 190 ok(wc.hInstance== cls.hInstance, 191 "hInstance did not match\n"); 192 } 193 else 194 ok(FALSE,"GetClassInfo (hinstance) failed!\n"); 195 196 /* check GetClassInfo with zero hInstance */ 197 if(global) 198 { 199 if((test_atom = GetClassInfoW(0, str, &wc))) 200 { 201 ok(test_atom == classatom, 202 "class atom did not match %x != %x\n", test_atom, classatom); 203 ok(wc.cbClsExtra == cls.cbClsExtra, 204 "cbClsExtra did not match %x!=%x\n",wc.cbClsExtra,cls.cbClsExtra); 205 ok(wc.cbWndExtra == cls.cbWndExtra, 206 "cbWndExtra did not match %x!=%x\n",wc.cbWndExtra,cls.cbWndExtra); 207 ok(wc.hbrBackground == cls.hbrBackground, 208 "hbrBackground did not match %p!=%p\n",wc.hbrBackground,cls.hbrBackground); 209 ok(wc.hCursor== cls.hCursor, 210 "hCursor did not match %p!=%p\n",wc.hCursor,cls.hCursor); 211 ok(!wc.hInstance, 212 "hInstance not zero for global class %p\n",wc.hInstance); 213 } 214 else 215 ok(FALSE,"GetClassInfo (0) failed for global class!\n"); 216 } 217 else 218 { 219 ok(!GetClassInfoW(0, str, &wc), 220 "GetClassInfo (0) succeeded for local class!\n"); 221 } 222 223 ok(!UnregisterClassW(className, hInstance), 224 "Unregister class succeeded with window existing\n"); 225 226 ok(DestroyWindow(hTestWnd), 227 "DestroyWindow() failed!\n"); 228 229 ok(UnregisterClassW(className, hInstance), 230 "UnregisterClass() failed\n"); 231 232 ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) == 0, 233 "atom still found\n"); 234 return; 235 } 236 237 static void check_style( const char *name, int must_exist, UINT style, UINT ignore ) 238 { 239 WNDCLASSA wc; 240 241 if (GetClassInfoA( 0, name, &wc )) 242 { 243 ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n", 244 name, ~wc.style & style, wc.style, style ); 245 ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n", 246 name, wc.style & ~style, wc.style, style ); 247 } 248 else 249 ok( !must_exist, "System class %s does not exist\n", name ); 250 } 251 252 /* test styles of system classes */ 253 static void test_styles(void) 254 { 255 /* check style bits */ 256 check_style( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 257 check_style( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 258 check_style( "Edit", 1, CS_PARENTDC | CS_DBLCLKS, 0 ); 259 check_style( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS, CS_PARENTDC /*FIXME*/ ); 260 check_style( "MDIClient", 1, 0, 0 ); 261 check_style( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 ); 262 check_style( "Static", 1, CS_PARENTDC | CS_DBLCLKS, 0 ); 263 check_style( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); 264 check_style( "DDEMLEvent", 0, 0, 0 ); 265 check_style( "Message", 0, 0, 0 ); 266 check_style( "#32768", 1, CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, CS_DROPSHADOW ); /* menu */ 267 check_style( "#32769", 1, CS_DBLCLKS, 0 ); /* desktop */ 268 check_style( "#32770", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); /* dialog */ 269 todo_wine { check_style( "#32771", 1, CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW, 0 ); } /* task switch */ 270 check_style( "#32772", 1, 0, 0 ); /* icon title */ 271 } 272 273 static void check_class_(int line, HINSTANCE inst, const char *name, const char *menu_name) 274 { 275 WNDCLASSA wc; 276 UINT atom = GetClassInfoA(inst,name,&wc); 277 ok_(__FILE__,line)( atom, "Class %s %p not found\n", name, inst ); 278 if (atom) 279 { 280 if (wc.lpszMenuName && menu_name) 281 ok_(__FILE__,line)( !strcmp( menu_name, wc.lpszMenuName ), 282 "Wrong name %s/%s for class %s %p\n", 283 wc.lpszMenuName, menu_name, name, inst ); 284 else 285 ok_(__FILE__,line)( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n", 286 wc.lpszMenuName, menu_name, name, inst ); 287 } 288 } 289 #define check_class(inst,name,menu) check_class_(__LINE__,inst,name,menu) 290 291 static void check_instance_( int line, const char *name, HINSTANCE inst, 292 HINSTANCE info_inst, HINSTANCE gcl_inst ) 293 { 294 WNDCLASSA wc; 295 HWND hwnd; 296 297 ok_(__FILE__,line)( GetClassInfoA( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst ); 298 ok_(__FILE__,line)( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n", 299 wc.hInstance, info_inst, name ); 300 hwnd = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, inst, 0 ); 301 ok_(__FILE__,line)( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst ); 302 ok_(__FILE__,line)( (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ) == gcl_inst, 303 "Wrong GCL instance %p/%p for class %s\n", 304 (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ), gcl_inst, name ); 305 ok_(__FILE__,line)( (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ) == inst, 306 "Wrong GWL instance %p/%p for window %s\n", 307 (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ), inst, name ); 308 ok_(__FILE__,line)(!UnregisterClassA(name, inst), 309 "UnregisterClassA should fail while exists a class window\n"); 310 ok_(__FILE__,line)(GetLastError() == ERROR_CLASS_HAS_WINDOWS, 311 "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %d\n", GetLastError()); 312 DestroyWindow(hwnd); 313 } 314 #define check_instance(name,inst,info_inst,gcl_inst) check_instance_(__LINE__,name,inst,info_inst,gcl_inst) 315 316 struct class_info 317 { 318 const char *name; 319 HINSTANCE inst, info_inst, gcl_inst; 320 }; 321 322 static DWORD WINAPI thread_proc(void *param) 323 { 324 struct class_info *class_info = param; 325 326 check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst); 327 328 return 0; 329 } 330 331 static void check_thread_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst ) 332 { 333 HANDLE hThread; 334 DWORD tid; 335 struct class_info class_info; 336 337 class_info.name = name; 338 class_info.inst = inst; 339 class_info.info_inst = info_inst; 340 class_info.gcl_inst = gcl_inst; 341 342 hThread = CreateThread(NULL, 0, thread_proc, &class_info, 0, &tid); 343 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); 344 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); 345 CloseHandle(hThread); 346 } 347 348 /* test various instance parameters */ 349 static void test_instances(void) 350 { 351 WNDCLASSA cls, wc; 352 WNDCLASSEXA wcexA; 353 HWND hwnd, hwnd2; 354 const char *name = "__test__"; 355 HINSTANCE kernel32 = GetModuleHandleA("kernel32"); 356 HINSTANCE user32 = GetModuleHandleA("user32"); 357 HINSTANCE main_module = GetModuleHandleA(NULL); 358 HINSTANCE zero_instance = 0; 359 DWORD r; 360 char buffer[0x10]; 361 362 memset( &cls, 0, sizeof(cls) ); 363 cls.style = CS_HREDRAW | CS_VREDRAW; 364 cls.lpfnWndProc = ClassTest_WndProc; 365 cls.cbClsExtra = 0; 366 cls.cbWndExtra = 0; 367 cls.lpszClassName = name; 368 369 cls.lpszMenuName = "main_module"; 370 cls.hInstance = main_module; 371 372 ok( RegisterClassA( &cls ), "Failed to register local class for main module\n" ); 373 check_class( main_module, name, "main_module" ); 374 check_instance( name, main_module, main_module, main_module ); 375 check_thread_instance( name, main_module, main_module, main_module ); 376 377 cls.lpszMenuName = "kernel32"; 378 cls.hInstance = kernel32; 379 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 380 check_class( kernel32, name, "kernel32" ); 381 check_class( main_module, name, "main_module" ); 382 check_instance( name, kernel32, kernel32, kernel32 ); 383 check_thread_instance( name, kernel32, kernel32, kernel32 ); 384 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 385 386 ZeroMemory(&wcexA, sizeof(wcexA)); 387 wcexA.lpfnWndProc = DefWindowProcA; 388 wcexA.lpszClassName = "__classex_test__"; 389 SetLastError(0xdeadbeef); 390 wcexA.cbSize = sizeof(wcexA) - 1; 391 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 392 "Succeeded with invalid number of cbSize bytes\n"); 393 SetLastError(0xdeadbeef); 394 wcexA.cbSize = sizeof(wcexA) + 1; 395 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 396 "Succeeded with invalid number of cbSize bytes\n"); 397 SetLastError(0xdeadbeef); 398 wcexA.cbSize = sizeof(wcexA); 399 ok( RegisterClassExA( &wcexA ), "Failed with valid number of cbSize bytes\n"); 400 wcexA.cbSize = 0xdeadbeef; 401 ok( GetClassInfoExA(main_module, wcexA.lpszClassName, &wcexA), "GetClassInfoEx failed\n"); 402 ok( wcexA.cbSize == 0xdeadbeef, "GetClassInfoEx returned wrong cbSize value %d\n", wcexA.cbSize); 403 UnregisterClassA(wcexA.lpszClassName, main_module); 404 405 /* Bug 2631 - Supplying an invalid number of bytes fails */ 406 cls.cbClsExtra = 0; 407 cls.cbWndExtra = -1; 408 SetLastError(0xdeadbeef); 409 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 410 "Failed with invalid number of WndExtra bytes\n"); 411 412 cls.cbClsExtra = -1; 413 cls.cbWndExtra = 0; 414 SetLastError(0xdeadbeef); 415 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 416 "Failed with invalid number of ClsExtra bytes\n"); 417 418 cls.cbClsExtra = -1; 419 cls.cbWndExtra = -1; 420 SetLastError(0xdeadbeef); 421 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)), 422 "Failed with invalid number of ClsExtra and cbWndExtra bytes\n"); 423 424 cls.cbClsExtra = 0; 425 cls.cbWndExtra = 0; 426 SetLastError(0xdeadbeef); 427 428 /* setting global flag doesn't change status of class */ 429 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 430 ok( hwnd != 0, "CreateWindow failed error %u\n", GetLastError()); 431 SetClassLongA( hwnd, GCL_STYLE, CS_GLOBALCLASS ); 432 cls.lpszMenuName = "kernel32"; 433 cls.hInstance = kernel32; 434 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 435 check_class( kernel32, name, "kernel32" ); 436 check_class( main_module, name, "main_module" ); 437 check_instance( name, kernel32, kernel32, kernel32 ); 438 check_instance( name, main_module, main_module, main_module ); 439 check_thread_instance( name, kernel32, kernel32, kernel32 ); 440 check_thread_instance( name, main_module, main_module, main_module ); 441 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 442 443 /* changing the instance doesn't make it global */ 444 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0 ); 445 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 446 check_class( kernel32, name, "kernel32" ); 447 check_instance( name, kernel32, kernel32, kernel32 ); 448 check_thread_instance( name, kernel32, kernel32, kernel32 ); 449 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 450 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 451 452 /* GetClassInfo with instance 0 finds user32 instance */ 453 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)user32 ); 454 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 455 if (!GetClassInfoA( 0, name, &wc )) zero_instance = user32; /* instance 0 not supported on wow64 */ 456 else 457 { 458 check_instance( name, 0, 0, kernel32 ); 459 check_thread_instance( name, 0, 0, kernel32 ); 460 } 461 check_class( kernel32, name, "kernel32" ); 462 check_class( user32, name, "main_module" ); 463 check_class( zero_instance, name, "main_module" ); 464 check_instance( name, kernel32, kernel32, kernel32 ); 465 check_instance( name, user32, zero_instance, user32 ); 466 check_thread_instance( name, kernel32, kernel32, kernel32 ); 467 check_thread_instance( name, user32, zero_instance, user32 ); 468 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 469 470 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0x12345678 ); 471 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" ); 472 check_class( kernel32, name, "kernel32" ); 473 check_class( (HINSTANCE)0x12345678, name, "main_module" ); 474 check_instance( name, kernel32, kernel32, kernel32 ); 475 check_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 ); 476 check_thread_instance( name, kernel32, kernel32, kernel32 ); 477 check_thread_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 ); 478 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 479 480 /* creating a window with instance 0 uses the first class found */ 481 cls.hInstance = (HINSTANCE)0xdeadbeef; 482 cls.lpszMenuName = "deadbeef"; 483 cls.style = 3; 484 ok( RegisterClassA( &cls ), "Failed to register local class for deadbeef\n" ); 485 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 486 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0xdeadbeef, 487 "Didn't get deadbeef class for null instance\n" ); 488 DestroyWindow( hwnd2 ); 489 ok( UnregisterClassA( name, (HINSTANCE)0xdeadbeef ), "Unregister failed for deadbeef\n" ); 490 491 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 492 ok( (HINSTANCE)GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == kernel32, 493 "Didn't get kernel32 class for null instance\n" ); 494 DestroyWindow( hwnd2 ); 495 496 r = GetClassNameA( hwnd, buffer, 4 ); 497 ok( r == 3, "expected 3, got %d\n", r ); 498 ok( !strcmp( buffer, "__t"), "name wrong: %s\n", buffer ); 499 500 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" ); 501 502 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); 503 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0x12345678, 504 "Didn't get 12345678 class for null instance\n" ); 505 DestroyWindow( hwnd2 ); 506 507 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)main_module ); 508 DestroyWindow( hwnd ); 509 510 /* null handle means the same thing as main module */ 511 cls.lpszMenuName = "null"; 512 cls.hInstance = 0; 513 ok( !RegisterClassA( &cls ), "Succeeded registering local class for null instance\n" ); 514 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 515 ok( UnregisterClassA( name, main_module ), "Unregister failed for main module\n" ); 516 517 ok( RegisterClassA( &cls ), "Failed to register local class for null instance\n" ); 518 /* must be found with main module handle */ 519 check_class( main_module, name, "null" ); 520 check_instance( name, main_module, main_module, main_module ); 521 check_thread_instance( name, main_module, main_module, main_module ); 522 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" ); 523 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 524 ok( UnregisterClassA( name, 0 ), "Unregister failed for null instance\n" ); 525 526 /* registering for user32 always fails */ 527 cls.lpszMenuName = "user32"; 528 cls.hInstance = user32; 529 ok( !RegisterClassA( &cls ), "Succeeded registering local class for user32\n" ); 530 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() ); 531 cls.style |= CS_GLOBALCLASS; 532 ok( !RegisterClassA( &cls ), "Succeeded registering global class for user32\n" ); 533 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() ); 534 535 /* unregister is OK though */ 536 cls.hInstance = main_module; 537 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" ); 538 ok( UnregisterClassA( name, user32 ), "Unregister failed for user32\n" ); 539 540 /* instance doesn't matter for global class */ 541 cls.style |= CS_GLOBALCLASS; 542 cls.lpszMenuName = "main_module"; 543 cls.hInstance = main_module; 544 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" ); 545 cls.lpszMenuName = "kernel32"; 546 cls.hInstance = kernel32; 547 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" ); 548 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 549 /* even if global flag is cleared */ 550 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 551 SetClassLongA( hwnd, GCL_STYLE, 0 ); 552 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" ); 553 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 554 555 check_class( main_module, name, "main_module" ); 556 check_class( kernel32, name, "main_module" ); 557 check_class( 0, name, "main_module" ); 558 check_class( (HINSTANCE)0x12345678, name, "main_module" ); 559 check_instance( name, main_module, main_module, main_module ); 560 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module ); 561 check_thread_instance( name, main_module, main_module, main_module ); 562 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module ); 563 564 /* changing the instance for global class doesn't make much difference */ 565 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef ); 566 check_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef ); 567 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef ); 568 check_thread_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef ); 569 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef ); 570 571 DestroyWindow( hwnd ); 572 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" ); 573 ok( !UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister succeeded the second time\n" ); 574 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 575 576 cls.hInstance = (HINSTANCE)0x12345678; 577 ok( RegisterClassA( &cls ), "Failed to register global class for dummy instance\n" ); 578 check_instance( name, main_module, main_module, (HINSTANCE)0x12345678 ); 579 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 ); 580 check_thread_instance( name, main_module, main_module, (HINSTANCE)0x12345678 ); 581 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 ); 582 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" ); 583 584 /* check system classes */ 585 586 /* we cannot register a global class with the name of a system class */ 587 cls.style |= CS_GLOBALCLASS; 588 cls.lpszMenuName = "button_main_module"; 589 cls.lpszClassName = "BUTTON"; 590 cls.hInstance = main_module; 591 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for main module\n" ); 592 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 593 cls.hInstance = kernel32; 594 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for kernel32\n" ); 595 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() ); 596 597 /* local class is OK however */ 598 cls.style &= ~CS_GLOBALCLASS; 599 cls.lpszMenuName = "button_main_module"; 600 cls.hInstance = main_module; 601 ok( RegisterClassA( &cls ), "Failed to register local button class for main module\n" ); 602 check_class( main_module, "BUTTON", "button_main_module" ); 603 cls.lpszMenuName = "button_kernel32"; 604 cls.hInstance = kernel32; 605 ok( RegisterClassA( &cls ), "Failed to register local button class for kernel32\n" ); 606 check_class( kernel32, "BUTTON", "button_kernel32" ); 607 check_class( main_module, "BUTTON", "button_main_module" ); 608 ok( UnregisterClassA( "BUTTON", kernel32 ), "Unregister failed for kernel32 button\n" ); 609 ok( UnregisterClassA( "BUTTON", main_module ), "Unregister failed for main module button\n" ); 610 /* GetClassInfo sets instance to passed value for global classes */ 611 check_instance( "BUTTON", 0, 0, user32 ); 612 check_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 613 check_instance( "BUTTON", user32, zero_instance, user32 ); 614 check_thread_instance( "BUTTON", 0, 0, user32 ); 615 check_thread_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 616 check_thread_instance( "BUTTON", user32, zero_instance, user32 ); 617 618 /* we can unregister system classes */ 619 ok( GetClassInfoA( 0, "BUTTON", &wc ), "Button class not found with null instance\n" ); 620 ok( GetClassInfoA( kernel32, "BUTTON", &wc ), "Button class not found with kernel32\n" ); 621 ok( UnregisterClassA( "BUTTON", (HINSTANCE)0x12345678 ), "Failed to unregister button\n" ); 622 ok( !UnregisterClassA( "BUTTON", (HINSTANCE)0x87654321 ), "Unregistered button a second time\n" ); 623 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); 624 ok( !GetClassInfoA( 0, "BUTTON", &wc ), "Button still exists\n" ); 625 /* last error not set reliably */ 626 627 /* we can change the instance of a system class */ 628 check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 629 check_thread_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); 630 hwnd = CreateWindowExA( 0, "EDIT", "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); 631 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef ); 632 check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); 633 check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); 634 DestroyWindow(hwnd); 635 } 636 637 static void test_builtinproc(void) 638 { 639 /* Edit behaves differently */ 640 static const CHAR NORMAL_CLASSES[][10] = { 641 "Button", 642 "Static", 643 "ComboBox", 644 "ComboLBox", 645 "ListBox", 646 "ScrollBar", 647 "#32770", /* dialog */ 648 }; 649 static const char classA[] = "deftest"; 650 static const WCHAR classW[] = {'d','e','f','t','e','s','t',0}; 651 WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0}; /* a string that would be destroyed by a W->A->W conversion */ 652 WNDPROC pDefWindowProcA, pDefWindowProcW; 653 WNDPROC pNtdllDefWindowProcA, pNtdllDefWindowProcW; 654 WNDPROC oldproc; 655 WNDCLASSEXA cls; /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */ 656 WCHAR buf[128]; 657 ATOM atom; 658 HWND hwnd; 659 unsigned int i; 660 661 pDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA"); 662 pDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW"); 663 pNtdllDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_A"); 664 pNtdllDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_W"); 665 666 /* On Vista+, the user32.dll export DefWindowProcA/W is forwarded to */ 667 /* ntdll.NtdllDefWindowProc_A/W. However, the wndproc returned by */ 668 /* GetClassLong/GetWindowLong points to an unexported user32 function */ 669 if (pDefWindowProcA == pNtdllDefWindowProcA && 670 pDefWindowProcW == pNtdllDefWindowProcW) 671 skip("user32.DefWindowProcX forwarded to ntdll.NtdllDefWindowProc_X\n"); 672 else 673 { 674 for (i = 0; i < 4; i++) 675 { 676 ZeroMemory(&cls, sizeof(cls)); 677 cls.cbSize = sizeof(cls); 678 cls.hInstance = GetModuleHandleA(NULL); 679 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 680 if (i & 1) 681 cls.lpfnWndProc = pDefWindowProcA; 682 else 683 cls.lpfnWndProc = pDefWindowProcW; 684 685 if (i & 2) 686 { 687 cls.lpszClassName = classA; 688 atom = RegisterClassExA(&cls); 689 } 690 else 691 { 692 cls.lpszClassName = (LPCSTR)classW; 693 atom = RegisterClassExW((WNDCLASSEXW *)&cls); 694 } 695 ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError()); 696 697 hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL); 698 ok(hwnd != NULL, "Couldn't create window i=%d\n", i); 699 700 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", 701 (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA); 702 ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", 703 (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA); 704 705 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", 706 (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW); 707 ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", 708 (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW); 709 710 DestroyWindow(hwnd); 711 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 712 } 713 } 714 715 /* built-in winproc - window A/W type automatically detected */ 716 ZeroMemory(&cls, sizeof(cls)); 717 cls.cbSize = sizeof(cls); 718 cls.hInstance = GetModuleHandleA(NULL); 719 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 720 cls.lpszClassName = classA; 721 cls.lpfnWndProc = pDefWindowProcW; 722 atom = RegisterClassExA(&cls); 723 724 hwnd = CreateWindowExW(0, classW, unistring, WS_OVERLAPPEDWINDOW, 725 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleW(NULL), 0); 726 ok(IsWindowUnicode(hwnd) || 727 broken(!IsWindowUnicode(hwnd)) /* Windows 8 and 10 */, 728 "Windows should be Unicode\n"); 729 SendMessageW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf); 730 if (IsWindowUnicode(hwnd)) 731 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 732 else 733 ok(memcmp(buf, unistring, sizeof(unistring)) != 0, "WM_GETTEXT invalid return\n"); 734 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pDefWindowProcA); 735 ok(IsWindowUnicode(hwnd), "Windows should have remained Unicode\n"); 736 if (GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA) 737 { 738 /* DefWindowProc isn't magic on wow64 */ 739 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Ansi winproc is not a handle\n"); 740 } 741 else 742 { 743 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Invalid Unicode winproc\n"); 744 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Invalid Ansi winproc\n"); 745 } 746 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 747 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have switched window to ANSI\n"); 748 749 DestroyWindow(hwnd); 750 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 751 752 /* custom winproc - the same function can be used as both A and W*/ 753 ZeroMemory(&cls, sizeof(cls)); 754 cls.cbSize = sizeof(cls); 755 cls.hInstance = GetModuleHandleA(NULL); 756 cls.hbrBackground = GetStockObject (WHITE_BRUSH); 757 cls.lpszClassName = classA; 758 cls.lpfnWndProc = ClassTest_WndProc2; 759 atom = RegisterClassExA(&cls); 760 761 hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW, 762 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); 763 ok(IsWindowUnicode(hwnd) == FALSE, "Window should be ANSI\n"); 764 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 765 ok(IsWindowUnicode(hwnd), "SetWindowLongPtrW should have changed window to Unicode\n"); 766 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 767 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n"); 768 769 DestroyWindow(hwnd); 770 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); 771 772 /* For most of the builtin controls both GetWindowLongPtrA and W returns a pointer that is executed directly 773 * by CallWindowProcA/W */ 774 for (i = 0; i < ARRAY_SIZE(NORMAL_CLASSES); i++) 775 { 776 WNDPROC procA, procW; 777 hwnd = CreateWindowExA(0, NORMAL_CLASSES[i], classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, 778 NULL, NULL, NULL, 0); 779 ok(hwnd != NULL, "Couldn't create window of class %s\n", NORMAL_CLASSES[i]); 780 SetWindowTextA(hwnd, classA); /* ComboBox needs this */ 781 procA = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); 782 procW = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); 783 ok(!IS_WNDPROC_HANDLE(procA), "procA should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procA); 784 ok(!IS_WNDPROC_HANDLE(procW), "procW should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procW); 785 CallWindowProcA(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 786 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT A/A invalid return for class %s\n", NORMAL_CLASSES[i]); 787 CallWindowProcA(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 788 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT A/W invalid return for class %s\n", NORMAL_CLASSES[i]); 789 CallWindowProcW(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 790 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT W/A invalid return for class %s\n", NORMAL_CLASSES[i]); 791 CallWindowProcW(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); 792 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT W/W invalid return for class %s\n", NORMAL_CLASSES[i]); 793 794 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 795 ok(IS_WNDPROC_HANDLE(oldproc) == FALSE, "Class %s shouldn't return a handle\n", NORMAL_CLASSES[i]); 796 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 797 DestroyWindow(hwnd); 798 } 799 800 /* Edit controls are special - they return a wndproc handle when GetWindowLongPtr is called with a different A/W. 801 * On the other hand there is no W->A->W conversion so this control is treated specially. */ 802 hwnd = CreateWindowW(WC_EDITW, unistring, WS_OVERLAPPEDWINDOW, 803 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); 804 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */ 805 ok(IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a Unicode wndproc\n"); 806 ok(IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a ANSI wndproc\n"); 807 /* But GetWindowLongPtr returns only a handle for the ANSI one */ 808 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 809 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return a W wndproc handle\n"); 810 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 811 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 812 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 813 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 814 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 815 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 816 817 SetWindowTextW(hwnd, classW); 818 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 819 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 820 821 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc2); 822 /* SetWindowLongPtr returns a wndproc handle - like GetWindowLongPtr */ 823 ok(IS_WNDPROC_HANDLE(oldproc), "Edit control should return a wndproc handle\n"); 824 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n"); 825 SetWindowTextA(hwnd, classA); /* Windows resets the title to WideStringToMultiByte(unistring) */ 826 memset(buf, 0, sizeof(buf)); 827 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 828 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 829 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 830 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 831 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 832 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 833 834 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 835 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); 836 837 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 838 839 DestroyWindow(hwnd); 840 841 hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW, 842 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); 843 844 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */ 845 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)), "Edit control class should have a Unicode wndproc\n"); 846 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)), "Edit control class should have a ANSI wndproc\n"); 847 /* But GetWindowLongPtr returns only a handle for the Unicode one */ 848 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return an A wndproc handle\n"); 849 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 850 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 851 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 852 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 853 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 854 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 855 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 856 857 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 858 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); 859 860 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); 861 SetWindowTextW(hwnd, unistring); 862 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 863 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 864 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 865 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 866 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 867 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); 868 869 SetWindowTextW(hwnd, classW); 870 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); 871 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); 872 873 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); 874 875 DestroyWindow(hwnd); 876 } 877 878 879 static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 880 { 881 return DefDlgProcA(hWnd, uMsg, wParam, lParam); 882 } 883 884 static BOOL RegisterTestDialog(HINSTANCE hInstance) 885 { 886 WNDCLASSEXA wcx; 887 ATOM atom = 0; 888 889 ZeroMemory(&wcx, sizeof(WNDCLASSEXA)); 890 wcx.cbSize = sizeof(wcx); 891 wcx.lpfnWndProc = TestDlgProc; 892 wcx.cbClsExtra = 0; 893 wcx.cbWndExtra = DLGWINDOWEXTRA; 894 wcx.hInstance = hInstance; 895 wcx.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); 896 wcx.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); 897 wcx.hbrBackground = GetStockObject(WHITE_BRUSH); 898 wcx.lpszClassName = "TestDialog"; 899 wcx.lpszMenuName = "TestDialog"; 900 wcx.hIconSm = LoadImageA(hInstance, (LPCSTR)MAKEINTRESOURCE(5), IMAGE_ICON, 901 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 902 LR_DEFAULTCOLOR); 903 904 atom = RegisterClassExA(&wcx); 905 ok(atom != 0, "RegisterClassEx returned 0\n"); 906 907 return atom; 908 } 909 910 /* test registering a dialog box created by using the CLASS directive in a 911 resource file, then test creating the dialog using CreateDialogParam. */ 912 static void CreateDialogParamTest(HINSTANCE hInstance) 913 { 914 HWND hWndMain; 915 916 if (RegisterTestDialog(hInstance)) 917 { 918 hWndMain = CreateDialogParamA(hInstance, "CLASS_TEST_DIALOG", NULL, 0, 0); 919 ok(hWndMain != NULL, "CreateDialogParam returned NULL\n"); 920 ShowWindow(hWndMain, SW_SHOW); 921 DestroyWindow(hWndMain); 922 } 923 } 924 925 static const struct 926 { 927 const char name[9]; 928 int value; 929 int badvalue; 930 } extra_values[] = 931 { 932 {"#32770",30,30}, /* Dialog */ 933 #ifdef _WIN64 934 {"Edit",8,8}, 935 #else 936 {"Edit",6,8}, /* Windows XP 64-bit returns 8 also to 32-bit applications */ 937 #endif 938 }; 939 940 static void test_extra_values(void) 941 { 942 int i; 943 for(i = 0; i < ARRAY_SIZE(extra_values); i++) 944 { 945 WNDCLASSEXA wcx; 946 BOOL ret = GetClassInfoExA(NULL,extra_values[i].name,&wcx); 947 948 ok( ret, "GetClassInfo (0) failed for global class %s\n", extra_values[i].name); 949 if (!ret) continue; 950 ok(extra_values[i].value == wcx.cbWndExtra || broken(extra_values[i].badvalue == wcx.cbWndExtra), 951 "expected %d, got %d\n", extra_values[i].value, wcx.cbWndExtra); 952 } 953 } 954 955 static void test_GetClassInfo(void) 956 { 957 static const WCHAR staticW[] = {'s','t','a','t','i','c',0}; 958 WNDCLASSA wc; 959 WNDCLASSEXA wcx; 960 BOOL ret; 961 962 SetLastError(0xdeadbeef); 963 ret = GetClassInfoA(0, "static", &wc); 964 ok(ret, "GetClassInfoA() error %d\n", GetLastError()); 965 966 if (0) { /* crashes under XP */ 967 SetLastError(0xdeadbeef); 968 ret = GetClassInfoA(0, "static", NULL); 969 ok(ret, "GetClassInfoA() error %d\n", GetLastError()); 970 971 SetLastError(0xdeadbeef); 972 ret = GetClassInfoW(0, staticW, NULL); 973 ok(ret, "GetClassInfoW() error %d\n", GetLastError()); 974 } 975 976 wcx.cbSize = sizeof(wcx); 977 SetLastError(0xdeadbeef); 978 ret = GetClassInfoExA(0, "static", &wcx); 979 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 980 981 SetLastError(0xdeadbeef); 982 ret = GetClassInfoExA(0, "static", NULL); 983 ok(!ret, "GetClassInfoExA() should fail\n"); 984 ok(GetLastError() == ERROR_NOACCESS || 985 broken(GetLastError() == 0xdeadbeef), /* win9x */ 986 "expected ERROR_NOACCESS, got %d\n", GetLastError()); 987 988 SetLastError(0xdeadbeef); 989 ret = GetClassInfoExW(0, staticW, NULL); 990 ok(!ret, "GetClassInfoExW() should fail\n"); 991 ok(GetLastError() == ERROR_NOACCESS || 992 broken(GetLastError() == 0xdeadbeef) /* NT4 */ || 993 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ 994 "expected ERROR_NOACCESS, got %d\n", GetLastError()); 995 996 wcx.cbSize = 0; 997 wcx.lpfnWndProc = NULL; 998 SetLastError(0xdeadbeef); 999 ret = GetClassInfoExA(0, "static", &wcx); 1000 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 1001 ok(GetLastError() == 0xdeadbeef, "Unexpected error code %d\n", GetLastError()); 1002 ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize); 1003 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 1004 1005 wcx.cbSize = sizeof(wcx) - 1; 1006 wcx.lpfnWndProc = NULL; 1007 SetLastError(0xdeadbeef); 1008 ret = GetClassInfoExA(0, "static", &wcx); 1009 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 1010 ok(wcx.cbSize == sizeof(wcx) - 1, "expected sizeof(wcx)-1, got %u\n", wcx.cbSize); 1011 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 1012 1013 wcx.cbSize = sizeof(wcx) + 1; 1014 wcx.lpfnWndProc = NULL; 1015 SetLastError(0xdeadbeef); 1016 ret = GetClassInfoExA(0, "static", &wcx); 1017 ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); 1018 ok(wcx.cbSize == sizeof(wcx) + 1, "expected sizeof(wcx)+1, got %u\n", wcx.cbSize); 1019 ok(wcx.lpfnWndProc != NULL, "got null proc\n"); 1020 } 1021 1022 static void test_icons(void) 1023 { 1024 WNDCLASSEXW wcex, ret_wcex; 1025 WCHAR cls_name[] = {'I','c','o','n','T','e','s','t','C','l','a','s','s',0}; 1026 HWND hwnd; 1027 HINSTANCE hinst = GetModuleHandleW(0); 1028 HICON hsmicon, hsmallnew; 1029 ICONINFO icinf; 1030 1031 memset(&wcex, 0, sizeof wcex); 1032 wcex.cbSize = sizeof wcex; 1033 wcex.lpfnWndProc = ClassTest_WndProc; 1034 wcex.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); 1035 wcex.hInstance = hinst; 1036 wcex.lpszClassName = cls_name; 1037 ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n"); 1038 hwnd = CreateWindowExW(0, cls_name, NULL, WS_OVERLAPPEDWINDOW, 1039 0, 0, 0, 0, NULL, NULL, hinst, 0); 1040 ok(hwnd != NULL, "Window was not created\n"); 1041 1042 ok(GetClassInfoExW(hinst, cls_name, &ret_wcex), "Class info was not retrieved\n"); 1043 ok(wcex.hIcon == ret_wcex.hIcon, "Icons don't match\n"); 1044 ok(ret_wcex.hIconSm != NULL, "hIconSm should be non-zero handle\n"); 1045 1046 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 1047 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 1048 1049 ok(SendMessageA(hwnd, WM_GETICON, ICON_BIG, 0) == 0, 1050 "WM_GETICON with ICON_BIG should not return the class icon\n"); 1051 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL, 0) == 0, 1052 "WM_GETICON with ICON_SMALL should not return the class icon\n"); 1053 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL2, 0) == 0, 1054 "WM_GETICON with ICON_SMALL2 should not return the class icon\n"); 1055 1056 hsmallnew = CopyImage(wcex.hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), 1057 GetSystemMetrics(SM_CYSMICON), 0); 1058 ok(!SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hsmallnew), 1059 "Previous hIconSm should be zero\n"); 1060 ok(hsmallnew == (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM), 1061 "Should return explicitly assigned small icon\n"); 1062 ok(!GetIconInfo(hsmicon, &icinf), "Previous small icon should be destroyed\n"); 1063 1064 SetClassLongPtrW(hwnd, GCLP_HICONSM, 0); 1065 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 1066 ok( hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 1067 1068 SetClassLongPtrW(hwnd, GCLP_HICON, 0); 1069 ok(!GetClassLongPtrW(hwnd, GCLP_HICONSM), "GetClassLong should return zero handle\n"); 1070 1071 SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)LoadIconW(NULL, (LPCWSTR)IDI_QUESTION)); 1072 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM); 1073 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n"); 1074 UnregisterClassW(cls_name, hinst); 1075 ok(GetIconInfo(hsmicon, &icinf), "Icon should NOT be destroyed\n"); 1076 1077 DestroyIcon(hsmallnew); 1078 DestroyWindow(hwnd); 1079 } 1080 1081 static void create_manifest_file(const char *filename, const char *manifest) 1082 { 1083 WCHAR path[MAX_PATH]; 1084 HANDLE file; 1085 DWORD size; 1086 1087 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); 1088 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 1089 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); 1090 WriteFile(file, manifest, strlen(manifest), &size, NULL); 1091 CloseHandle(file); 1092 } 1093 1094 static HANDLE create_test_actctx(const char *file) 1095 { 1096 WCHAR path[MAX_PATH]; 1097 ACTCTXW actctx; 1098 HANDLE handle; 1099 1100 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH); 1101 memset(&actctx, 0, sizeof(ACTCTXW)); 1102 actctx.cbSize = sizeof(ACTCTXW); 1103 actctx.lpSource = path; 1104 1105 handle = CreateActCtxW(&actctx); 1106 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); 1107 1108 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize); 1109 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags); 1110 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource); 1111 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); 1112 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); 1113 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory); 1114 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName); 1115 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName); 1116 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule); 1117 1118 return handle; 1119 } 1120 static void test_comctl32_class( const char *name ) 1121 { 1122 WNDCLASSA wcA; 1123 WNDCLASSW wcW; 1124 BOOL ret; 1125 HMODULE module; 1126 WCHAR nameW[20]; 1127 HWND hwnd; 1128 1129 if (name[0] == '!') 1130 { 1131 char path[MAX_PATH]; 1132 ULONG_PTR cookie; 1133 HANDLE context; 1134 1135 name++; 1136 1137 GetTempPathA(ARRAY_SIZE(path), path); 1138 strcat(path, "comctl32_class.manifest"); 1139 1140 create_manifest_file(path, comctl32_manifest); 1141 context = create_test_actctx(path); 1142 ret = DeleteFileA(path); 1143 ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError()); 1144 1145 module = GetModuleHandleA( "comctl32" ); 1146 ok( !module, "comctl32 already loaded\n" ); 1147 1148 ret = ActivateActCtx(context, &cookie); 1149 ok(ret, "Failed to activate context.\n"); 1150 1151 /* Some systems load modules during context activation. In this case skip the rest of the test. */ 1152 module = GetModuleHandleA( "comctl32" ); 1153 ok( !module || broken(module != NULL) /* Vista/Win7 */, "comctl32 already loaded\n" ); 1154 if (module) 1155 { 1156 win_skip("Module loaded during context activation. Skipping tests.\n"); 1157 goto skiptest; 1158 } 1159 1160 ret = GetClassInfoA( 0, name, &wcA ); 1161 ok( ret || broken(!ret) /* WinXP */, "GetClassInfoA failed for %s\n", name ); 1162 if (!ret) 1163 goto skiptest; 1164 1165 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW)); 1166 ret = GetClassInfoW( 0, nameW, &wcW ); 1167 ok( ret, "GetClassInfoW failed for %s\n", name ); 1168 module = GetModuleHandleA( "comctl32" ); 1169 ok( module != 0, "comctl32 not loaded\n" ); 1170 FreeLibrary( module ); 1171 module = GetModuleHandleA( "comctl32" ); 1172 ok( !module || broken(module != NULL) /* Vista */, "comctl32 still loaded\n" ); 1173 hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); 1174 ok( hwnd != 0, "failed to create window for %s\n", name ); 1175 module = GetModuleHandleA( "comctl32" ); 1176 ok( module != 0, "comctl32 not loaded\n" ); 1177 DestroyWindow( hwnd ); 1178 1179 skiptest: 1180 ret = DeactivateActCtx(0, cookie); 1181 ok(ret, "Failed to deactivate context.\n"); 1182 ReleaseActCtx(context); 1183 } 1184 else 1185 { 1186 module = GetModuleHandleA( "comctl32" ); 1187 ok( !module, "comctl32 already loaded\n" ); 1188 ret = GetClassInfoA( 0, name, &wcA ); 1189 ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name ); 1190 if (!ret) return; 1191 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW)); 1192 ret = GetClassInfoW( 0, nameW, &wcW ); 1193 ok( ret, "GetClassInfoW failed for %s\n", name ); 1194 module = GetModuleHandleA( "comctl32" ); 1195 ok( module != 0, "comctl32 not loaded\n" ); 1196 FreeLibrary( module ); 1197 module = GetModuleHandleA( "comctl32" ); 1198 ok( !module, "comctl32 still loaded\n" ); 1199 hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); 1200 ok( hwnd != 0, "failed to create window for %s\n", name ); 1201 module = GetModuleHandleA( "comctl32" ); 1202 ok( module != 0, "comctl32 not loaded\n" ); 1203 DestroyWindow( hwnd ); 1204 } 1205 } 1206 1207 /* verify that comctl32 classes are automatically loaded by user32 */ 1208 static void test_comctl32_classes(void) 1209 { 1210 char path_name[MAX_PATH]; 1211 PROCESS_INFORMATION info; 1212 STARTUPINFOA startup; 1213 char **argv; 1214 int i; 1215 1216 static const char *classes[] = 1217 { 1218 ANIMATE_CLASSA, 1219 WC_COMBOBOXEXA, 1220 DATETIMEPICK_CLASSA, 1221 WC_HEADERA, 1222 HOTKEY_CLASSA, 1223 WC_IPADDRESSA, 1224 WC_LISTVIEWA, 1225 MONTHCAL_CLASSA, 1226 WC_NATIVEFONTCTLA, 1227 WC_PAGESCROLLERA, 1228 PROGRESS_CLASSA, 1229 REBARCLASSNAMEA, 1230 STATUSCLASSNAMEA, 1231 "SysLink", 1232 WC_TABCONTROLA, 1233 TOOLBARCLASSNAMEA, 1234 TOOLTIPS_CLASSA, 1235 TRACKBAR_CLASSA, 1236 WC_TREEVIEWA, 1237 UPDOWN_CLASSA, 1238 "!Button", 1239 "!Edit", 1240 "!Static", 1241 "!Listbox", 1242 "!ComboBox", 1243 "!ComboLBox", 1244 }; 1245 1246 winetest_get_mainargs( &argv ); 1247 for (i = 0; i < ARRAY_SIZE(classes); i++) 1248 { 1249 memset( &startup, 0, sizeof(startup) ); 1250 startup.cb = sizeof( startup ); 1251 sprintf( path_name, "%s class %s", argv[0], classes[i] ); 1252 ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ), 1253 "CreateProcess failed.\n" ); 1254 winetest_wait_child_process( info.hProcess ); 1255 CloseHandle( info.hProcess ); 1256 CloseHandle( info.hThread ); 1257 } 1258 } 1259 1260 static void test_IME(void) 1261 { 1262 static const WCHAR ime_classW[] = {'I','M','E',0}; 1263 1264 char module_name[MAX_PATH], *ptr; 1265 MEMORY_BASIC_INFORMATION mbi; 1266 WNDCLASSW wnd_classw; 1267 WNDCLASSA wnd_class; 1268 SIZE_T size; 1269 BOOL ret; 1270 1271 if (!GetProcAddress(GetModuleHandleA("user32.dll"), "BroadcastSystemMessageExA")) 1272 { 1273 win_skip("BroadcastSystemMessageExA not available, skipping IME class test\n"); 1274 return; 1275 } 1276 1277 ok(GetModuleHandleA("imm32") != 0, "imm32.dll is not loaded\n"); 1278 1279 ret = GetClassInfoA(NULL, "IME", &wnd_class); 1280 ok(ret, "GetClassInfo failed: %d\n", GetLastError()); 1281 1282 size = VirtualQuery(wnd_class.lpfnWndProc, &mbi, sizeof(mbi)); 1283 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); 1284 if (size == sizeof(mbi)) { 1285 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); 1286 ok(size, "GetModuleFileName failed\n"); 1287 for (ptr = module_name+size-1; ptr > module_name; ptr--) 1288 if (*ptr == '\\' || *ptr == '/') break; 1289 if (*ptr == '\\' || *ptr=='/') ptr++; 1290 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr); 1291 } 1292 1293 ret = GetClassInfoW(NULL, ime_classW, &wnd_classw); 1294 ok(ret, "GetClassInfo failed: %d\n", GetLastError()); 1295 1296 size = VirtualQuery(wnd_classw.lpfnWndProc, &mbi, sizeof(mbi)); 1297 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); 1298 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); 1299 ok(size, "GetModuleFileName failed\n"); 1300 for (ptr = module_name+size-1; ptr > module_name; ptr--) 1301 if (*ptr == '\\' || *ptr == '/') break; 1302 if (*ptr == '\\' || *ptr=='/') ptr++; 1303 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr); 1304 } 1305 1306 static void test_actctx_classes(void) 1307 { 1308 static const char main_manifest[] = 1309 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">" 1310 "<assemblyIdentity version=\"4.3.2.1\" name=\"Wine.WndClass.Test\" type=\"win32\" />" 1311 "<file name=\"file.exe\">" 1312 "<windowClass>MyTestClass</windowClass>" 1313 "</file>" 1314 "</assembly>"; 1315 static const char *testclass = "MyTestClass"; 1316 WNDCLASSA wc; 1317 ULONG_PTR cookie; 1318 HANDLE context; 1319 BOOL ret; 1320 ATOM class; 1321 HINSTANCE hinst; 1322 char buff[64]; 1323 HWND hwnd, hwnd2; 1324 char path[MAX_PATH]; 1325 1326 GetTempPathA(ARRAY_SIZE(path), path); 1327 strcat(path, "actctx_classes.manifest"); 1328 1329 create_manifest_file(path, main_manifest); 1330 context = create_test_actctx(path); 1331 ret = DeleteFileA(path); 1332 ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError()); 1333 1334 ret = ActivateActCtx(context, &cookie); 1335 ok(ret, "Failed to activate context.\n"); 1336 1337 memset(&wc, 0, sizeof(wc)); 1338 wc.lpfnWndProc = ClassTest_WndProc; 1339 wc.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); 1340 wc.lpszClassName = testclass; 1341 1342 hinst = GetModuleHandleW(0); 1343 1344 ret = GetClassInfoA(hinst, testclass, &wc); 1345 ok(!ret, "Expected failure.\n"); 1346 1347 class = RegisterClassA(&wc); 1348 ok(class != 0, "Failed to register class.\n"); 1349 1350 /* Class info is available by versioned and regular names. */ 1351 ret = GetClassInfoA(hinst, testclass, &wc); 1352 ok(ret, "Failed to get class info.\n"); 1353 1354 hwnd = CreateWindowExA(0, testclass, "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0); 1355 ok(hwnd != NULL, "Failed to create a window.\n"); 1356 1357 hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL); 1358 ok(hwnd2 == hwnd, "Failed to find test window.\n"); 1359 1360 hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL); 1361 ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2); 1362 1363 ret = GetClassNameA(hwnd, buff, sizeof(buff)); 1364 ok(ret, "Failed to get class name.\n"); 1365 ok(!strcmp(buff, testclass), "Unexpected class name.\n"); 1366 1367 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc); 1368 ok(ret, "Failed to get class info.\n"); 1369 1370 ret = UnregisterClassA(testclass, hinst); 1371 ok(!ret, "Failed to unregister class.\n"); 1372 1373 ret = DeactivateActCtx(0, cookie); 1374 ok(ret, "Failed to deactivate context.\n"); 1375 1376 ret = GetClassInfoA(hinst, testclass, &wc); 1377 ok(!ret, "Unexpected ret val %d.\n", ret); 1378 1379 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc); 1380 ok(ret, "Failed to get class info.\n"); 1381 1382 ret = GetClassNameA(hwnd, buff, sizeof(buff)); 1383 ok(ret, "Failed to get class name.\n"); 1384 ok(!strcmp(buff, testclass), "Unexpected class name.\n"); 1385 1386 DestroyWindow(hwnd); 1387 1388 hwnd = CreateWindowExA(0, "4.3.2.1!MyTestClass", "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0); 1389 ok(hwnd != NULL, "Failed to create a window.\n"); 1390 1391 hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL); 1392 ok(hwnd2 == hwnd, "Failed to find test window.\n"); 1393 1394 hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL); 1395 ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2); 1396 1397 DestroyWindow(hwnd); 1398 1399 ret = UnregisterClassA("MyTestClass", hinst); 1400 ok(!ret, "Unexpected ret value %d.\n", ret); 1401 1402 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst); 1403 ok(ret, "Failed to unregister class.\n"); 1404 1405 /* Register versioned class without active context. */ 1406 wc.lpszClassName = "4.3.2.1!MyTestClass"; 1407 class = RegisterClassA(&wc); 1408 ok(class != 0, "Failed to register class.\n"); 1409 1410 ret = ActivateActCtx(context, &cookie); 1411 ok(ret, "Failed to activate context.\n"); 1412 1413 wc.lpszClassName = "MyTestClass"; 1414 class = RegisterClassA(&wc); 1415 ok(class == 0, "Expected failure.\n"); 1416 1417 ret = DeactivateActCtx(0, cookie); 1418 ok(ret, "Failed to deactivate context.\n"); 1419 1420 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst); 1421 ok(ret, "Failed to unregister class.\n"); 1422 1423 /* Only versioned name is registered. */ 1424 ret = ActivateActCtx(context, &cookie); 1425 ok(ret, "Failed to activate context.\n"); 1426 1427 wc.lpszClassName = "MyTestClass"; 1428 class = RegisterClassA(&wc); 1429 ok(class != 0, "Failed to register class\n"); 1430 1431 ret = DeactivateActCtx(0, cookie); 1432 ok(ret, "Failed to deactivate context.\n"); 1433 1434 ret = GetClassInfoA(hinst, "MyTestClass", &wc); 1435 ok(!ret, "Expected failure.\n"); 1436 1437 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc); 1438 ok(ret, "Failed to get class info.\n"); 1439 1440 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst); 1441 ok(ret, "Failed to unregister class.\n"); 1442 1443 /* Register regular name first, it's not considered when versioned name is registered. */ 1444 wc.lpszClassName = "MyTestClass"; 1445 class = RegisterClassA(&wc); 1446 ok(class != 0, "Failed to register class.\n"); 1447 1448 ret = ActivateActCtx(context, &cookie); 1449 ok(ret, "Failed to activate context.\n"); 1450 1451 wc.lpszClassName = "MyTestClass"; 1452 class = RegisterClassA(&wc); 1453 ok(class != 0, "Failed to register class.\n"); 1454 1455 ret = DeactivateActCtx(0, cookie); 1456 ok(ret, "Failed to deactivate context.\n"); 1457 1458 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst); 1459 ok(ret, "Failed to unregister class.\n"); 1460 1461 ret = UnregisterClassA("MyTestClass", hinst); 1462 ok(ret, "Failed to unregister class.\n"); 1463 1464 ReleaseActCtx(context); 1465 } 1466 1467 START_TEST(class) 1468 { 1469 char **argv; 1470 HANDLE hInstance = GetModuleHandleA( NULL ); 1471 int argc = winetest_get_mainargs( &argv ); 1472 1473 if (argc >= 3) 1474 { 1475 test_comctl32_class( argv[2] ); 1476 return; 1477 } 1478 1479 test_IME(); 1480 test_GetClassInfo(); 1481 test_extra_values(); 1482 1483 if (!GetModuleHandleW(0)) 1484 { 1485 trace("Class test is incompatible with Win9x implementation, skipping\n"); 1486 return; 1487 } 1488 1489 ClassTest(hInstance,FALSE); 1490 ClassTest(hInstance,TRUE); 1491 CreateDialogParamTest(hInstance); 1492 test_styles(); 1493 test_builtinproc(); 1494 test_icons(); 1495 test_comctl32_classes(); 1496 test_actctx_classes(); 1497 1498 /* this test unregisters the Button class so it should be executed at the end */ 1499 test_instances(); 1500 } 1501