win32u: Move NtUserSetClassLong from user32.
[wine.git] / dlls / user32 / class.c
blob212bf9f8d4bf27eaf8516c9baec5c4e21b30307c
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 <assert.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winnls.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "wine/server.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(class);
41 #define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
43 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
45 #define CLASS_OTHER_PROCESS ((CLASS *)1)
47 static inline const char *debugstr_us( const UNICODE_STRING *us )
49 if (!us) return "<null>";
50 return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
53 /***********************************************************************
54 * get_class_ptr
56 static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
58 WND *ptr = WIN_GetPtr( hwnd );
60 if (ptr)
62 if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
63 if (!write_access) return CLASS_OTHER_PROCESS;
65 /* modifying classes in other processes is not allowed */
66 if (ptr == WND_DESKTOP || IsWindow( hwnd ))
68 SetLastError( ERROR_ACCESS_DENIED );
69 return NULL;
72 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
73 return NULL;
77 /***********************************************************************
78 * release_class_ptr
80 static inline void release_class_ptr( CLASS *ptr )
82 USER_Unlock();
86 /***********************************************************************
87 * get_int_atom_value
89 ATOM get_int_atom_value( UNICODE_STRING *name )
91 const WCHAR *ptr = name->Buffer;
92 const WCHAR *end = ptr + name->Length / sizeof(WCHAR);
93 UINT ret = 0;
95 if (IS_INTRESOURCE(ptr)) return LOWORD(ptr);
97 if (*ptr++ != '#') return 0;
98 while (ptr < end)
100 if (*ptr < '0' || *ptr > '9') return 0;
101 ret = ret * 10 + *ptr++ - '0';
102 if (ret > 0xffff) return 0;
104 return ret;
108 /***********************************************************************
109 * is_comctl32_class
111 static BOOL is_comctl32_class( const WCHAR *name )
113 static const WCHAR *classesW[] =
115 L"ComboBoxEx32",
116 L"msctls_hotkey32",
117 L"msctls_progress32",
118 L"msctls_statusbar32",
119 L"msctls_trackbar32",
120 L"msctls_updown32",
121 L"NativeFontCtl",
122 L"ReBarWindow32",
123 L"SysAnimate32",
124 L"SysDateTimePick32",
125 L"SysHeader32",
126 L"SysIPAddress32",
127 L"SysLink",
128 L"SysListView32",
129 L"SysMonthCal32",
130 L"SysPager",
131 L"SysTabControl32",
132 L"SysTreeView32",
133 L"ToolbarWindow32",
134 L"tooltips_class32",
137 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
139 while (min <= max)
141 int res, pos = (min + max) / 2;
142 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
143 if (res < 0) max = pos - 1;
144 else min = pos + 1;
146 return FALSE;
149 static BOOL is_builtin_class( const WCHAR *name )
151 static const WCHAR *classesW[] =
153 L"IME",
154 L"MDIClient",
155 L"Scrollbar",
158 int min = 0, max = ARRAY_SIZE( classesW ) - 1;
160 while (min <= max)
162 int res, pos = (min + max) / 2;
163 if (!(res = wcsicmp( name, classesW[pos] ))) return TRUE;
164 if (res < 0) max = pos - 1;
165 else min = pos + 1;
167 return FALSE;
171 static void init_class_name( UNICODE_STRING *str, const WCHAR *name )
173 if (IS_INTRESOURCE( name ))
175 str->Buffer = (WCHAR *)name;
176 str->Length = str->MaximumLength = 0;
178 else RtlInitUnicodeString( str, name );
181 static BOOL alloc_menu_nameA( struct client_menu_name *ret, const char *menu_name )
183 if (!IS_INTRESOURCE(menu_name))
185 DWORD lenA = strlen( menu_name ) + 1;
186 DWORD lenW = MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, NULL, 0 );
187 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
188 if (!ret->nameW) return FALSE;
189 ret->nameA = (char *)(ret->nameW + lenW);
190 MultiByteToWideChar( CP_ACP, 0, menu_name, lenA, ret->nameW, lenW );
191 memcpy( ret->nameA, menu_name, lenA );
193 else
195 ret->nameW = (WCHAR *)menu_name;
196 ret->nameA = (char *)menu_name;
198 return TRUE;
201 static BOOL alloc_menu_nameW( struct client_menu_name *ret, const WCHAR *menu_name )
203 if (!IS_INTRESOURCE(menu_name))
205 DWORD lenW = lstrlenW( menu_name ) + 1;
206 DWORD lenA = WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, NULL, 0, NULL, NULL );
207 ret->nameW = HeapAlloc( GetProcessHeap(), 0, lenA + lenW * sizeof(WCHAR) );
208 if (!ret->nameW) return FALSE;
209 memcpy( ret->nameW, menu_name, lenW * sizeof(WCHAR) );
210 WideCharToMultiByte( CP_ACP, 0, menu_name, lenW, ret->nameA, lenA, NULL, NULL );
212 else
214 ret->nameW = (WCHAR *)menu_name;
215 ret->nameA = (char *)menu_name;
217 return TRUE;
220 static void free_menu_name( struct client_menu_name *name )
222 if (!IS_INTRESOURCE(name->nameW)) HeapFree( GetProcessHeap(), 0, name->nameW );
225 static ULONG_PTR set_menu_nameW( HWND hwnd, INT offset, ULONG_PTR newval )
227 struct client_menu_name menu_name;
228 if (!alloc_menu_nameW( &menu_name, (const WCHAR *)newval )) return 0;
229 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, FALSE );
230 free_menu_name( &menu_name );
231 return 0;
234 static ULONG_PTR set_menu_nameA( HWND hwnd, INT offset, ULONG_PTR newval )
236 struct client_menu_name menu_name;
237 if (!alloc_menu_nameA( &menu_name, (const char *)newval )) return 0;
238 NtUserSetClassLongPtr( hwnd, offset, (ULONG_PTR)&menu_name, TRUE );
239 free_menu_name( &menu_name );
240 return 0;
243 static void get_versioned_name( const WCHAR *name, UNICODE_STRING *ret, UNICODE_STRING *version, HMODULE *reg_module )
245 ACTCTX_SECTION_KEYED_DATA data;
246 struct wndclass_redirect_data
248 ULONG size;
249 DWORD res;
250 ULONG name_len;
251 ULONG name_offset;
252 ULONG module_len;
253 ULONG module_offset;
254 } *wndclass;
255 const WCHAR *module, *ptr;
256 UNICODE_STRING name_us;
257 HMODULE hmod;
258 UINT offset = 0;
260 if (reg_module) *reg_module = 0;
261 if (version) version->Length = 0;
263 if (IS_INTRESOURCE( name ) || is_comctl32_class( name ) || is_builtin_class( name ))
265 init_class_name( ret, name );
266 return;
269 data.cbSize = sizeof(data);
270 RtlInitUnicodeString(&name_us, name);
271 if (RtlFindActivationContextSectionString( 0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
272 &name_us, &data ))
274 init_class_name( ret, name );
275 return;
278 wndclass = (struct wndclass_redirect_data *)data.lpData;
279 offset = wndclass->name_len / sizeof(WCHAR) - lstrlenW(name);
281 module = (const WCHAR *)((BYTE *)data.lpSectionBase + wndclass->module_offset);
282 if (!(hmod = GetModuleHandleW( module )))
283 hmod = LoadLibraryW( module );
285 /* Combined name is used to register versioned class name. Base name part will match exactly
286 original class name and won't be reused from context data. */
287 ptr = (const WCHAR *)((BYTE *)wndclass + wndclass->name_offset);
288 if (version)
290 WCHAR *combined = version->Buffer;
291 memcpy( combined, ptr, offset * sizeof(WCHAR) );
292 lstrcpyW( &combined[offset], name );
293 version->Length = offset * sizeof(WCHAR);
294 ptr = combined;
297 if (reg_module) *reg_module = hmod;
298 init_class_name( ret, ptr );
302 /***********************************************************************
303 * register_builtin
305 * Register a builtin control class.
306 * This allows having both ANSI and Unicode winprocs for the same class.
308 static void register_builtin( const struct builtin_class_descr *descr )
310 UNICODE_STRING name, version = { .Length = 0 };
311 struct client_menu_name menu_name = { 0 };
312 WNDCLASSEXW class = {
313 .cbSize = sizeof(class),
314 .hInstance = user32_module,
315 .style = descr->style,
316 .cbWndExtra = descr->extra,
317 .hbrBackground = descr->brush,
318 .lpfnWndProc = BUILTIN_WINPROC( descr->proc ),
321 if (descr->cursor) class.hCursor = LoadCursorA( 0, (LPSTR)descr->cursor );
323 init_class_name( &name, descr->name );
324 if (!NtUserRegisterClassExWOW( &class, &name, &version, &menu_name, 1, 0, NULL ) && class.hCursor)
325 DestroyCursor( class.hCursor );
328 static void load_uxtheme(void)
330 BOOL (WINAPI * pIsThemeActive)(void);
331 HMODULE uxtheme;
333 uxtheme = LoadLibraryA("uxtheme.dll");
334 if (uxtheme)
336 pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive");
337 if (!pIsThemeActive || !pIsThemeActive())
338 FreeLibrary(uxtheme);
342 /***********************************************************************
343 * register_builtins
345 static BOOL WINAPI register_builtins( INIT_ONCE *once, void *param, void **context )
347 register_builtin( &BUTTON_builtin_class );
348 register_builtin( &COMBO_builtin_class );
349 register_builtin( &COMBOLBOX_builtin_class );
350 register_builtin( &DIALOG_builtin_class );
351 register_builtin( &EDIT_builtin_class );
352 register_builtin( &ICONTITLE_builtin_class );
353 register_builtin( &LISTBOX_builtin_class );
354 register_builtin( &MDICLIENT_builtin_class );
355 register_builtin( &MENU_builtin_class );
356 register_builtin( &SCROLL_builtin_class );
357 register_builtin( &STATIC_builtin_class );
358 register_builtin( &IME_builtin_class );
360 /* Load uxtheme.dll so that standard scrollbars and dialogs are hooked for theming support */
361 load_uxtheme();
362 return TRUE;
366 /***********************************************************************
367 * register_builtin_classes
369 void register_builtin_classes(void)
371 InitOnceExecuteOnce( &init_once, register_builtins, NULL, NULL );
375 /***********************************************************************
376 * register_desktop_class
378 void register_desktop_class(void)
380 register_builtin( &DESKTOP_builtin_class );
381 register_builtin( &MESSAGE_builtin_class );
385 /***********************************************************************
386 * get_class_winproc
388 WNDPROC get_class_winproc( CLASS *class )
390 return class->winproc;
394 /***********************************************************************
395 * get_class_dce
397 struct dce *get_class_dce( CLASS *class )
399 return class->dce;
403 /***********************************************************************
404 * set_class_dce
406 struct dce *set_class_dce( CLASS *class, struct dce *dce )
408 if (class->dce) return class->dce; /* already set, don't change it */
409 class->dce = dce;
410 return dce;
414 /***********************************************************************
415 * RegisterClassA (USER32.@)
417 * Register a window class.
419 * RETURNS
420 * >0: Unique identifier
421 * 0: Failure
423 ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
425 WNDCLASSEXA wcex;
427 wcex.cbSize = sizeof(wcex);
428 wcex.style = wc->style;
429 wcex.lpfnWndProc = wc->lpfnWndProc;
430 wcex.cbClsExtra = wc->cbClsExtra;
431 wcex.cbWndExtra = wc->cbWndExtra;
432 wcex.hInstance = wc->hInstance;
433 wcex.hIcon = wc->hIcon;
434 wcex.hCursor = wc->hCursor;
435 wcex.hbrBackground = wc->hbrBackground;
436 wcex.lpszMenuName = wc->lpszMenuName;
437 wcex.lpszClassName = wc->lpszClassName;
438 wcex.hIconSm = 0;
439 return RegisterClassExA( &wcex );
443 /***********************************************************************
444 * RegisterClassW (USER32.@)
446 * See RegisterClassA.
448 ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
450 WNDCLASSEXW wcex;
452 wcex.cbSize = sizeof(wcex);
453 wcex.style = wc->style;
454 wcex.lpfnWndProc = wc->lpfnWndProc;
455 wcex.cbClsExtra = wc->cbClsExtra;
456 wcex.cbWndExtra = wc->cbWndExtra;
457 wcex.hInstance = wc->hInstance;
458 wcex.hIcon = wc->hIcon;
459 wcex.hCursor = wc->hCursor;
460 wcex.hbrBackground = wc->hbrBackground;
461 wcex.lpszMenuName = wc->lpszMenuName;
462 wcex.lpszClassName = wc->lpszClassName;
463 wcex.hIconSm = 0;
464 return RegisterClassExW( &wcex );
468 /***********************************************************************
469 * RegisterClassExA (USER32.@)
471 ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
473 WCHAR nameW[MAX_ATOM_LEN + 1], combined[MAX_ATOM_LEN + 1];
474 struct client_menu_name menu_name;
475 UNICODE_STRING name, version;
476 ATOM atom;
478 version.Buffer = combined;
479 version.MaximumLength = sizeof(combined);
480 if (!IS_INTRESOURCE(wc->lpszClassName))
482 if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, nameW, MAX_ATOM_LEN + 1 )) return 0;
483 get_versioned_name( nameW, &name, &version, FALSE );
485 else
487 init_class_name( &name, (const WCHAR *)wc->lpszClassName );
488 version.Length = 0;
491 if (!alloc_menu_nameA( &menu_name, wc->lpszMenuName )) return 0;
493 atom = NtUserRegisterClassExWOW( (WNDCLASSEXW *)wc, &name, &version, &menu_name, 0, 1, NULL );
494 if (!atom) free_menu_name( &menu_name );
495 return atom;
499 /***********************************************************************
500 * RegisterClassExW (USER32.@)
502 ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
504 WCHAR combined[MAX_ATOM_LEN + 1];
505 struct client_menu_name menu_name;
506 UNICODE_STRING name, version;
507 ATOM atom;
509 version.Buffer = combined;
510 version.MaximumLength = sizeof(combined);
511 get_versioned_name( wc->lpszClassName, &name, &version, FALSE );
513 if (!alloc_menu_nameW( &menu_name, wc->lpszMenuName )) return 0;
515 atom = NtUserRegisterClassExWOW( wc, &name, &version, &menu_name, 0, 0, NULL );
516 if (!atom) free_menu_name( &menu_name );
517 return atom;
521 /***********************************************************************
522 * UnregisterClassA (USER32.@)
524 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
526 if (!IS_INTRESOURCE(className))
528 WCHAR name[MAX_ATOM_LEN + 1];
530 if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
531 return FALSE;
532 return UnregisterClassW( name, hInstance );
534 return UnregisterClassW( (LPCWSTR)className, hInstance );
537 /***********************************************************************
538 * UnregisterClassW (USER32.@)
540 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
542 struct client_menu_name menu_name;
543 UNICODE_STRING name;
544 BOOL ret;
546 get_versioned_name( className, &name, NULL, FALSE );
547 ret = NtUserUnregisterClass( &name, hInstance, &menu_name );
548 if (ret) free_menu_name( &menu_name );
549 return ret;
553 /***********************************************************************
554 * GetClassWord (USER32.@)
556 WORD WINAPI GetClassWord( HWND hwnd, INT offset )
558 CLASS *class;
559 WORD retvalue = 0;
561 if (offset < 0) return GetClassLongA( hwnd, offset );
563 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
565 if (class == CLASS_OTHER_PROCESS)
567 SERVER_START_REQ( set_class_info )
569 req->window = wine_server_user_handle( hwnd );
570 req->flags = 0;
571 req->extra_offset = offset;
572 req->extra_size = sizeof(retvalue);
573 if (!wine_server_call_err( req ))
574 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
576 SERVER_END_REQ;
577 return retvalue;
580 if (offset <= class->cbClsExtra - sizeof(WORD))
581 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
582 else
583 SetLastError( ERROR_INVALID_INDEX );
584 release_class_ptr( class );
585 return retvalue;
589 /***********************************************************************
590 * CLASS_GetClassLong
592 * Implementation of GetClassLong(Ptr)A/W
594 static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
595 BOOL unicode )
597 CLASS *class;
598 ULONG_PTR retvalue = 0;
600 if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
602 if (class == CLASS_OTHER_PROCESS)
604 SERVER_START_REQ( set_class_info )
606 req->window = wine_server_user_handle( hwnd );
607 req->flags = 0;
608 req->extra_offset = (offset >= 0) ? offset : -1;
609 req->extra_size = (offset >= 0) ? size : 0;
610 if (!wine_server_call_err( req ))
612 switch(offset)
614 case GCLP_HBRBACKGROUND:
615 case GCLP_HCURSOR:
616 case GCLP_HICON:
617 case GCLP_HICONSM:
618 case GCLP_WNDPROC:
619 case GCLP_MENUNAME:
620 FIXME( "offset %d (%s) not supported on other process window %p\n",
621 offset, SPY_GetClassLongOffsetName(offset), hwnd );
622 SetLastError( ERROR_INVALID_HANDLE );
623 break;
624 case GCL_STYLE:
625 retvalue = reply->old_style;
626 break;
627 case GCL_CBWNDEXTRA:
628 retvalue = reply->old_win_extra;
629 break;
630 case GCL_CBCLSEXTRA:
631 retvalue = reply->old_extra;
632 break;
633 case GCLP_HMODULE:
634 retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
635 break;
636 case GCW_ATOM:
637 retvalue = reply->old_atom;
638 break;
639 default:
640 if (offset >= 0)
642 if (size == sizeof(DWORD))
644 DWORD retdword;
645 memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
646 retvalue = retdword;
648 else
649 memcpy( &retvalue, &reply->old_extra_value,
650 sizeof(ULONG_PTR) );
652 else SetLastError( ERROR_INVALID_INDEX );
653 break;
657 SERVER_END_REQ;
658 return retvalue;
661 if (offset >= 0)
663 if (offset <= class->cbClsExtra - size)
665 if (size == sizeof(DWORD))
667 DWORD retdword;
668 memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
669 retvalue = retdword;
671 else
672 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
674 else
675 SetLastError( ERROR_INVALID_INDEX );
676 release_class_ptr( class );
677 return retvalue;
680 switch(offset)
682 case GCLP_HBRBACKGROUND:
683 retvalue = (ULONG_PTR)class->hbrBackground;
684 break;
685 case GCLP_HCURSOR:
686 retvalue = (ULONG_PTR)class->hCursor;
687 break;
688 case GCLP_HICON:
689 retvalue = (ULONG_PTR)class->hIcon;
690 break;
691 case GCLP_HICONSM:
692 retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern);
693 break;
694 case GCL_STYLE:
695 retvalue = class->style;
696 break;
697 case GCL_CBWNDEXTRA:
698 retvalue = class->cbWndExtra;
699 break;
700 case GCL_CBCLSEXTRA:
701 retvalue = class->cbClsExtra;
702 break;
703 case GCLP_HMODULE:
704 retvalue = class->instance;
705 break;
706 case GCLP_WNDPROC:
707 retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
708 break;
709 case GCLP_MENUNAME:
710 if (unicode)
711 retvalue = (ULONG_PTR)class->menu_name.nameW;
712 else
713 retvalue = (ULONG_PTR)class->menu_name.nameA;
714 break;
715 case GCW_ATOM:
716 retvalue = class->atomName;
717 break;
718 default:
719 SetLastError( ERROR_INVALID_INDEX );
720 break;
722 release_class_ptr( class );
723 return retvalue;
727 /***********************************************************************
728 * GetClassLongW (USER32.@)
730 DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
732 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
737 /***********************************************************************
738 * GetClassLongA (USER32.@)
740 DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
742 return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
746 /***********************************************************************
747 * SetClassLongW (USER32.@)
749 DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
751 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
752 return NtUserSetClassLong( hwnd, offset, newval, FALSE );
756 /***********************************************************************
757 * SetClassLongA (USER32.@)
759 DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
761 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
762 return NtUserSetClassLong( hwnd, offset, newval, TRUE );
766 /***********************************************************************
767 * GetClassNameA (USER32.@)
769 INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
771 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
772 DWORD len;
774 if (count <= 0) return 0;
775 if (!GetClassNameW( hwnd, tmpbuf, ARRAY_SIZE( tmpbuf ))) return 0;
776 RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, lstrlenW(tmpbuf) * sizeof(WCHAR) );
777 buffer[len] = 0;
778 return len;
782 /***********************************************************************
783 * GetClassNameW (USER32.@)
785 INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
787 UNICODE_STRING name = { .Buffer = buffer, .MaximumLength = count * sizeof(WCHAR) };
788 return NtUserGetClassName( hwnd, FALSE, &name );
792 /***********************************************************************
793 * RealGetWindowClassA (USER32.@)
795 UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
797 return GetClassNameA( hwnd, buffer, count );
801 /***********************************************************************
802 * RealGetWindowClassW (USER32.@)
804 UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
806 return GetClassNameW( hwnd, buffer, count );
810 /***********************************************************************
811 * GetClassInfoA (USER32.@)
813 BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
815 WNDCLASSEXA wcex;
816 UINT ret = GetClassInfoExA( hInstance, name, &wcex );
818 if (ret)
820 wc->style = wcex.style;
821 wc->lpfnWndProc = wcex.lpfnWndProc;
822 wc->cbClsExtra = wcex.cbClsExtra;
823 wc->cbWndExtra = wcex.cbWndExtra;
824 wc->hInstance = wcex.hInstance;
825 wc->hIcon = wcex.hIcon;
826 wc->hCursor = wcex.hCursor;
827 wc->hbrBackground = wcex.hbrBackground;
828 wc->lpszMenuName = wcex.lpszMenuName;
829 wc->lpszClassName = wcex.lpszClassName;
831 return ret;
835 /***********************************************************************
836 * GetClassInfoW (USER32.@)
838 BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
840 WNDCLASSEXW wcex;
841 UINT ret = GetClassInfoExW( hInstance, name, &wcex );
843 if (ret)
845 wc->style = wcex.style;
846 wc->lpfnWndProc = wcex.lpfnWndProc;
847 wc->cbClsExtra = wcex.cbClsExtra;
848 wc->cbWndExtra = wcex.cbWndExtra;
849 wc->hInstance = wcex.hInstance;
850 wc->hIcon = wcex.hIcon;
851 wc->hCursor = wcex.hCursor;
852 wc->hbrBackground = wcex.hbrBackground;
853 wc->lpszMenuName = wcex.lpszMenuName;
854 wc->lpszClassName = wcex.lpszClassName;
856 return ret;
859 ATOM get_class_info( HINSTANCE instance, const WCHAR *class_name, WNDCLASSEXW *info,
860 UNICODE_STRING *name_str, BOOL ansi )
862 UNICODE_STRING name;
863 HMODULE module;
864 ATOM atom;
866 get_versioned_name( class_name, &name, NULL, &module );
868 if (!name_str && !instance) instance = user32_module;
870 while (!(atom = NtUserGetClassInfoEx( instance, &name, info, NULL, ansi )))
872 if (module)
874 BOOL (WINAPI *pRegisterClassNameW)( const WCHAR *class );
875 pRegisterClassNameW = (void *)GetProcAddress( module, "RegisterClassNameW" );
876 module = NULL;
877 if (pRegisterClassNameW)
879 TRACE( "registering %s\n", debugstr_us(&name) );
880 pRegisterClassNameW( class_name );
881 continue;
884 if (IS_INTRESOURCE( class_name )) break;
885 if (!is_comctl32_class( class_name )) break;
886 if (GetModuleHandleW( L"comctl32.dll" )) break;
887 if (!LoadLibraryW( L"comctl32.dll" )) break;
888 TRACE( "%s retrying after loading comctl32\n", debugstr_w(class_name) );
891 if (!atom)
893 TRACE( "%s %p -> not found\n", debugstr_w(class_name), instance );
894 SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
895 return 0;
898 if (name_str) *name_str = name;
899 return atom;
902 /***********************************************************************
903 * GetClassInfoExA (USER32.@)
905 BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
907 ATOM atom;
909 TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
911 if (!wc)
913 SetLastError( ERROR_NOACCESS );
914 return FALSE;
917 if (!IS_INTRESOURCE(name))
919 WCHAR nameW[MAX_ATOM_LEN + 1];
920 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE( nameW )))
921 return FALSE;
922 atom = get_class_info( hInstance, nameW, (WNDCLASSEXW *)wc, NULL, TRUE );
924 else atom = get_class_info( hInstance, (const WCHAR *)name, (WNDCLASSEXW *)wc, NULL, TRUE );
925 if (atom) wc->lpszClassName = name;
927 /* We must return the atom of the class here instead of just TRUE. */
928 return atom;
932 /***********************************************************************
933 * GetClassInfoExW (USER32.@)
935 BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
937 ATOM atom;
939 TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
941 if (!wc)
943 SetLastError( ERROR_NOACCESS );
944 return FALSE;
947 atom = get_class_info( hInstance, name, wc, NULL, FALSE );
948 if (atom) wc->lpszClassName = name;
950 /* We must return the atom of the class here instead of just TRUE. */
951 return atom;
955 #if 0 /* toolhelp is in kernel, so this cannot work */
957 /***********************************************************************
958 * ClassFirst (TOOLHELP.69)
960 BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
962 TRACE("%p\n",pClassEntry);
963 pClassEntry->wNext = 1;
964 return ClassNext16( pClassEntry );
968 /***********************************************************************
969 * ClassNext (TOOLHELP.70)
971 BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
973 int i;
974 CLASS *class = firstClass;
976 TRACE("%p\n",pClassEntry);
978 if (!pClassEntry->wNext) return FALSE;
979 for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
980 if (!class)
982 pClassEntry->wNext = 0;
983 return FALSE;
985 pClassEntry->hInst = class->hInstance;
986 pClassEntry->wNext++;
987 GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
988 sizeof(pClassEntry->szClassName) );
989 return TRUE;
991 #endif
993 /* 64bit versions */
995 #ifdef GetClassLongPtrA
996 #undef GetClassLongPtrA
997 #endif
999 #ifdef GetClassLongPtrW
1000 #undef GetClassLongPtrW
1001 #endif
1003 #ifdef SetClassLongPtrA
1004 #undef SetClassLongPtrA
1005 #endif
1007 #ifdef SetClassLongPtrW
1008 #undef SetClassLongPtrW
1009 #endif
1011 /***********************************************************************
1012 * GetClassLongPtrA (USER32.@)
1014 ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
1016 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1019 /***********************************************************************
1020 * GetClassLongPtrW (USER32.@)
1022 ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
1024 return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1027 /***********************************************************************
1028 * SetClassLongPtrW (USER32.@)
1030 ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
1032 if (offset == GCLP_MENUNAME) return set_menu_nameW( hwnd, offset, newval );
1033 return NtUserSetClassLongPtr( hwnd, offset, newval, FALSE );
1036 /***********************************************************************
1037 * SetClassLongPtrA (USER32.@)
1039 ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
1041 if (offset == GCLP_MENUNAME) return set_menu_nameA( hwnd, offset, newval );
1042 return NtUserSetClassLongPtr( hwnd, offset, newval, TRUE );