user32: Ignore low instance word in find_class.
[wine.git] / dlls / user32 / tests / class.c
blobc13893ae9d326b6ad9178d1cb8b50c7844678bbc
1 /* Unit test suite for window classes.
3 * Copyright 2002 Mike McCormack
4 * Copyright 2003 Alexandre Julliard
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.
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.
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
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <stdio.h>
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"
34 #define NUMCLASSWORDS 4
36 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
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
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";
74 static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
76 if (msg == WM_NCCREATE) return 1;
77 return DefWindowProcW (hWnd, msg, wParam, lParam);
80 static LRESULT WINAPI ClassTest_WndProc2 (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
82 if (msg == WM_NCCREATE) return 1;
83 return DefWindowProcA (hWnd, msg, wParam, lParam);
86 /***********************************************************************
88 static void ClassTest(HINSTANCE hInstance, BOOL global)
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 WNDCLASSW info;
94 ATOM test_atom;
95 HWND hTestWnd;
96 LONG i;
97 WCHAR str[20];
98 ATOM classatom;
99 HINSTANCE hInstance2;
100 BOOL ret;
102 cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0);
103 cls.lpfnWndProc = ClassTest_WndProc;
104 cls.cbClsExtra = NUMCLASSWORDS*sizeof(DWORD);
105 cls.cbWndExtra = 12;
106 cls.hInstance = hInstance;
107 cls.hIcon = LoadIconW (0, (LPWSTR)IDI_APPLICATION);
108 cls.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
109 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
110 cls.lpszMenuName = 0;
111 cls.lpszClassName = className;
113 classatom=RegisterClassW(&cls);
114 if (!classatom && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
115 return;
116 ok(classatom, "failed to register class\n");
118 ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) != 0, "atom not found\n");
120 ok(!RegisterClassW (&cls),
121 "RegisterClass of the same class should fail for the second time\n");
123 /* Setup windows */
124 hInstance2 = (HINSTANCE)(((ULONG_PTR)hInstance & ~0xffff) | 0xdead);
126 hTestWnd = CreateWindowW (className, winName,
127 WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL,
128 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0,
129 0, hInstance2, 0);
130 ok(hTestWnd != 0, "Failed to create window for hInstance %p\n", hInstance2);
132 ok((HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE) == hInstance,
133 "Wrong GCL instance %p != %p\n",
134 (HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE), hInstance);
135 ok((HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE) == hInstance2,
136 "Wrong GWL instance %p != %p\n",
137 (HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE), hInstance2);
139 DestroyWindow(hTestWnd);
141 ret = GetClassInfoW(hInstance2, className, &info);
142 ok(ret, "GetClassInfoW failed: %u\n", GetLastError());
144 hTestWnd = CreateWindowW (className, winName,
145 WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL,
146 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0,
147 0, hInstance, 0);
149 ok(hTestWnd!=0, "Failed to create window\n");
151 ok((HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE) == hInstance,
152 "Wrong GCL instance %p/%p\n",
153 (HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE), hInstance);
154 ok((HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE) == hInstance,
155 "Wrong GWL instance %p/%p\n",
156 (HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE), hInstance);
159 /* test initial values of valid classwords */
160 for(i=0; i<NUMCLASSWORDS; i++)
162 SetLastError(0);
163 ok(!GetClassLongW(hTestWnd,i*sizeof (DWORD)),
164 "GetClassLongW initial value nonzero!\n");
165 ok(!GetLastError(),
166 "GetClassLongW failed!\n");
169 if (0)
172 * GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD))
173 * does not fail on Win 98, though MSDN says it should
175 SetLastError(0);
176 GetClassLongW(hTestWnd, NUMCLASSWORDS*sizeof(DWORD));
177 ok(GetLastError(),
178 "GetClassLongW() with invalid offset did not fail\n");
181 /* set values of valid class words */
182 for(i=0; i<NUMCLASSWORDS; i++)
184 SetLastError(0);
185 ok(!SetClassLongW(hTestWnd,i*sizeof(DWORD),i+1),
186 "GetClassLongW(%d) initial value nonzero!\n",i);
187 ok(!GetLastError(),
188 "SetClassLongW(%d) failed!\n",i);
191 /* test values of valid classwords that we set */
192 for(i=0; i<NUMCLASSWORDS; i++)
194 SetLastError(0);
195 ok( (i+1) == GetClassLongW(hTestWnd,i*sizeof (DWORD)),
196 "GetClassLongW value doesn't match what was set!\n");
197 ok(!GetLastError(),
198 "GetClassLongW failed!\n");
201 /* check GetClassName */
202 i = GetClassNameW(hTestWnd, str, ARRAY_SIZE(str));
203 ok(i == lstrlenW(className),
204 "GetClassName returned incorrect length\n");
205 ok(!lstrcmpW(className,str),
206 "GetClassName returned incorrect name for this window's class\n");
208 /* check GetClassInfo with our hInstance */
209 if((test_atom = GetClassInfoW(hInstance, str, &wc)))
211 ok(test_atom == classatom,
212 "class atom did not match\n");
213 ok(wc.cbClsExtra == cls.cbClsExtra,
214 "cbClsExtra did not match\n");
215 ok(wc.cbWndExtra == cls.cbWndExtra,
216 "cbWndExtra did not match\n");
217 ok(wc.hbrBackground == cls.hbrBackground,
218 "hbrBackground did not match\n");
219 ok(wc.hCursor== cls.hCursor,
220 "hCursor did not match\n");
221 ok(wc.hInstance== cls.hInstance,
222 "hInstance did not match\n");
224 else
225 ok(FALSE,"GetClassInfo (hinstance) failed!\n");
227 /* check GetClassInfo with zero hInstance */
228 if(global)
230 if((test_atom = GetClassInfoW(0, str, &wc)))
232 ok(test_atom == classatom,
233 "class atom did not match %x != %x\n", test_atom, classatom);
234 ok(wc.cbClsExtra == cls.cbClsExtra,
235 "cbClsExtra did not match %x!=%x\n",wc.cbClsExtra,cls.cbClsExtra);
236 ok(wc.cbWndExtra == cls.cbWndExtra,
237 "cbWndExtra did not match %x!=%x\n",wc.cbWndExtra,cls.cbWndExtra);
238 ok(wc.hbrBackground == cls.hbrBackground,
239 "hbrBackground did not match %p!=%p\n",wc.hbrBackground,cls.hbrBackground);
240 ok(wc.hCursor== cls.hCursor,
241 "hCursor did not match %p!=%p\n",wc.hCursor,cls.hCursor);
242 ok(!wc.hInstance,
243 "hInstance not zero for global class %p\n",wc.hInstance);
245 else
246 ok(FALSE,"GetClassInfo (0) failed for global class!\n");
248 else
250 ok(!GetClassInfoW(0, str, &wc),
251 "GetClassInfo (0) succeeded for local class!\n");
254 ok(!UnregisterClassW(className, hInstance),
255 "Unregister class succeeded with window existing\n");
257 ok(DestroyWindow(hTestWnd),
258 "DestroyWindow() failed!\n");
260 ok(UnregisterClassW(className, hInstance),
261 "UnregisterClass() failed\n");
263 ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) == 0,
264 "atom still found\n");
265 return;
268 static void check_style( const char *name, int must_exist, UINT style, UINT ignore )
270 WNDCLASSA wc;
272 if (GetClassInfoA( 0, name, &wc ))
274 ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n",
275 name, ~wc.style & style, wc.style, style );
276 ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n",
277 name, wc.style & ~style, wc.style, style );
279 else
280 ok( !must_exist, "System class %s does not exist\n", name );
283 /* test styles of system classes */
284 static void test_styles(void)
286 /* check style bits */
287 check_style( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
288 check_style( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
289 check_style( "Edit", 1, CS_PARENTDC | CS_DBLCLKS, 0 );
290 check_style( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS, CS_PARENTDC /*FIXME*/ );
291 check_style( "MDIClient", 1, 0, 0 );
292 check_style( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0 );
293 check_style( "Static", 1, CS_PARENTDC | CS_DBLCLKS, 0 );
294 check_style( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS, 0 );
295 check_style( "DDEMLEvent", 0, 0, 0 );
296 check_style( "Message", 0, 0, 0 );
297 check_style( "#32768", 1, CS_DROPSHADOW | CS_SAVEBITS | CS_DBLCLKS, CS_DROPSHADOW ); /* menu */
298 check_style( "#32769", 1, CS_DBLCLKS, 0 ); /* desktop */
299 check_style( "#32770", 1, CS_SAVEBITS | CS_DBLCLKS, 0 ); /* dialog */
300 todo_wine { check_style( "#32771", 1, CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW, 0 ); } /* task switch */
301 check_style( "#32772", 1, 0, 0 ); /* icon title */
304 static void check_class_(int line, HINSTANCE inst, const char *name, const char *menu_name)
306 WNDCLASSA wc;
307 UINT atom = GetClassInfoA(inst,name,&wc);
308 ok_(__FILE__,line)( atom, "Class %s %p not found\n", name, inst );
309 if (atom)
311 if (wc.lpszMenuName && menu_name)
312 ok_(__FILE__,line)( !strcmp( menu_name, wc.lpszMenuName ),
313 "Wrong name %s/%s for class %s %p\n",
314 wc.lpszMenuName, menu_name, name, inst );
315 else
316 ok_(__FILE__,line)( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n",
317 wc.lpszMenuName, menu_name, name, inst );
320 #define check_class(inst,name,menu) check_class_(__LINE__,inst,name,menu)
322 static void check_instance_( int line, const char *name, HINSTANCE inst,
323 HINSTANCE info_inst, HINSTANCE gcl_inst )
325 WNDCLASSA wc;
326 HWND hwnd;
328 ok_(__FILE__,line)( GetClassInfoA( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst );
329 ok_(__FILE__,line)( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n",
330 wc.hInstance, info_inst, name );
331 hwnd = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, inst, 0 );
332 ok_(__FILE__,line)( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst );
333 ok_(__FILE__,line)( (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ) == gcl_inst,
334 "Wrong GCL instance %p/%p for class %s\n",
335 (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ), gcl_inst, name );
336 ok_(__FILE__,line)( (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ) == inst,
337 "Wrong GWL instance %p/%p for window %s\n",
338 (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ), inst, name );
339 ok_(__FILE__,line)(!UnregisterClassA(name, inst),
340 "UnregisterClassA should fail while exists a class window\n");
341 ok_(__FILE__,line)(GetLastError() == ERROR_CLASS_HAS_WINDOWS,
342 "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %d\n", GetLastError());
343 DestroyWindow(hwnd);
345 #define check_instance(name,inst,info_inst,gcl_inst) check_instance_(__LINE__,name,inst,info_inst,gcl_inst)
347 struct class_info
349 const char *name;
350 HINSTANCE inst, info_inst, gcl_inst;
353 static DWORD WINAPI thread_proc(void *param)
355 struct class_info *class_info = param;
357 check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst);
359 return 0;
362 static void check_thread_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst )
364 HANDLE hThread;
365 DWORD tid;
366 struct class_info class_info;
368 class_info.name = name;
369 class_info.inst = inst;
370 class_info.info_inst = info_inst;
371 class_info.gcl_inst = gcl_inst;
373 hThread = CreateThread(NULL, 0, thread_proc, &class_info, 0, &tid);
374 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
375 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
376 CloseHandle(hThread);
379 /* test various instance parameters */
380 static void test_instances(void)
382 WNDCLASSA cls, wc;
383 WNDCLASSEXA wcexA;
384 HWND hwnd, hwnd2;
385 const char *name = "__test__";
386 HINSTANCE kernel32 = GetModuleHandleA("kernel32");
387 HINSTANCE user32 = GetModuleHandleA("user32");
388 HINSTANCE main_module = GetModuleHandleA(NULL);
389 HINSTANCE zero_instance = 0;
390 DWORD r;
391 char buffer[0x10];
393 memset( &cls, 0, sizeof(cls) );
394 cls.style = CS_HREDRAW | CS_VREDRAW;
395 cls.lpfnWndProc = ClassTest_WndProc;
396 cls.cbClsExtra = 0;
397 cls.cbWndExtra = 0;
398 cls.lpszClassName = name;
400 cls.lpszMenuName = "main_module";
401 cls.hInstance = main_module;
403 ok( RegisterClassA( &cls ), "Failed to register local class for main module\n" );
404 check_class( main_module, name, "main_module" );
405 check_instance( name, main_module, main_module, main_module );
406 check_thread_instance( name, main_module, main_module, main_module );
408 cls.lpszMenuName = "kernel32";
409 cls.hInstance = kernel32;
410 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
411 check_class( kernel32, name, "kernel32" );
412 check_class( main_module, name, "main_module" );
413 check_instance( name, kernel32, kernel32, kernel32 );
414 check_thread_instance( name, kernel32, kernel32, kernel32 );
415 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
417 ZeroMemory(&wcexA, sizeof(wcexA));
418 wcexA.lpfnWndProc = DefWindowProcA;
419 wcexA.lpszClassName = "__classex_test__";
420 SetLastError(0xdeadbeef);
421 wcexA.cbSize = sizeof(wcexA) - 1;
422 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
423 "Succeeded with invalid number of cbSize bytes\n");
424 SetLastError(0xdeadbeef);
425 wcexA.cbSize = sizeof(wcexA) + 1;
426 ok( ((RegisterClassExA( &wcexA ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
427 "Succeeded with invalid number of cbSize bytes\n");
428 SetLastError(0xdeadbeef);
429 wcexA.cbSize = sizeof(wcexA);
430 ok( RegisterClassExA( &wcexA ), "Failed with valid number of cbSize bytes\n");
431 wcexA.cbSize = 0xdeadbeef;
432 ok( GetClassInfoExA(main_module, wcexA.lpszClassName, &wcexA), "GetClassInfoEx failed\n");
433 ok( wcexA.cbSize == 0xdeadbeef, "GetClassInfoEx returned wrong cbSize value %d\n", wcexA.cbSize);
434 UnregisterClassA(wcexA.lpszClassName, main_module);
436 /* Bug 2631 - Supplying an invalid number of bytes fails */
437 cls.cbClsExtra = 0;
438 cls.cbWndExtra = -1;
439 SetLastError(0xdeadbeef);
440 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
441 "Failed with invalid number of WndExtra bytes\n");
443 cls.cbClsExtra = -1;
444 cls.cbWndExtra = 0;
445 SetLastError(0xdeadbeef);
446 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
447 "Failed with invalid number of ClsExtra bytes\n");
449 cls.cbClsExtra = -1;
450 cls.cbWndExtra = -1;
451 SetLastError(0xdeadbeef);
452 ok( ((RegisterClassA( &cls ) == 0) && (GetLastError() == ERROR_INVALID_PARAMETER)),
453 "Failed with invalid number of ClsExtra and cbWndExtra bytes\n");
455 cls.cbClsExtra = 0;
456 cls.cbWndExtra = 0;
457 SetLastError(0xdeadbeef);
459 /* setting global flag doesn't change status of class */
460 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
461 ok( hwnd != 0, "CreateWindow failed error %u\n", GetLastError());
462 SetClassLongA( hwnd, GCL_STYLE, CS_GLOBALCLASS );
463 cls.lpszMenuName = "kernel32";
464 cls.hInstance = kernel32;
465 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
466 check_class( kernel32, name, "kernel32" );
467 check_class( main_module, name, "main_module" );
468 check_instance( name, kernel32, kernel32, kernel32 );
469 check_instance( name, main_module, main_module, main_module );
470 check_thread_instance( name, kernel32, kernel32, kernel32 );
471 check_thread_instance( name, main_module, main_module, main_module );
472 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
474 /* changing the instance doesn't make it global */
475 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0 );
476 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
477 check_class( kernel32, name, "kernel32" );
478 check_instance( name, kernel32, kernel32, kernel32 );
479 check_thread_instance( name, kernel32, kernel32, kernel32 );
480 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" );
481 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
483 /* GetClassInfo with instance 0 finds user32 instance */
484 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)user32 );
485 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
486 if (!GetClassInfoA( 0, name, &wc )) zero_instance = user32; /* instance 0 not supported on wow64 */
487 else
489 check_instance( name, 0, 0, kernel32 );
490 check_thread_instance( name, 0, 0, kernel32 );
492 check_class( kernel32, name, "kernel32" );
493 check_class( user32, name, "main_module" );
494 check_class( zero_instance, name, "main_module" );
495 check_instance( name, kernel32, kernel32, kernel32 );
496 check_instance( name, user32, zero_instance, user32 );
497 check_thread_instance( name, kernel32, kernel32, kernel32 );
498 check_thread_instance( name, user32, zero_instance, user32 );
499 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
501 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0x12345678 );
502 ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
503 check_class( kernel32, name, "kernel32" );
504 check_class( (HINSTANCE)0x12345678, name, "main_module" );
505 check_instance( name, kernel32, kernel32, kernel32 );
506 check_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
507 check_thread_instance( name, kernel32, kernel32, kernel32 );
508 check_thread_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
509 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" );
511 /* creating a window with instance 0 uses the first class found */
512 cls.hInstance = (HINSTANCE)0xdeadbeef;
513 cls.lpszMenuName = "deadbeef";
514 cls.style = 3;
515 ok( RegisterClassA( &cls ), "Failed to register local class for deadbeef\n" );
516 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
517 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0xdeadbeef,
518 "Didn't get deadbeef class for null instance\n" );
519 DestroyWindow( hwnd2 );
520 ok( UnregisterClassA( name, (HINSTANCE)0xdeadbeef ), "Unregister failed for deadbeef\n" );
522 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
523 ok( (HINSTANCE)GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == kernel32,
524 "Didn't get kernel32 class for null instance\n" );
525 DestroyWindow( hwnd2 );
527 r = GetClassNameA( hwnd, buffer, 4 );
528 ok( r == 3, "expected 3, got %d\n", r );
529 ok( !strcmp( buffer, "__t"), "name wrong: %s\n", buffer );
531 ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
533 hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 );
534 ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0x12345678,
535 "Didn't get 12345678 class for null instance\n" );
536 DestroyWindow( hwnd2 );
538 SetClassLongPtrA( hwnd, GCLP_HMODULE, (LONG_PTR)main_module );
539 DestroyWindow( hwnd );
541 /* null handle means the same thing as main module */
542 cls.lpszMenuName = "null";
543 cls.hInstance = 0;
544 ok( !RegisterClassA( &cls ), "Succeeded registering local class for null instance\n" );
545 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() );
546 ok( UnregisterClassA( name, main_module ), "Unregister failed for main module\n" );
548 ok( RegisterClassA( &cls ), "Failed to register local class for null instance\n" );
549 /* must be found with main module handle */
550 check_class( main_module, name, "null" );
551 check_instance( name, main_module, main_module, main_module );
552 check_thread_instance( name, main_module, main_module, main_module );
553 ok( !GetClassInfoA( 0, name, &wc ), "Class found with null instance\n" );
554 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() );
555 ok( UnregisterClassA( name, 0 ), "Unregister failed for null instance\n" );
557 /* registering for user32 always fails */
558 cls.lpszMenuName = "user32";
559 cls.hInstance = user32;
560 ok( !RegisterClassA( &cls ), "Succeeded registering local class for user32\n" );
561 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() );
562 cls.style |= CS_GLOBALCLASS;
563 ok( !RegisterClassA( &cls ), "Succeeded registering global class for user32\n" );
564 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error code %d\n", GetLastError() );
566 /* unregister is OK though */
567 cls.hInstance = main_module;
568 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" );
569 ok( UnregisterClassA( name, user32 ), "Unregister failed for user32\n" );
571 /* instance doesn't matter for global class */
572 cls.style |= CS_GLOBALCLASS;
573 cls.lpszMenuName = "main_module";
574 cls.hInstance = main_module;
575 ok( RegisterClassA( &cls ), "Failed to register global class for main module\n" );
576 cls.lpszMenuName = "kernel32";
577 cls.hInstance = kernel32;
578 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" );
579 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() );
580 /* even if global flag is cleared */
581 hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
582 SetClassLongA( hwnd, GCL_STYLE, 0 );
583 ok( !RegisterClassA( &cls ), "Succeeded registering local class for kernel32\n" );
584 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() );
586 check_class( main_module, name, "main_module" );
587 check_class( kernel32, name, "main_module" );
588 check_class( 0, name, "main_module" );
589 check_class( (HINSTANCE)0x12345678, name, "main_module" );
590 check_instance( name, main_module, main_module, main_module );
591 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
592 check_thread_instance( name, main_module, main_module, main_module );
593 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
595 /* changing the instance for global class doesn't make much difference */
596 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef );
597 check_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
598 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
599 check_thread_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
600 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
602 DestroyWindow( hwnd );
603 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
604 ok( !UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister succeeded the second time\n" );
605 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() );
607 cls.hInstance = (HINSTANCE)0x12345678;
608 ok( RegisterClassA( &cls ), "Failed to register global class for dummy instance\n" );
609 check_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
610 check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
611 check_thread_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
612 check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
613 ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
615 /* check system classes */
617 /* we cannot register a global class with the name of a system class */
618 cls.style |= CS_GLOBALCLASS;
619 cls.lpszMenuName = "button_main_module";
620 cls.lpszClassName = "BUTTON";
621 cls.hInstance = main_module;
622 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for main module\n" );
623 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() );
624 cls.hInstance = kernel32;
625 ok( !RegisterClassA( &cls ), "Succeeded registering global button class for kernel32\n" );
626 ok( GetLastError() == ERROR_CLASS_ALREADY_EXISTS, "Wrong error code %d\n", GetLastError() );
628 /* local class is OK however */
629 cls.style &= ~CS_GLOBALCLASS;
630 cls.lpszMenuName = "button_main_module";
631 cls.hInstance = main_module;
632 ok( RegisterClassA( &cls ), "Failed to register local button class for main module\n" );
633 check_class( main_module, "BUTTON", "button_main_module" );
634 cls.lpszMenuName = "button_kernel32";
635 cls.hInstance = kernel32;
636 ok( RegisterClassA( &cls ), "Failed to register local button class for kernel32\n" );
637 check_class( kernel32, "BUTTON", "button_kernel32" );
638 check_class( main_module, "BUTTON", "button_main_module" );
639 ok( UnregisterClassA( "BUTTON", kernel32 ), "Unregister failed for kernel32 button\n" );
640 ok( UnregisterClassA( "BUTTON", main_module ), "Unregister failed for main module button\n" );
641 /* GetClassInfo sets instance to passed value for global classes */
642 check_instance( "BUTTON", 0, 0, user32 );
643 check_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
644 check_instance( "BUTTON", user32, zero_instance, user32 );
645 check_thread_instance( "BUTTON", 0, 0, user32 );
646 check_thread_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
647 check_thread_instance( "BUTTON", user32, zero_instance, user32 );
649 /* we can unregister system classes */
650 ok( GetClassInfoA( 0, "BUTTON", &wc ), "Button class not found with null instance\n" );
651 ok( GetClassInfoA( kernel32, "BUTTON", &wc ), "Button class not found with kernel32\n" );
652 ok( UnregisterClassA( "BUTTON", (HINSTANCE)0x12345678 ), "Failed to unregister button\n" );
653 ok( !UnregisterClassA( "BUTTON", (HINSTANCE)0x87654321 ), "Unregistered button a second time\n" );
654 ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() );
655 ok( !GetClassInfoA( 0, "BUTTON", &wc ), "Button still exists\n" );
656 /* last error not set reliably */
658 /* we can change the instance of a system class */
659 check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
660 check_thread_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
661 hwnd = CreateWindowExA( 0, "EDIT", "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
662 SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef );
663 check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
664 check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
665 DestroyWindow(hwnd);
668 static void test_builtinproc(void)
670 /* Edit behaves differently */
671 static const CHAR NORMAL_CLASSES[][10] = {
672 "Button",
673 "Static",
674 "ComboBox",
675 "ComboLBox",
676 "ListBox",
677 "ScrollBar",
678 "#32770", /* dialog */
680 static const char classA[] = "deftest";
681 static const WCHAR classW[] = {'d','e','f','t','e','s','t',0};
682 WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0}; /* a string that would be destroyed by a W->A->W conversion */
683 WNDPROC pDefWindowProcA, pDefWindowProcW;
684 WNDPROC pNtdllDefWindowProcA, pNtdllDefWindowProcW;
685 WNDPROC oldproc;
686 WNDCLASSEXA cls; /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */
687 WCHAR buf[128];
688 ATOM atom;
689 HWND hwnd;
690 unsigned int i;
692 pDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA");
693 pDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW");
694 pNtdllDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_A");
695 pNtdllDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_W");
697 /* On Vista+, the user32.dll export DefWindowProcA/W is forwarded to */
698 /* ntdll.NtdllDefWindowProc_A/W. However, the wndproc returned by */
699 /* GetClassLong/GetWindowLong points to an unexported user32 function */
700 if (pDefWindowProcA == pNtdllDefWindowProcA &&
701 pDefWindowProcW == pNtdllDefWindowProcW)
702 skip("user32.DefWindowProcX forwarded to ntdll.NtdllDefWindowProc_X\n");
703 else
705 for (i = 0; i < 4; i++)
707 ZeroMemory(&cls, sizeof(cls));
708 cls.cbSize = sizeof(cls);
709 cls.hInstance = GetModuleHandleA(NULL);
710 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
711 if (i & 1)
712 cls.lpfnWndProc = pDefWindowProcA;
713 else
714 cls.lpfnWndProc = pDefWindowProcW;
716 if (i & 2)
718 cls.lpszClassName = classA;
719 atom = RegisterClassExA(&cls);
721 else
723 cls.lpszClassName = (LPCSTR)classW;
724 atom = RegisterClassExW((WNDCLASSEXW *)&cls);
726 ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError());
728 hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);
729 ok(hwnd != NULL, "Couldn't create window i=%d\n", i);
731 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
732 (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA);
733 ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
734 (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA);
736 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
737 (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW);
738 ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
739 (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW);
741 DestroyWindow(hwnd);
742 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL));
746 /* built-in winproc - window A/W type automatically detected */
747 ZeroMemory(&cls, sizeof(cls));
748 cls.cbSize = sizeof(cls);
749 cls.hInstance = GetModuleHandleA(NULL);
750 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
751 cls.lpszClassName = classA;
752 cls.lpfnWndProc = pDefWindowProcW;
753 atom = RegisterClassExA(&cls);
755 hwnd = CreateWindowExW(0, classW, unistring, WS_OVERLAPPEDWINDOW,
756 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleW(NULL), 0);
757 ok(IsWindowUnicode(hwnd) ||
758 broken(!IsWindowUnicode(hwnd)) /* Windows 8 and 10 */,
759 "Windows should be Unicode\n");
760 SendMessageW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
761 if (IsWindowUnicode(hwnd))
762 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
763 else
764 ok(memcmp(buf, unistring, sizeof(unistring)) != 0, "WM_GETTEXT invalid return\n");
765 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pDefWindowProcA);
766 ok(IsWindowUnicode(hwnd), "Windows should have remained Unicode\n");
767 if (GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA)
769 /* DefWindowProc isn't magic on wow64 */
770 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Ansi winproc is not a handle\n");
772 else
774 ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Invalid Unicode winproc\n");
775 ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Invalid Ansi winproc\n");
777 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
778 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have switched window to ANSI\n");
780 DestroyWindow(hwnd);
781 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL));
783 /* custom winproc - the same function can be used as both A and W*/
784 ZeroMemory(&cls, sizeof(cls));
785 cls.cbSize = sizeof(cls);
786 cls.hInstance = GetModuleHandleA(NULL);
787 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
788 cls.lpszClassName = classA;
789 cls.lpfnWndProc = ClassTest_WndProc2;
790 atom = RegisterClassExA(&cls);
792 hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW,
793 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
794 ok(IsWindowUnicode(hwnd) == FALSE, "Window should be ANSI\n");
795 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
796 ok(IsWindowUnicode(hwnd), "SetWindowLongPtrW should have changed window to Unicode\n");
797 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
798 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n");
800 DestroyWindow(hwnd);
801 UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL));
803 /* For most of the builtin controls both GetWindowLongPtrA and W returns a pointer that is executed directly
804 * by CallWindowProcA/W */
805 for (i = 0; i < ARRAY_SIZE(NORMAL_CLASSES); i++)
807 WNDPROC procA, procW;
808 hwnd = CreateWindowExA(0, NORMAL_CLASSES[i], classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260,
809 NULL, NULL, NULL, 0);
810 ok(hwnd != NULL, "Couldn't create window of class %s\n", NORMAL_CLASSES[i]);
811 SetWindowTextA(hwnd, classA); /* ComboBox needs this */
812 procA = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
813 procW = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
814 ok(!IS_WNDPROC_HANDLE(procA), "procA should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procA);
815 ok(!IS_WNDPROC_HANDLE(procW), "procW should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procW);
816 CallWindowProcA(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf);
817 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT A/A invalid return for class %s\n", NORMAL_CLASSES[i]);
818 CallWindowProcA(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf);
819 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT A/W invalid return for class %s\n", NORMAL_CLASSES[i]);
820 CallWindowProcW(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf);
821 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT W/A invalid return for class %s\n", NORMAL_CLASSES[i]);
822 CallWindowProcW(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf);
823 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT W/W invalid return for class %s\n", NORMAL_CLASSES[i]);
825 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
826 ok(IS_WNDPROC_HANDLE(oldproc) == FALSE, "Class %s shouldn't return a handle\n", NORMAL_CLASSES[i]);
827 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc);
828 DestroyWindow(hwnd);
831 /* Edit controls are special - they return a wndproc handle when GetWindowLongPtr is called with a different A/W.
832 * On the other hand there is no W->A->W conversion so this control is treated specially. */
833 hwnd = CreateWindowW(WC_EDITW, unistring, WS_OVERLAPPEDWINDOW,
834 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0);
835 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */
836 ok(IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a Unicode wndproc\n");
837 ok(IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a ANSI wndproc\n");
838 /* But GetWindowLongPtr returns only a handle for the ANSI one */
839 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n");
840 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return a W wndproc handle\n");
841 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
842 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
843 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
844 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
845 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
846 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
848 SetWindowTextW(hwnd, classW);
849 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
850 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
852 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc2);
853 /* SetWindowLongPtr returns a wndproc handle - like GetWindowLongPtr */
854 ok(IS_WNDPROC_HANDLE(oldproc), "Edit control should return a wndproc handle\n");
855 ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n");
856 SetWindowTextA(hwnd, classA); /* Windows resets the title to WideStringToMultiByte(unistring) */
857 memset(buf, 0, sizeof(buf));
858 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
859 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
860 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
861 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
862 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
863 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
865 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
866 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n");
868 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc);
870 DestroyWindow(hwnd);
872 hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW,
873 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0);
875 /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */
876 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)), "Edit control class should have a Unicode wndproc\n");
877 ok(!IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)), "Edit control class should have a ANSI wndproc\n");
878 /* But GetWindowLongPtr returns only a handle for the Unicode one */
879 ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return an A wndproc handle\n");
880 ok(IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n");
881 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
882 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
883 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
884 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
885 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
886 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
888 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
889 ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n");
891 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
892 SetWindowTextW(hwnd, unistring);
893 CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
894 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
895 CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
896 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
897 CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
898 ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
900 SetWindowTextW(hwnd, classW);
901 CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
902 ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
904 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc);
906 DestroyWindow(hwnd);
910 static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
912 return DefDlgProcA(hWnd, uMsg, wParam, lParam);
915 static BOOL RegisterTestDialog(HINSTANCE hInstance)
917 WNDCLASSEXA wcx;
918 ATOM atom = 0;
920 ZeroMemory(&wcx, sizeof(WNDCLASSEXA));
921 wcx.cbSize = sizeof(wcx);
922 wcx.lpfnWndProc = TestDlgProc;
923 wcx.cbClsExtra = 0;
924 wcx.cbWndExtra = DLGWINDOWEXTRA;
925 wcx.hInstance = hInstance;
926 wcx.hIcon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
927 wcx.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
928 wcx.hbrBackground = GetStockObject(WHITE_BRUSH);
929 wcx.lpszClassName = "TestDialog";
930 wcx.lpszMenuName = "TestDialog";
931 wcx.hIconSm = LoadImageA(hInstance, (LPCSTR)MAKEINTRESOURCE(5), IMAGE_ICON,
932 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
933 LR_DEFAULTCOLOR);
935 atom = RegisterClassExA(&wcx);
936 ok(atom != 0, "RegisterClassEx returned 0\n");
938 return atom;
941 /* test registering a dialog box created by using the CLASS directive in a
942 resource file, then test creating the dialog using CreateDialogParam. */
943 static void CreateDialogParamTest(HINSTANCE hInstance)
945 HWND hWndMain;
947 if (RegisterTestDialog(hInstance))
949 hWndMain = CreateDialogParamA(hInstance, "CLASS_TEST_DIALOG", NULL, 0, 0);
950 ok(hWndMain != NULL, "CreateDialogParam returned NULL\n");
951 ShowWindow(hWndMain, SW_SHOW);
952 DestroyWindow(hWndMain);
956 static const struct
958 const char name[9];
959 int value;
960 int badvalue;
961 } extra_values[] =
963 {"#32770",30,30}, /* Dialog */
964 #ifdef _WIN64
965 {"Edit",8,8},
966 #else
967 {"Edit",6,8}, /* Windows XP 64-bit returns 8 also to 32-bit applications */
968 #endif
971 static void test_extra_values(void)
973 int i;
974 for(i = 0; i < ARRAY_SIZE(extra_values); i++)
976 WNDCLASSEXA wcx;
977 BOOL ret = GetClassInfoExA(NULL,extra_values[i].name,&wcx);
979 ok( ret, "GetClassInfo (0) failed for global class %s\n", extra_values[i].name);
980 if (!ret) continue;
981 ok(extra_values[i].value == wcx.cbWndExtra || broken(extra_values[i].badvalue == wcx.cbWndExtra),
982 "expected %d, got %d\n", extra_values[i].value, wcx.cbWndExtra);
986 static void test_GetClassInfo(void)
988 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
989 WNDCLASSA wc;
990 WNDCLASSEXA wcx;
991 BOOL ret;
993 SetLastError(0xdeadbeef);
994 ret = GetClassInfoA(0, "static", &wc);
995 ok(ret, "GetClassInfoA() error %d\n", GetLastError());
997 if (0) { /* crashes under XP */
998 SetLastError(0xdeadbeef);
999 ret = GetClassInfoA(0, "static", NULL);
1000 ok(ret, "GetClassInfoA() error %d\n", GetLastError());
1002 SetLastError(0xdeadbeef);
1003 ret = GetClassInfoW(0, staticW, NULL);
1004 ok(ret, "GetClassInfoW() error %d\n", GetLastError());
1007 wcx.cbSize = sizeof(wcx);
1008 SetLastError(0xdeadbeef);
1009 ret = GetClassInfoExA(0, "static", &wcx);
1010 ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
1012 SetLastError(0xdeadbeef);
1013 ret = GetClassInfoExA(0, "static", NULL);
1014 ok(!ret, "GetClassInfoExA() should fail\n");
1015 ok(GetLastError() == ERROR_NOACCESS ||
1016 broken(GetLastError() == 0xdeadbeef), /* win9x */
1017 "expected ERROR_NOACCESS, got %d\n", GetLastError());
1019 SetLastError(0xdeadbeef);
1020 ret = GetClassInfoExW(0, staticW, NULL);
1021 ok(!ret, "GetClassInfoExW() should fail\n");
1022 ok(GetLastError() == ERROR_NOACCESS ||
1023 broken(GetLastError() == 0xdeadbeef) /* NT4 */ ||
1024 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1025 "expected ERROR_NOACCESS, got %d\n", GetLastError());
1027 wcx.cbSize = 0;
1028 wcx.lpfnWndProc = NULL;
1029 SetLastError(0xdeadbeef);
1030 ret = GetClassInfoExA(0, "static", &wcx);
1031 ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
1032 ok(GetLastError() == 0xdeadbeef, "Unexpected error code %d\n", GetLastError());
1033 ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize);
1034 ok(wcx.lpfnWndProc != NULL, "got null proc\n");
1036 wcx.cbSize = sizeof(wcx) - 1;
1037 wcx.lpfnWndProc = NULL;
1038 SetLastError(0xdeadbeef);
1039 ret = GetClassInfoExA(0, "static", &wcx);
1040 ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
1041 ok(wcx.cbSize == sizeof(wcx) - 1, "expected sizeof(wcx)-1, got %u\n", wcx.cbSize);
1042 ok(wcx.lpfnWndProc != NULL, "got null proc\n");
1044 wcx.cbSize = sizeof(wcx) + 1;
1045 wcx.lpfnWndProc = NULL;
1046 SetLastError(0xdeadbeef);
1047 ret = GetClassInfoExA(0, "static", &wcx);
1048 ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
1049 ok(wcx.cbSize == sizeof(wcx) + 1, "expected sizeof(wcx)+1, got %u\n", wcx.cbSize);
1050 ok(wcx.lpfnWndProc != NULL, "got null proc\n");
1053 static void test_icons(void)
1055 WNDCLASSEXW wcex, ret_wcex;
1056 WCHAR cls_name[] = {'I','c','o','n','T','e','s','t','C','l','a','s','s',0};
1057 HWND hwnd;
1058 HINSTANCE hinst = GetModuleHandleW(0);
1059 HICON hsmicon, hsmallnew;
1060 ICONINFO icinf;
1062 memset(&wcex, 0, sizeof wcex);
1063 wcex.cbSize = sizeof wcex;
1064 wcex.lpfnWndProc = ClassTest_WndProc;
1065 wcex.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
1066 wcex.hInstance = hinst;
1067 wcex.lpszClassName = cls_name;
1068 ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n");
1069 hwnd = CreateWindowExW(0, cls_name, NULL, WS_OVERLAPPEDWINDOW,
1070 0, 0, 0, 0, NULL, NULL, hinst, 0);
1071 ok(hwnd != NULL, "Window was not created\n");
1073 ok(GetClassInfoExW(hinst, cls_name, &ret_wcex), "Class info was not retrieved\n");
1074 ok(wcex.hIcon == ret_wcex.hIcon, "Icons don't match\n");
1075 ok(ret_wcex.hIconSm != NULL, "hIconSm should be non-zero handle\n");
1077 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
1078 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
1080 ok(SendMessageA(hwnd, WM_GETICON, ICON_BIG, 0) == 0,
1081 "WM_GETICON with ICON_BIG should not return the class icon\n");
1082 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL, 0) == 0,
1083 "WM_GETICON with ICON_SMALL should not return the class icon\n");
1084 ok(SendMessageA(hwnd, WM_GETICON, ICON_SMALL2, 0) == 0,
1085 "WM_GETICON with ICON_SMALL2 should not return the class icon\n");
1087 hsmallnew = CopyImage(wcex.hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
1088 GetSystemMetrics(SM_CYSMICON), 0);
1089 ok(!SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hsmallnew),
1090 "Previous hIconSm should be zero\n");
1091 ok(hsmallnew == (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM),
1092 "Should return explicitly assigned small icon\n");
1093 ok(!GetIconInfo(hsmicon, &icinf), "Previous small icon should be destroyed\n");
1095 SetClassLongPtrW(hwnd, GCLP_HICONSM, 0);
1096 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
1097 ok( hsmicon != NULL, "GetClassLong should return non-zero handle\n");
1099 SetClassLongPtrW(hwnd, GCLP_HICON, 0);
1100 ok(!GetClassLongPtrW(hwnd, GCLP_HICONSM), "GetClassLong should return zero handle\n");
1102 SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)LoadIconW(NULL, (LPCWSTR)IDI_QUESTION));
1103 hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
1104 ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
1105 UnregisterClassW(cls_name, hinst);
1106 ok(GetIconInfo(hsmicon, &icinf), "Icon should NOT be destroyed\n");
1108 DestroyIcon(hsmallnew);
1109 DestroyWindow(hwnd);
1112 static void create_manifest_file(const char *filename, const char *manifest)
1114 WCHAR path[MAX_PATH];
1115 HANDLE file;
1116 DWORD size;
1118 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
1119 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1120 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1121 WriteFile(file, manifest, strlen(manifest), &size, NULL);
1122 CloseHandle(file);
1125 static HANDLE create_test_actctx(const char *file)
1127 WCHAR path[MAX_PATH];
1128 ACTCTXW actctx;
1129 HANDLE handle;
1131 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
1132 memset(&actctx, 0, sizeof(ACTCTXW));
1133 actctx.cbSize = sizeof(ACTCTXW);
1134 actctx.lpSource = path;
1136 handle = CreateActCtxW(&actctx);
1137 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
1139 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
1140 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
1141 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
1142 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
1143 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
1144 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
1145 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
1146 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
1147 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
1149 return handle;
1151 static void test_comctl32_class( const char *name )
1153 WNDCLASSA wcA;
1154 WNDCLASSW wcW;
1155 BOOL ret;
1156 HMODULE module;
1157 WCHAR nameW[20];
1158 HWND hwnd;
1160 if (name[0] == '!')
1162 char path[MAX_PATH];
1163 ULONG_PTR cookie;
1164 HANDLE context;
1166 name++;
1168 GetTempPathA(ARRAY_SIZE(path), path);
1169 strcat(path, "comctl32_class.manifest");
1171 create_manifest_file(path, comctl32_manifest);
1172 context = create_test_actctx(path);
1173 ret = DeleteFileA(path);
1174 ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError());
1176 module = GetModuleHandleA( "comctl32" );
1177 ok( !module, "comctl32 already loaded\n" );
1179 ret = ActivateActCtx(context, &cookie);
1180 ok(ret, "Failed to activate context.\n");
1182 /* Some systems load modules during context activation. In this case skip the rest of the test. */
1183 module = GetModuleHandleA( "comctl32" );
1184 ok( !module || broken(module != NULL) /* Vista/Win7 */, "comctl32 already loaded\n" );
1185 if (module)
1187 win_skip("Module loaded during context activation. Skipping tests.\n");
1188 goto skiptest;
1191 ret = GetClassInfoA( 0, name, &wcA );
1192 ok( ret || broken(!ret) /* WinXP */, "GetClassInfoA failed for %s\n", name );
1193 if (!ret)
1194 goto skiptest;
1196 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1197 ret = GetClassInfoW( 0, nameW, &wcW );
1198 ok( ret, "GetClassInfoW failed for %s\n", name );
1199 module = GetModuleHandleA( "comctl32" );
1200 ok( module != 0, "comctl32 not loaded\n" );
1201 FreeLibrary( module );
1202 module = GetModuleHandleA( "comctl32" );
1203 ok( !module || broken(module != NULL) /* Vista */, "comctl32 still loaded\n" );
1204 hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 );
1205 ok( hwnd != 0, "failed to create window for %s\n", name );
1206 module = GetModuleHandleA( "comctl32" );
1207 ok( module != 0, "comctl32 not loaded\n" );
1208 DestroyWindow( hwnd );
1210 skiptest:
1211 ret = DeactivateActCtx(0, cookie);
1212 ok(ret, "Failed to deactivate context.\n");
1213 ReleaseActCtx(context);
1215 else
1217 module = GetModuleHandleA( "comctl32" );
1218 ok( !module, "comctl32 already loaded\n" );
1219 ret = GetClassInfoA( 0, name, &wcA );
1220 ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name );
1221 if (!ret) return;
1222 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW));
1223 ret = GetClassInfoW( 0, nameW, &wcW );
1224 ok( ret, "GetClassInfoW failed for %s\n", name );
1225 module = GetModuleHandleA( "comctl32" );
1226 ok( module != 0, "comctl32 not loaded\n" );
1227 FreeLibrary( module );
1228 module = GetModuleHandleA( "comctl32" );
1229 ok( !module, "comctl32 still loaded\n" );
1230 hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 );
1231 ok( hwnd != 0, "failed to create window for %s\n", name );
1232 module = GetModuleHandleA( "comctl32" );
1233 ok( module != 0, "comctl32 not loaded\n" );
1234 DestroyWindow( hwnd );
1238 /* verify that comctl32 classes are automatically loaded by user32 */
1239 static void test_comctl32_classes(void)
1241 char path_name[MAX_PATH];
1242 PROCESS_INFORMATION info;
1243 STARTUPINFOA startup;
1244 char **argv;
1245 int i;
1247 static const char *classes[] =
1249 ANIMATE_CLASSA,
1250 WC_COMBOBOXEXA,
1251 DATETIMEPICK_CLASSA,
1252 WC_HEADERA,
1253 HOTKEY_CLASSA,
1254 WC_IPADDRESSA,
1255 WC_LISTVIEWA,
1256 MONTHCAL_CLASSA,
1257 WC_NATIVEFONTCTLA,
1258 WC_PAGESCROLLERA,
1259 PROGRESS_CLASSA,
1260 REBARCLASSNAMEA,
1261 STATUSCLASSNAMEA,
1262 "SysLink",
1263 WC_TABCONTROLA,
1264 TOOLBARCLASSNAMEA,
1265 TOOLTIPS_CLASSA,
1266 TRACKBAR_CLASSA,
1267 WC_TREEVIEWA,
1268 UPDOWN_CLASSA,
1269 "!Button",
1270 "!Edit",
1271 "!Static",
1272 "!Listbox",
1273 "!ComboBox",
1274 "!ComboLBox",
1277 winetest_get_mainargs( &argv );
1278 for (i = 0; i < ARRAY_SIZE(classes); i++)
1280 memset( &startup, 0, sizeof(startup) );
1281 startup.cb = sizeof( startup );
1282 sprintf( path_name, "%s class %s", argv[0], classes[i] );
1283 ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ),
1284 "CreateProcess failed.\n" );
1285 wait_child_process( info.hProcess );
1286 CloseHandle( info.hProcess );
1287 CloseHandle( info.hThread );
1291 static void test_IME(void)
1293 static const WCHAR ime_classW[] = {'I','M','E',0};
1295 char module_name[MAX_PATH], *ptr;
1296 MEMORY_BASIC_INFORMATION mbi;
1297 WNDCLASSW wnd_classw;
1298 WNDCLASSA wnd_class;
1299 SIZE_T size;
1300 BOOL ret;
1302 if (!GetProcAddress(GetModuleHandleA("user32.dll"), "BroadcastSystemMessageExA"))
1304 win_skip("BroadcastSystemMessageExA not available, skipping IME class test\n");
1305 return;
1308 ok(GetModuleHandleA("imm32") != 0, "imm32.dll is not loaded\n");
1310 ret = GetClassInfoA(NULL, "IME", &wnd_class);
1311 ok(ret, "GetClassInfo failed: %d\n", GetLastError());
1313 size = VirtualQuery(wnd_class.lpfnWndProc, &mbi, sizeof(mbi));
1314 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size);
1315 if (size == sizeof(mbi)) {
1316 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name));
1317 ok(size, "GetModuleFileName failed\n");
1318 for (ptr = module_name+size-1; ptr > module_name; ptr--)
1319 if (*ptr == '\\' || *ptr == '/') break;
1320 if (*ptr == '\\' || *ptr=='/') ptr++;
1321 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr);
1324 ret = GetClassInfoW(NULL, ime_classW, &wnd_classw);
1325 ok(ret, "GetClassInfo failed: %d\n", GetLastError());
1327 size = VirtualQuery(wnd_classw.lpfnWndProc, &mbi, sizeof(mbi));
1328 ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size);
1329 size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name));
1330 ok(size, "GetModuleFileName failed\n");
1331 for (ptr = module_name+size-1; ptr > module_name; ptr--)
1332 if (*ptr == '\\' || *ptr == '/') break;
1333 if (*ptr == '\\' || *ptr=='/') ptr++;
1334 ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr);
1337 static void test_actctx_classes(void)
1339 static const char main_manifest[] =
1340 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1341 "<assemblyIdentity version=\"4.3.2.1\" name=\"Wine.WndClass.Test\" type=\"win32\" />"
1342 "<file name=\"file.exe\">"
1343 "<windowClass>MyTestClass</windowClass>"
1344 "</file>"
1345 "</assembly>";
1346 static const char *testclass = "MyTestClass";
1347 WNDCLASSA wc;
1348 ULONG_PTR cookie;
1349 HANDLE context;
1350 BOOL ret;
1351 ATOM class;
1352 HINSTANCE hinst;
1353 char buff[64];
1354 HWND hwnd, hwnd2;
1355 char path[MAX_PATH];
1357 GetTempPathA(ARRAY_SIZE(path), path);
1358 strcat(path, "actctx_classes.manifest");
1360 create_manifest_file(path, main_manifest);
1361 context = create_test_actctx(path);
1362 ret = DeleteFileA(path);
1363 ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError());
1365 ret = ActivateActCtx(context, &cookie);
1366 ok(ret, "Failed to activate context.\n");
1368 memset(&wc, 0, sizeof(wc));
1369 wc.lpfnWndProc = ClassTest_WndProc;
1370 wc.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
1371 wc.lpszClassName = testclass;
1373 hinst = GetModuleHandleW(0);
1375 ret = GetClassInfoA(hinst, testclass, &wc);
1376 ok(!ret, "Expected failure.\n");
1378 class = RegisterClassA(&wc);
1379 ok(class != 0, "Failed to register class.\n");
1381 /* Class info is available by versioned and regular names. */
1382 ret = GetClassInfoA(hinst, testclass, &wc);
1383 ok(ret, "Failed to get class info.\n");
1385 hwnd = CreateWindowExA(0, testclass, "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0);
1386 ok(hwnd != NULL, "Failed to create a window.\n");
1388 hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL);
1389 ok(hwnd2 == hwnd, "Failed to find test window.\n");
1391 hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL);
1392 ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2);
1394 ret = GetClassNameA(hwnd, buff, sizeof(buff));
1395 ok(ret, "Failed to get class name.\n");
1396 ok(!strcmp(buff, testclass), "Unexpected class name.\n");
1398 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc);
1399 ok(ret, "Failed to get class info.\n");
1401 ret = UnregisterClassA(testclass, hinst);
1402 ok(!ret, "Failed to unregister class.\n");
1404 ret = DeactivateActCtx(0, cookie);
1405 ok(ret, "Failed to deactivate context.\n");
1407 ret = GetClassInfoA(hinst, testclass, &wc);
1408 ok(!ret, "Unexpected ret val %d.\n", ret);
1410 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc);
1411 ok(ret, "Failed to get class info.\n");
1413 ret = GetClassNameA(hwnd, buff, sizeof(buff));
1414 ok(ret, "Failed to get class name.\n");
1415 ok(!strcmp(buff, testclass), "Unexpected class name.\n");
1417 DestroyWindow(hwnd);
1419 hwnd = CreateWindowExA(0, "4.3.2.1!MyTestClass", "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0);
1420 ok(hwnd != NULL, "Failed to create a window.\n");
1422 hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL);
1423 ok(hwnd2 == hwnd, "Failed to find test window.\n");
1425 hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL);
1426 ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2);
1428 DestroyWindow(hwnd);
1430 ret = UnregisterClassA("MyTestClass", hinst);
1431 ok(!ret, "Unexpected ret value %d.\n", ret);
1433 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst);
1434 ok(ret, "Failed to unregister class.\n");
1436 /* Register versioned class without active context. */
1437 wc.lpszClassName = "4.3.2.1!MyTestClass";
1438 class = RegisterClassA(&wc);
1439 ok(class != 0, "Failed to register class.\n");
1441 ret = ActivateActCtx(context, &cookie);
1442 ok(ret, "Failed to activate context.\n");
1444 wc.lpszClassName = "MyTestClass";
1445 class = RegisterClassA(&wc);
1446 ok(class == 0, "Expected failure.\n");
1448 ret = DeactivateActCtx(0, cookie);
1449 ok(ret, "Failed to deactivate context.\n");
1451 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst);
1452 ok(ret, "Failed to unregister class.\n");
1454 /* Only versioned name is registered. */
1455 ret = ActivateActCtx(context, &cookie);
1456 ok(ret, "Failed to activate context.\n");
1458 wc.lpszClassName = "MyTestClass";
1459 class = RegisterClassA(&wc);
1460 ok(class != 0, "Failed to register class\n");
1462 ret = DeactivateActCtx(0, cookie);
1463 ok(ret, "Failed to deactivate context.\n");
1465 ret = GetClassInfoA(hinst, "MyTestClass", &wc);
1466 ok(!ret, "Expected failure.\n");
1468 ret = GetClassInfoA(hinst, "4.3.2.1!MyTestClass", &wc);
1469 ok(ret, "Failed to get class info.\n");
1471 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst);
1472 ok(ret, "Failed to unregister class.\n");
1474 /* Register regular name first, it's not considered when versioned name is registered. */
1475 wc.lpszClassName = "MyTestClass";
1476 class = RegisterClassA(&wc);
1477 ok(class != 0, "Failed to register class.\n");
1479 ret = ActivateActCtx(context, &cookie);
1480 ok(ret, "Failed to activate context.\n");
1482 wc.lpszClassName = "MyTestClass";
1483 class = RegisterClassA(&wc);
1484 ok(class != 0, "Failed to register class.\n");
1486 ret = DeactivateActCtx(0, cookie);
1487 ok(ret, "Failed to deactivate context.\n");
1489 ret = UnregisterClassA("4.3.2.1!MyTestClass", hinst);
1490 ok(ret, "Failed to unregister class.\n");
1492 ret = UnregisterClassA("MyTestClass", hinst);
1493 ok(ret, "Failed to unregister class.\n");
1495 ReleaseActCtx(context);
1498 static void test_uxtheme(void)
1500 static const CHAR *class_name = "test_uxtheme_class";
1501 BOOL (WINAPI * pIsThemeActive)(void);
1502 BOOL dll_loaded, is_theme_active;
1503 WNDCLASSEXA class;
1504 HMODULE uxtheme;
1505 ATOM atom;
1506 HWND hwnd;
1508 memset(&class, 0, sizeof(class));
1509 class.cbSize = sizeof(class);
1510 class.lpfnWndProc = DefWindowProcA;
1511 class.hInstance = GetModuleHandleA(NULL);
1512 class.lpszClassName = class_name;
1513 atom = RegisterClassExA(&class);
1514 ok(atom, "RegisterClassExA failed, error %u.\n", GetLastError());
1516 dll_loaded = !!GetModuleHandleA("comctl32.dll");
1517 ok(!dll_loaded, "Expected comctl32.dll not loaded.\n");
1518 dll_loaded = !!GetModuleHandleA("uxtheme.dll");
1519 todo_wine_if(dll_loaded)
1520 ok(!dll_loaded, "Expected uxtheme.dll not loaded.\n");
1522 /* Creating a window triggers uxtheme load when theming is active */
1523 hwnd = CreateWindowA(class_name, "Test", WS_POPUP, 0, 0, 1, 1, NULL, NULL,
1524 GetModuleHandleA(NULL), NULL);
1525 ok(!!hwnd, "Failed to create a test window, error %u.\n", GetLastError());
1527 dll_loaded = !!GetModuleHandleA("comctl32.dll");
1528 ok(!dll_loaded, "Expected comctl32.dll not loaded.\n");
1530 /* Uxtheme is loaded when theming is active */
1531 dll_loaded = !!GetModuleHandleA("uxtheme.dll");
1533 uxtheme = LoadLibraryA("uxtheme.dll");
1534 ok(!!uxtheme, "Failed to load uxtheme.dll, error %u.\n", GetLastError());
1535 pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive");
1536 ok(!!pIsThemeActive, "Failed to load IsThemeActive, error %u.\n", GetLastError());
1537 is_theme_active = pIsThemeActive();
1538 FreeLibrary(uxtheme);
1540 ok(dll_loaded == is_theme_active, "Expected uxtheme %s when theming is %s.\n",
1541 is_theme_active ? "loaded" : "not loaded", is_theme_active ? "active" : "inactive");
1543 DestroyWindow(hwnd);
1544 UnregisterClassA(class_name, GetModuleHandleA(NULL));
1547 START_TEST(class)
1549 char **argv;
1550 HANDLE hInstance = GetModuleHandleA( NULL );
1551 int argc = winetest_get_mainargs( &argv );
1553 if (argc >= 3)
1555 test_comctl32_class( argv[2] );
1556 return;
1559 test_uxtheme();
1560 test_IME();
1561 test_GetClassInfo();
1562 test_extra_values();
1564 if (!GetModuleHandleW(0))
1566 trace("Class test is incompatible with Win9x implementation, skipping\n");
1567 return;
1570 ClassTest(hInstance,FALSE);
1571 ClassTest(hInstance,TRUE);
1572 ClassTest((HANDLE)((ULONG_PTR)hInstance | 0x1234), FALSE);
1573 ClassTest((HANDLE)((ULONG_PTR)hInstance | 0x1234), TRUE);
1574 CreateDialogParamTest(hInstance);
1575 test_styles();
1576 test_builtinproc();
1577 test_icons();
1578 test_comctl32_classes();
1579 test_actctx_classes();
1581 /* this test unregisters the Button class so it should be executed at the end */
1582 test_instances();