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