msi/tests: Delete the temp .msi file in all failure cases.
[wine.git] / dlls / user32 / class.c
blob9c7bd3a5c6b8f8579387134ee004097745f61f43
1 /*
2 * Window classes functions
4 * Copyright 1993, 1996, 2003 Alexandre Julliard
5 * Copyright 1998 Juergen Schmied (jsch)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "ntstatus.h"
23 #define WIN32_NO_STATUS
24 #include "user_private.h"
25 #include "controls.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(class);
30 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
32 static inline const char *debugstr_us( const UNICODE_STRING *us )
34 if (!us) return "<null>";
35 return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
39 /***********************************************************************
40 * get_int_atom_value
42 ATOM get_int_atom_value( UNICODE_STRING *name )
44 const WCHAR *ptr = name->Buffer;
45 const WCHAR *end = ptr + name->Length / sizeof(WCHAR);
46 UINT ret = 0;
48 if (IS_INTRESOURCE(ptr)) return LOWORD(ptr);
50 if (*ptr++ != '#') return 0;
51 while (ptr < end)
53 if (*ptr < '0' || *ptr > '9') return 0;
54 ret = ret * 10 + *ptr++ - '0';
55 if (ret > 0xffff) return 0;
57 return ret;
61 /***********************************************************************
62 * is_comctl32_class
64 static BOOL is_comctl32_class( const WCHAR *name )
66 static const WCHAR *classesW[] =
68 L"ComboBoxEx32",
69 L"msctls_hotkey32",
70 L"msctls_progress32",
71 L"msctls_statusbar32",
72 L"msctls_trackbar32",
73 L"msctls_updown32",
74 L"NativeFontCtl",
75 L"ReBarWindow32",
76 L"SysAnimate32",
77 L"SysDateTimePick32",
78 L"SysHeader32",
79 L"SysIPAddress32",
80 L"SysLink",
81 L"SysListView32",
82 L"SysMonthCal32",
83 L"SysPager",
84 L"SysTabControl32",
85 L"SysTreeView32",
86 L"ToolbarWindow32",
87 L"tooltips_class32",
90 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
92 while (min <= max)
94 int res, pos = (min + max) / 2;
95 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
96 if (res < 0) max = pos - 1;
97 else min = pos + 1;
99 return FALSE;
102 static BOOL is_builtin_class( const WCHAR *name )
104 static const WCHAR *classesW[] =
106 L"IME",
107 L"MDIClient",
108 L"Scrollbar",
111 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
113 while (min <= max)
115 int res, pos = (min + max) / 2;
116 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
117 if (res < 0) max = pos - 1;
118 else min = pos + 1;
120 return FALSE;
124 static void init_class_name( UNICODE_STRING *str, const WCHAR *name )
126 if (IS_INTRESOURCE( name ))
128 str->Buffer = (WCHAR *)name;
129 str->Length = str->MaximumLength = 0;
131 else RtlInitUnicodeString( str, name );
134 static BOOL alloc_menu_nameA( struct client_menu_name *ret, const char *menu_name )
136 if (!IS_INTRESOURCE(menu_name))
138 DWORD lenA = strlen( menu_name ) + 1;
139 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, NULL, 0 );
140 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
141 if (!ret->nameW) return FALSE;
142 ret->nameA = (char *)(ret->nameW + lenW);
143 MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, ret->nameW, lenW );
144 memcpy( ret->nameA, menu_name, lenA );
146 else
148 ret->nameW = (WCHAR *)menu_name;
149 ret->nameA = (char *)menu_name;
151 return TRUE;
154 static BOOL alloc_menu_nameW( struct client_menu_name *ret, const WCHAR *menu_name )
156 if (!IS_INTRESOURCE(menu_name))
158 DWORD lenW = lstrlenW( menu_name ) + 1;
159 DWORD lenA = WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, NULL, 0, NULL, NULL );
160 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
161 if (!ret->nameW) return FALSE;
162 ret->nameA = (char *)(ret->nameW + lenW);
163 memcpy( ret->nameW, menu_name, lenW * sizeof(WCHAR) );
164 WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, ret->nameA, lenA, NULL, NULL );
166 else
168 ret->nameW = (WCHAR *)menu_name;
169 ret->nameA = (char *)menu_name;
171 return TRUE;
174 static void free_menu_name( struct client_menu_name *name )
176 if (!IS_INTRESOURCE(name->nameW)) HeapFree( GetProcessHeap(), 0, name->nameW );
179 static ULONG_PTR set_menu_nameW( HWND hwnd, INT offset, ULONG_PTR newval )
181 struct client_menu_name menu_name;
182 if (!alloc_menu_nameW( &menu_name, (const WCHAR *)newval )) return 0;
183 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, FALSE );
184 free_menu_name( &menu_name );
185 return 0;
188 static ULONG_PTR set_menu_nameA( HWND hwnd, INT offset, ULONG_PTR newval )
190 struct client_menu_name menu_name;
191 if (!alloc_menu_nameA( &menu_name, (const char *)newval )) return 0;
192 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, TRUE );
193 free_menu_name( &menu_name );
194 return 0;
197 static void get_versioned_name( const WCHAR *name, UNICODE_STRING *ret, UNICODE_STRING *version, HMODULE *reg_module )
199 ACTCTX_SECTION_KEYED_DATA data;
200 struct wndclass_redirect_data
202 ULONG size;
203 DWORD res;
204 ULONG name_len;
205 ULONG name_offset;
206 ULONG module_len;
207 ULONG module_offset;
208 } *wndclass;
209 const WCHAR *module, *ptr;
210 UNICODE_STRING name_us;
211 HMODULE hmod;
212 UINT offset = 0;
214 if (reg_module) *reg_module = 0;
215 if (version) version->Length = 0;
217 if (IS_INTRESOURCE( name ) || is_comctl32_class( name ) || is_builtin_class( name ))
219 init_class_name( ret, name );
220 return;
223 data.cbSize = sizeof(data);
224 RtlInitUnicodeString(&name_us, name);
225 if (RtlFindActivationContextSectionString( 0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
226 &name_us, &data ))
228 init_class_name( ret, name );
229 return;
232 wndclass = (struct wndclass_redirect_data *)data.lpData;
233 offset = wndclass->name_len / sizeof(WCHAR) - lstrlenW(name);
235 module = (const WCHAR *)((BYTE *)data.lpSectionBase + wndclass->module_offset);
236 if (!(hmod = GetModuleHandleW( module )))
237 hmod = LoadLibraryW( module );
239 /* Combined name is used to register versioned class name. Base name part will match exactly
240 original class name and won't be reused from context data. */
241 ptr = (const WCHAR *)((BYTE *)wndclass + wndclass->name_offset);
242 if (version)
244 WCHAR *combined = version->Buffer;
245 memcpy( combined, ptr, offset * sizeof(WCHAR) );
246 lstrcpyW( &combined[offset], name );
247 version->Length = offset * sizeof(WCHAR);
248 ptr = combined;
251 if (reg_module) *reg_module = hmod;
252 init_class_name( ret, ptr );
256 static void load_uxtheme(void)
258 BOOL (WINAPI * pIsThemeActive)(void);
259 HMODULE uxtheme;
261 uxtheme = LoadLibraryA("uxtheme.dll");
262 if (uxtheme)
264 pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive");
265 if (!pIsThemeActive || !pIsThemeActive())
266 FreeLibrary(uxtheme);
270 /***********************************************************************
271 * User32InitBuiltinClasses
273 NTSTATUS WINAPI User32InitBuiltinClasses( void *args, ULONG size )
275 DWORD layout;
277 GetProcessDefaultLayout( &layout ); /* make sure that process layout is initialized */
279 /* Load uxtheme.dll so that standard scrollbars and dialogs are hooked for theming support */
280 load_uxtheme();
281 return STATUS_SUCCESS;
285 /***********************************************************************
286 * RegisterClassA (USER32.@)
288 * Register a window class.
290 * RETURNS
291 * >0: Unique identifier
292 * 0: Failure
294 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
296 WNDCLASSEXA wcex;
298 wcex.cbSize = sizeof(wcex);
299 wcex.style = wc->style;
300 wcex.lpfnWndProc = wc->lpfnWndProc;
301 wcex.cbClsExtra = wc->cbClsExtra;
302 wcex.cbWndExtra = wc->cbWndExtra;
303 wcex.hInstance = wc->hInstance;
304 wcex.hIcon = wc->hIcon;
305 wcex.hCursor = wc->hCursor;
306 wcex.hbrBackground = wc->hbrBackground;
307 wcex.lpszMenuName = wc->lpszMenuName;
308 wcex.lpszClassName = wc->lpszClassName;
309 wcex.hIconSm = 0;
310 return RegisterClassExA( &wcex );
314 /***********************************************************************
315 * RegisterClassW (USER32.@)
317 * See RegisterClassA.
319 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
321 WNDCLASSEXW wcex;
323 wcex.cbSize = sizeof(wcex);
324 wcex.style = wc->style;
325 wcex.lpfnWndProc = wc->lpfnWndProc;
326 wcex.cbClsExtra = wc->cbClsExtra;
327 wcex.cbWndExtra = wc->cbWndExtra;
328 wcex.hInstance = wc->hInstance;
329 wcex.hIcon = wc->hIcon;
330 wcex.hCursor = wc->hCursor;
331 wcex.hbrBackground = wc->hbrBackground;
332 wcex.lpszMenuName = wc->lpszMenuName;
333 wcex.lpszClassName = wc->lpszClassName;
334 wcex.hIconSm = 0;
335 return RegisterClassExW( &wcex );
339 /***********************************************************************
340 * RegisterClassExA (USER32.@)
342 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
344 WCHAR nameW[MAX_ATOM_LEN + 1], combined[MAX_ATOM_LEN + 1];
345 struct client_menu_name menu_name;
346 UNICODE_STRING name, version;
347 ATOM atom;
349 version.Buffer = combined;
350 version.MaximumLength = sizeof(combined);
351 if (!IS_INTRESOURCE(wc->lpszClassName))
353 if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, nameW, MAX_ATOM_LEN + 1 )) return 0;
354 get_versioned_name( nameW, &name, &version, FALSE );
356 else
358 init_class_name( &name, (const WCHAR *)wc->lpszClassName );
359 version.Length = 0;
362 if (!alloc_menu_nameA( &menu_name, wc->lpszMenuName )) return 0;
364 atom = NtUserRegisterClassExWOW( (WNDCLASSEXW *)wc, &name, &version, &menu_name, 0, 1, NULL );
365 if (!atom) free_menu_name( &menu_name );
366 return atom;
370 /***********************************************************************
371 * RegisterClassExW (USER32.@)
373 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
375 WCHAR combined[MAX_ATOM_LEN + 1];
376 struct client_menu_name menu_name;
377 UNICODE_STRING name, version;
378 ATOM atom;
380 version.Buffer = combined;
381 version.MaximumLength = sizeof(combined);
382 get_versioned_name( wc->lpszClassName, &name, &version, FALSE );
384 if (!alloc_menu_nameW( &menu_name, wc->lpszMenuName )) return 0;
386 atom = NtUserRegisterClassExWOW( wc, &name, &version, &menu_name, 0, 0, NULL );
387 if (!atom) free_menu_name( &menu_name );
388 return atom;
392 /***********************************************************************
393 * UnregisterClassA (USER32.@)
395 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
397 if (!IS_INTRESOURCE(className))
399 WCHAR name[MAX_ATOM_LEN + 1];
401 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
402 return FALSE;
403 return UnregisterClassW( name, hInstance );
405 return UnregisterClassW( (LPCWSTR)className, hInstance );
408 /***********************************************************************
409 * UnregisterClassW (USER32.@)
411 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
413 struct client_menu_name menu_name;
414 UNICODE_STRING name;
415 BOOL ret;
417 get_versioned_name( className, &name, NULL, FALSE );
418 ret = NtUserUnregisterClass( &name, hInstance, &menu_name );
419 if (ret) free_menu_name( &menu_name );
420 return ret;
424 /***********************************************************************
425 * GetClassWord (USER32.@)
427 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
429 return NtUserGetClassWord( hwnd, offset );
433 /***********************************************************************
434 * GetClassLongW (USER32.@)
436 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
438 return NtUserGetClassLongW( hwnd, offset );
443 /***********************************************************************
444 * GetClassLongA (USER32.@)
446 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
448 return NtUserGetClassLongA( hwnd, offset );
452 /***********************************************************************
453 * SetClassLongW (USER32.@)
455 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
457 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
458 return NtUserSetClassLong( hwnd, offset, newval, FALSE );
462 /***********************************************************************
463 * SetClassLongA (USER32.@)
465 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
467 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
468 return NtUserSetClassLong( hwnd, offset, newval, TRUE );
472 /***********************************************************************
473 * GetClassNameA (USER32.@)
475 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
477 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
478 DWORD len;
480 if (count <= 0) return 0;
481 if (!GetClassNameW( hwnd, tmpbuf, ARRAY_SIZE( tmpbuf ))) return 0;
482 RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, lstrlenW(tmpbuf) * sizeof(WCHAR) );
483 buffer[len] = 0;
484 return len;
488 /***********************************************************************
489 * GetClassNameW (USER32.@)
491 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
493 UNICODE_STRING name = { .Buffer = buffer, .MaximumLength = count * sizeof(WCHAR) };
494 return NtUserGetClassName( hwnd, FALSE, &name );
498 /***********************************************************************
499 * RealGetWindowClassA (USER32.@)
501 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
503 return GetClassNameA( hwnd, buffer, count );
507 /***********************************************************************
508 * RealGetWindowClassW (USER32.@)
510 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
512 return GetClassNameW( hwnd, buffer, count );
516 /***********************************************************************
517 * GetClassInfoA (USER32.@)
519 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
521 WNDCLASSEXA wcex;
522 UINT ret = GetClassInfoExA( hInstance, name, &wcex );
524 if (ret)
526 wc->style = wcex.style;
527 wc->lpfnWndProc = wcex.lpfnWndProc;
528 wc->cbClsExtra = wcex.cbClsExtra;
529 wc->cbWndExtra = wcex.cbWndExtra;
530 wc->hInstance = wcex.hInstance;
531 wc->hIcon = wcex.hIcon;
532 wc->hCursor = wcex.hCursor;
533 wc->hbrBackground = wcex.hbrBackground;
534 wc->lpszMenuName = wcex.lpszMenuName;
535 wc->lpszClassName = wcex.lpszClassName;
537 return ret;
541 /***********************************************************************
542 * GetClassInfoW (USER32.@)
544 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
546 WNDCLASSEXW wcex;
547 UINT ret = GetClassInfoExW( hInstance, name, &wcex );
549 if (ret)
551 wc->style = wcex.style;
552 wc->lpfnWndProc = wcex.lpfnWndProc;
553 wc->cbClsExtra = wcex.cbClsExtra;
554 wc->cbWndExtra = wcex.cbWndExtra;
555 wc->hInstance = wcex.hInstance;
556 wc->hIcon = wcex.hIcon;
557 wc->hCursor = wcex.hCursor;
558 wc->hbrBackground = wcex.hbrBackground;
559 wc->lpszMenuName = wcex.lpszMenuName;
560 wc->lpszClassName = wcex.lpszClassName;
562 return ret;
565 ATOM get_class_info( HINSTANCE instance, const WCHAR *class_name, WNDCLASSEXW *info,
566 UNICODE_STRING *name_str, BOOL ansi )
568 UNICODE_STRING name;
569 HMODULE module;
570 ATOM atom;
572 get_versioned_name( class_name, &name, NULL, &module );
574 if (!name_str && !instance) instance = user32_module;
576 while (!(atom = NtUserGetClassInfoEx( instance, &name, info, NULL, ansi )))
578 if (module)
580 BOOL (WINAPI *pRegisterClassNameW)( const WCHAR *class );
581 pRegisterClassNameW = (void *)GetProcAddress( module, "RegisterClassNameW" );
582 module = NULL;
583 if (pRegisterClassNameW)
585 TRACE( "registering %s\n", debugstr_us(&name) );
586 pRegisterClassNameW( class_name );
587 continue;
590 if (IS_INTRESOURCE( class_name )) break;
591 if (!is_comctl32_class( class_name )) break;
592 if (GetModuleHandleW( L"comctl32.dll" )) break;
593 if (!LoadLibraryW( L"comctl32.dll" )) break;
594 TRACE( "%s retrying after loading comctl32\n", debugstr_w(class_name) );
597 if (!atom)
599 TRACE( "%s %p -> not found\n", debugstr_w(class_name), instance );
600 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
601 return 0;
604 if (name_str) *name_str = name;
605 return atom;
608 /***********************************************************************
609 * GetClassInfoExA (USER32.@)
611 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
613 ATOM atom;
615 TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
617 if (!wc)
619 SetLastError( ERROR_NOACCESS );
620 return FALSE;
623 if (!IS_INTRESOURCE(name))
625 WCHAR nameW[MAX_ATOM_LEN + 1];
626 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE( nameW )))
627 return FALSE;
628 atom = get_class_info( hInstance, nameW, (WNDCLASSEXW *)wc, NULL, TRUE );
630 else atom = get_class_info( hInstance, (const WCHAR *)name, (WNDCLASSEXW *)wc, NULL, TRUE );
631 if (atom) wc->lpszClassName = name;
633 /* We must return the atom of the class here instead of just TRUE. */
634 return atom;
638 /***********************************************************************
639 * GetClassInfoExW (USER32.@)
641 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
643 ATOM atom;
645 TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
647 if (!wc)
649 SetLastError( ERROR_NOACCESS );
650 return FALSE;
653 atom = get_class_info( hInstance, name, wc, NULL, FALSE );
654 if (atom) wc->lpszClassName = name;
656 /* We must return the atom of the class here instead of just TRUE. */
657 return atom;
661 #ifdef _WIN64
663 /* 64bit versions */
665 #undef GetClassLongPtrA
666 #undef GetClassLongPtrW
667 #undef SetClassLongPtrA
668 #undef SetClassLongPtrW
670 /***********************************************************************
671 * GetClassLongPtrA (USER32.@)
673 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
675 return NtUserGetClassLongPtrA( hwnd, offset );
678 /***********************************************************************
679 * GetClassLongPtrW (USER32.@)
681 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
683 return NtUserGetClassLongPtrW( hwnd, offset );
686 /***********************************************************************
687 * SetClassLongPtrW (USER32.@)
689 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
691 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
692 return NtUserSetClassLongPtr( hwnd, offset, newval, FALSE );
695 /***********************************************************************
696 * SetClassLongPtrA (USER32.@)
698 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
700 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
701 return NtUserSetClassLongPtr( hwnd, offset, newval, TRUE );
704 #endif /* _WIN64 */