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