class.c 41.7 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Window classes functions
 *
4 5
 * Copyright 1993, 1996, 2003 Alexandre Julliard
 * Copyright 1998 Juergen Schmied (jsch)
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
20
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
21

22
#include "config.h"
23 24
#include "wine/port.h"

25
#include <assert.h>
26
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27 28
#include <stdlib.h>
#include <string.h>
29

30 31
#include "winerror.h"
#include "windef.h"
32
#include "winbase.h"
33 34
#include "wingdi.h"
#include "wine/unicode.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#include "win.h"
36
#include "user_private.h"
37
#include "controls.h"
38 39
#include "wine/server.h"
#include "wine/list.h"
40
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
41

42
WINE_DEFAULT_DEBUG_CHANNEL(class);
43

44 45
#define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */

46 47
typedef struct tagCLASS
{
48
    struct list      entry;         /* Entry in class list */
49
    UINT             style;         /* Class style */
50
    BOOL             local;         /* Local class? */
51
    WNDPROC          winproc;       /* Window procedure */
52 53 54
    INT              cbClsExtra;    /* Class extra bytes */
    INT              cbWndExtra;    /* Window extra bytes */
    LPWSTR           menuName;      /* Default menu name (Unicode followed by ASCII) */
55
    struct dce      *dce;           /* Opaque pointer to class DCE */
56 57 58
    HINSTANCE        hInstance;     /* Module that created the task */
    HICON            hIcon;         /* Default icon */
    HICON            hIconSm;       /* Default small icon */
59
    HICON            hIconSmIntern; /* Internal small icon, derived from hIcon */
60 61 62
    HCURSOR          hCursor;       /* Default cursor */
    HBRUSH           hbrBackground; /* Default background */
    ATOM             atomName;      /* Name of the class */
63
    WCHAR            name[MAX_ATOM_LEN + 1];
64 65
} CLASS;

66
static struct list class_list = LIST_INIT( class_list );
67
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
68 69

#define CLASS_OTHER_PROCESS ((CLASS *)1)
Alexandre Julliard's avatar
Alexandre Julliard committed
70

71 72 73
/***********************************************************************
 *           get_class_ptr
 */
74
static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
75
{
76
    WND *ptr = WIN_GetPtr( hwnd );
77

78
    if (ptr)
79
    {
80
        if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
81
        if (!write_access) return CLASS_OTHER_PROCESS;
82

83 84
        /* modifying classes in other processes is not allowed */
        if (ptr == WND_DESKTOP || IsWindow( hwnd ))
85
        {
86 87
            SetLastError( ERROR_ACCESS_DENIED );
            return NULL;
88 89
        }
    }
90 91
    SetLastError( ERROR_INVALID_WINDOW_HANDLE );
    return NULL;
92 93 94 95 96 97
}


/***********************************************************************
 *           release_class_ptr
 */
98
static inline void release_class_ptr( CLASS *ptr )
99 100 101 102
{
    USER_Unlock();
}

Alexandre Julliard's avatar
Alexandre Julliard committed
103

104 105 106
/***********************************************************************
 *           get_int_atom_value
 */
107
ATOM get_int_atom_value( LPCWSTR name )
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
{
    UINT ret = 0;

    if (IS_INTRESOURCE(name)) return LOWORD(name);
    if (*name++ != '#') return 0;
    while (*name)
    {
        if (*name < '0' || *name > '9') return 0;
        ret = ret * 10 + *name++ - '0';
        if (ret > 0xffff) return 0;
    }
    return ret;
}


123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
/***********************************************************************
 *           is_comctl32_class
 */
static BOOL is_comctl32_class( const WCHAR *name )
{
    static const WCHAR classesW[][20] =
    {
        {'C','o','m','b','o','B','o','x','E','x','3','2',0},
        {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
        {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
        {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
        {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
        {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
        {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
        {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
        {'S','y','s','A','n','i','m','a','t','e','3','2',0},
        {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
        {'S','y','s','H','e','a','d','e','r','3','2',0},
        {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
        {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
        {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
        {'S','y','s','P','a','g','e','r',0},
        {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
        {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
        {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
        {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
    };

    int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;

    while (min <= max)
    {
        int res, pos = (min + max) / 2;
        if (!(res = strcmpiW( name, classesW[pos] ))) return TRUE;
        if (res < 0) max = pos - 1;
        else min = pos + 1;
    }
    return FALSE;
}


164 165 166 167 168
/***********************************************************************
 *           set_server_info
 *
 * Set class info with the wine server.
 */
169
static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
170 171 172 173 174
{
    BOOL ret;

    SERVER_START_REQ( set_class_info )
    {
175
        req->window = wine_server_user_handle( hwnd );
176 177 178 179 180
        req->extra_offset = -1;
        switch(offset)
        {
        case GCW_ATOM:
            req->flags = SET_CLASS_ATOM;
181
            req->atom = LOWORD(newval);
182
            break;
183 184 185 186 187 188 189 190
        case GCL_STYLE:
            req->flags = SET_CLASS_STYLE;
            req->style = newval;
            break;
        case GCL_CBWNDEXTRA:
            req->flags = SET_CLASS_WINEXTRA;
            req->win_extra = newval;
            break;
191
        case GCLP_HMODULE:
192
            req->flags = SET_CLASS_INSTANCE;
193
            req->instance = wine_server_client_ptr( (void *)newval );
194 195 196 197 198
            break;
        default:
            assert( offset >= 0 );
            req->flags = SET_CLASS_EXTRA;
            req->extra_offset = offset;
199 200 201 202 203 204 205 206
            req->extra_size = size;
            if ( size == sizeof(LONG) )
            {
                LONG newlong = newval;
                memcpy( &req->extra_value, &newlong, sizeof(LONG) );
            }
            else
                memcpy( &req->extra_value, &newval, sizeof(LONG_PTR) );
207 208 209 210 211 212 213 214 215
            break;
        }
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
216 217 218 219 220
/***********************************************************************
 *           CLASS_GetMenuNameA
 *
 * Get the menu name as a ASCII string.
 */
221
static inline LPSTR CLASS_GetMenuNameA( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
222
{
223
    if (IS_INTRESOURCE(classPtr->menuName)) return (LPSTR)classPtr->menuName;
224
    return (LPSTR)(classPtr->menuName + strlenW(classPtr->menuName) + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
225 226 227 228 229 230 231 232
}


/***********************************************************************
 *           CLASS_GetMenuNameW
 *
 * Get the menu name as a Unicode string.
 */
233
static inline LPWSTR CLASS_GetMenuNameW( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
234
{
235
    return classPtr->menuName;
Alexandre Julliard's avatar
Alexandre Julliard committed
236 237 238 239 240 241 242 243 244 245
}


/***********************************************************************
 *           CLASS_SetMenuNameA
 *
 * Set the menu name in a class structure by copying the string.
 */
static void CLASS_SetMenuNameA( CLASS *classPtr, LPCSTR name )
{
246 247
    if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
    if (!IS_INTRESOURCE(name))
248 249 250
    {
        DWORD lenA = strlen(name) + 1;
        DWORD lenW = MultiByteToWideChar( CP_ACP, 0, name, lenA, NULL, 0 );
251
        classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
252 253 254 255
        MultiByteToWideChar( CP_ACP, 0, name, lenA, classPtr->menuName, lenW );
        memcpy( classPtr->menuName + lenW, name, lenA );
    }
    else classPtr->menuName = (LPWSTR)name;
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257 258 259 260 261 262 263 264 265
}


/***********************************************************************
 *           CLASS_SetMenuNameW
 *
 * Set the menu name in a class structure by copying the string.
 */
static void CLASS_SetMenuNameW( CLASS *classPtr, LPCWSTR name )
{
266 267
    if (!IS_INTRESOURCE(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
    if (!IS_INTRESOURCE(name))
268
    {
269 270
        DWORD lenW = strlenW(name) + 1;
        DWORD lenA = WideCharToMultiByte( CP_ACP, 0, name, lenW, NULL, 0, NULL, NULL );
271
        classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
272 273 274
        memcpy( classPtr->menuName, name, lenW*sizeof(WCHAR) );
        WideCharToMultiByte( CP_ACP, 0, name, lenW,
                             (char *)(classPtr->menuName + lenW), lenA, NULL, NULL );
275
    }
276
    else classPtr->menuName = (LPWSTR)name;
277 278 279
}


Alexandre Julliard's avatar
Alexandre Julliard committed
280 281 282 283 284
/***********************************************************************
 *           CLASS_FreeClass
 *
 * Free a class structure.
 */
285
static void CLASS_FreeClass( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
286
{
287
    TRACE("%p\n", classPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
288

289
    USER_Lock();
290

291
    if (classPtr->dce) free_dce( classPtr->dce, 0 );
292 293 294 295 296 297
    list_remove( &classPtr->entry );
    if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
        DeleteObject( classPtr->hbrBackground );
    HeapFree( GetProcessHeap(), 0, classPtr->menuName );
    HeapFree( GetProcessHeap(), 0, classPtr );
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
298 299 300
}


Alexandre Julliard's avatar
Alexandre Julliard committed
301
/***********************************************************************
302
 *           CLASS_FindClass
Alexandre Julliard's avatar
Alexandre Julliard committed
303
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
304
 * Return a pointer to the class.
Alexandre Julliard's avatar
Alexandre Julliard committed
305
 */
306
static CLASS *CLASS_FindClass( LPCWSTR name, HINSTANCE hinstance )
307
{
308
    static const WCHAR comctl32W[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0};
309
    struct list *ptr;
310
    ATOM atom = get_int_atom_value( name );
Alexandre Julliard's avatar
Alexandre Julliard committed
311

312 313
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */

314 315
    if (!name) return NULL;

316
    for (;;)
Alexandre Julliard's avatar
Alexandre Julliard committed
317
    {
318 319 320
        USER_Lock();

        LIST_FOR_EACH( ptr, &class_list )
Alexandre Julliard's avatar
Alexandre Julliard committed
321
        {
322 323 324 325 326 327 328
            CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
            if (atom)
            {
                if (class->atomName != atom) continue;
            }
            else
            {
329
                if (strcmpiW( class->name, name )) continue;
330 331 332 333 334 335
            }
            if (!class->local || class->hInstance == hinstance)
            {
                TRACE("%s %p -> %p\n", debugstr_w(name), hinstance, class);
                return class;
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
336
        }
337 338
        USER_Unlock();

339
        if (atom) break;
340 341 342 343
        if (!is_comctl32_class( name )) break;
        if (GetModuleHandleW( comctl32W )) break;
        if (!LoadLibraryW( comctl32W )) break;
        TRACE( "%s retrying after loading comctl32\n", debugstr_w(name) );
Alexandre Julliard's avatar
Alexandre Julliard committed
344
    }
345

346
    TRACE("%s %p -> not found\n", debugstr_w(name), hinstance);
347
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
348 349
}

Alexandre Julliard's avatar
Alexandre Julliard committed
350

Alexandre Julliard's avatar
Alexandre Julliard committed
351
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
352 353 354
 *           CLASS_RegisterClass
 *
 * The real RegisterClass() functionality.
Alexandre Julliard's avatar
Alexandre Julliard committed
355
 */
356
static CLASS *CLASS_RegisterClass( LPCWSTR name, HINSTANCE hInstance, BOOL local,
357
                                   DWORD style, INT classExtra, INT winExtra )
Alexandre Julliard's avatar
Alexandre Julliard committed
358
{
Alexandre Julliard's avatar
Alexandre Julliard committed
359
    CLASS *classPtr;
360
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
361

362 363
    TRACE("name=%s hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
          debugstr_w(name), hInstance, style, classExtra, winExtra );
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365 366

    /* Fix the extra bytes value */

367
    if (classExtra > 40)  /* Extra bytes are limited to 40 in Win32 */
368
        WARN("Class extra bytes %d is > 40\n", classExtra);
369
    if (winExtra > 40)    /* Extra bytes are limited to 40 in Win32 */
370
        WARN("Win extra bytes %d is > 40\n", winExtra );
Alexandre Julliard's avatar
Alexandre Julliard committed
371

372
    classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
373
    if (!classPtr) return NULL;
374

375 376 377 378
    classPtr->atomName = get_int_atom_value( name );
    if (!classPtr->atomName && name) strcpyW( classPtr->name, name );
    else GlobalGetAtomNameW( classPtr->atomName, classPtr->name, sizeof(classPtr->name)/sizeof(WCHAR) );

379 380
    SERVER_START_REQ( create_class )
    {
381 382
        req->local      = local;
        req->style      = style;
383
        req->instance   = wine_server_client_ptr( hInstance );
384 385
        req->extra      = classExtra;
        req->win_extra  = winExtra;
386
        req->client_ptr = wine_server_client_ptr( classPtr );
387 388
        req->atom       = classPtr->atomName;
        if (!req->atom && name) wine_server_add_data( req, name, strlenW(name) * sizeof(WCHAR) );
389
        ret = !wine_server_call_err( req );
390
        classPtr->atomName = reply->atom;
391 392 393 394 395 396 397 398
    }
    SERVER_END_REQ;
    if (!ret)
    {
        HeapFree( GetProcessHeap(), 0, classPtr );
        return NULL;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
399
    classPtr->style       = style;
400
    classPtr->local       = local;
Alexandre Julliard's avatar
Alexandre Julliard committed
401 402 403
    classPtr->cbWndExtra  = winExtra;
    classPtr->cbClsExtra  = classExtra;
    classPtr->hInstance   = hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
404

405
    /* Other non-null values must be set by caller */
Alexandre Julliard's avatar
Alexandre Julliard committed
406

407
    USER_Lock();
408 409
    if (local) list_add_head( &class_list, &classPtr->entry );
    else list_add_tail( &class_list, &classPtr->entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
410 411 412 413
    return classPtr;
}


414
/***********************************************************************
415
 *           register_builtin
416 417 418 419
 *
 * Register a builtin control class.
 * This allows having both ASCII and Unicode winprocs for the same class.
 */
420
static void register_builtin( const struct builtin_class_descr *descr )
421 422 423
{
    CLASS *classPtr;

424
    if (!(classPtr = CLASS_RegisterClass( descr->name, user32_module, FALSE,
425
                                          descr->style, 0, descr->extra ))) return;
426

427
    if (descr->cursor) classPtr->hCursor = LoadCursorA( 0, (LPSTR)descr->cursor );
428
    classPtr->hbrBackground = descr->brush;
429
    classPtr->winproc       = BUILTIN_WINPROC( descr->proc );
430
    release_class_ptr( classPtr );
431 432 433
}


434
/***********************************************************************
435
 *           register_builtins
436
 */
437
static BOOL WINAPI register_builtins( INIT_ONCE *once, void *param, void **context )
438 439 440 441 442
{
    register_builtin( &BUTTON_builtin_class );
    register_builtin( &COMBO_builtin_class );
    register_builtin( &COMBOLBOX_builtin_class );
    register_builtin( &DIALOG_builtin_class );
443
    register_builtin( &EDIT_builtin_class );
444 445 446 447 448 449
    register_builtin( &ICONTITLE_builtin_class );
    register_builtin( &LISTBOX_builtin_class );
    register_builtin( &MDICLIENT_builtin_class );
    register_builtin( &MENU_builtin_class );
    register_builtin( &SCROLL_builtin_class );
    register_builtin( &STATIC_builtin_class );
450
    register_builtin( &IME_builtin_class );
451 452 453 454 455
    return TRUE;
}


/***********************************************************************
456
 *           register_builtin_classes
457
 */
458
void register_builtin_classes(void)
459 460
{
    InitOnceExecuteOnce( &init_once, register_builtins, NULL, NULL );
461 462 463
}


464 465 466 467 468 469 470 471 472 473
/***********************************************************************
 *           register_desktop_class
 */
void register_desktop_class(void)
{
    register_builtin( &DESKTOP_builtin_class );
    register_builtin( &MESSAGE_builtin_class );
}


474
/***********************************************************************
475
 *           get_class_winproc
476
 */
477
WNDPROC get_class_winproc( CLASS *class )
478
{
479
    return class->winproc;
480 481 482
}


483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
/***********************************************************************
 *           get_class_dce
 */
struct dce *get_class_dce( CLASS *class )
{
    return class->dce;
}


/***********************************************************************
 *           set_class_dce
 */
struct dce *set_class_dce( CLASS *class, struct dce *dce )
{
    if (class->dce) return class->dce;  /* already set, don't change it */
    class->dce = dce;
    return dce;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
503
/***********************************************************************
504
 *		RegisterClassA (USER32.@)
505 506 507
 *
 * Register a window class.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
508 509 510
 * RETURNS
 *	>0: Unique identifier
 *	0: Failure
Alexandre Julliard's avatar
Alexandre Julliard committed
511
 */
512
ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
513
{
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    WNDCLASSEXA wcex;

    wcex.cbSize        = sizeof(wcex);
    wcex.style         = wc->style;
    wcex.lpfnWndProc   = wc->lpfnWndProc;
    wcex.cbClsExtra    = wc->cbClsExtra;
    wcex.cbWndExtra    = wc->cbWndExtra;
    wcex.hInstance     = wc->hInstance;
    wcex.hIcon         = wc->hIcon;
    wcex.hCursor       = wc->hCursor;
    wcex.hbrBackground = wc->hbrBackground;
    wcex.lpszMenuName  = wc->lpszMenuName;
    wcex.lpszClassName = wc->lpszClassName;
    wcex.hIconSm       = 0;
    return RegisterClassExA( &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
529
}
Alexandre Julliard's avatar
Alexandre Julliard committed
530

Alexandre Julliard's avatar
Alexandre Julliard committed
531 532

/***********************************************************************
533
 *		RegisterClassW (USER32.@)
534 535
 *
 * See RegisterClassA.
Alexandre Julliard's avatar
Alexandre Julliard committed
536
 */
537
ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
538
{
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    WNDCLASSEXW wcex;

    wcex.cbSize        = sizeof(wcex);
    wcex.style         = wc->style;
    wcex.lpfnWndProc   = wc->lpfnWndProc;
    wcex.cbClsExtra    = wc->cbClsExtra;
    wcex.cbWndExtra    = wc->cbWndExtra;
    wcex.hInstance     = wc->hInstance;
    wcex.hIcon         = wc->hIcon;
    wcex.hCursor       = wc->hCursor;
    wcex.hbrBackground = wc->hbrBackground;
    wcex.lpszMenuName  = wc->lpszMenuName;
    wcex.lpszClassName = wc->lpszClassName;
    wcex.hIconSm       = 0;
    return RegisterClassExW( &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
554 555 556 557
}


/***********************************************************************
558
 *		RegisterClassExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
559
 */
560
ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
561 562 563
{
    ATOM atom;
    CLASS *classPtr;
564 565
    HINSTANCE instance;

566
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
567

568
    if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
569
        wc->hInstance == user32_module)  /* we can't register a class for user32 */
570
    {
571 572
         SetLastError( ERROR_INVALID_PARAMETER );
         return 0;
573 574
    }
    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
575

576 577 578
    if (!IS_INTRESOURCE(wc->lpszClassName))
    {
        WCHAR name[MAX_ATOM_LEN + 1];
579

580 581 582 583 584 585 586 587 588 589 590 591
        if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, name, MAX_ATOM_LEN + 1 )) return 0;
        classPtr = CLASS_RegisterClass( name, instance, !(wc->style & CS_GLOBALCLASS),
                                        wc->style, wc->cbClsExtra, wc->cbWndExtra );
    }
    else
    {
        classPtr = CLASS_RegisterClass( (LPCWSTR)wc->lpszClassName, instance,
                                        !(wc->style & CS_GLOBALCLASS), wc->style,
                                        wc->cbClsExtra, wc->cbWndExtra );
    }
    if (!classPtr) return 0;
    atom = classPtr->atomName;
Alexandre Julliard's avatar
Alexandre Julliard committed
592

593 594
    TRACE("name=%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
          debugstr_a(wc->lpszClassName), atom, wc->lpfnWndProc, instance, wc->hbrBackground,
595
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
596

597 598
    classPtr->hIcon         = wc->hIcon;
    classPtr->hIconSm       = wc->hIconSm;
599 600 601 602
    classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
                                            CopyImage( wc->hIcon, IMAGE_ICON,
                                                GetSystemMetrics( SM_CXSMICON ),
                                                GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
603 604
    classPtr->hCursor       = wc->hCursor;
    classPtr->hbrBackground = wc->hbrBackground;
605
    classPtr->winproc       = WINPROC_AllocProc( wc->lpfnWndProc, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
606
    CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
607
    release_class_ptr( classPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
608 609 610 611 612
    return atom;
}


/***********************************************************************
613
 *		RegisterClassExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
614
 */
615
ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
616 617 618
{
    ATOM atom;
    CLASS *classPtr;
619 620
    HINSTANCE instance;

621
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
622

623
    if (wc->cbSize != sizeof(*wc) || wc->cbClsExtra < 0 || wc->cbWndExtra < 0 ||
624
        wc->hInstance == user32_module)  /* we can't register a class for user32 */
625
    {
626 627
         SetLastError( ERROR_INVALID_PARAMETER );
         return 0;
628 629
    }
    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
630

631
    if (!(classPtr = CLASS_RegisterClass( wc->lpszClassName, instance, !(wc->style & CS_GLOBALCLASS),
632
                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
Alexandre Julliard's avatar
Alexandre Julliard committed
633 634
        return 0;

635 636 637 638
    atom = classPtr->atomName;

    TRACE("name=%s atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
          debugstr_w(wc->lpszClassName), atom, wc->lpfnWndProc, instance, wc->hbrBackground,
639
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
640

641 642
    classPtr->hIcon         = wc->hIcon;
    classPtr->hIconSm       = wc->hIconSm;
643 644 645 646
    classPtr->hIconSmIntern = wc->hIcon && !wc->hIconSm ?
                                            CopyImage( wc->hIcon, IMAGE_ICON,
                                                GetSystemMetrics( SM_CXSMICON ),
                                                GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
647 648
    classPtr->hCursor       = wc->hCursor;
    classPtr->hbrBackground = wc->hbrBackground;
649
    classPtr->winproc       = WINPROC_AllocProc( wc->lpfnWndProc, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
650
    CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
651
    release_class_ptr( classPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
652
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
653 654 655
}


Alexandre Julliard's avatar
Alexandre Julliard committed
656
/***********************************************************************
657
 *		UnregisterClassA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
658
 */
659
BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
660
{
661 662 663 664 665 666 667 668 669
    if (!IS_INTRESOURCE(className))
    {
        WCHAR name[MAX_ATOM_LEN + 1];

        if (!MultiByteToWideChar( CP_ACP, 0, className, -1, name, MAX_ATOM_LEN + 1 ))
            return FALSE;
        return UnregisterClassW( name, hInstance );
    }
    return UnregisterClassW( (LPCWSTR)className, hInstance );
Alexandre Julliard's avatar
Alexandre Julliard committed
670
}
Alexandre Julliard's avatar
Alexandre Julliard committed
671 672

/***********************************************************************
673
 *		UnregisterClassW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
674
 */
675
BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
676
{
677
    CLASS *classPtr = NULL;
678

679
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
680

681
    SERVER_START_REQ( destroy_class )
682
    {
683
        req->instance = wine_server_client_ptr( hInstance );
684 685
        if (!(req->atom = get_int_atom_value(className)) && className)
            wine_server_add_data( req, className, strlenW(className) * sizeof(WCHAR) );
686
        if (!wine_server_call_err( req )) classPtr = wine_server_get_ptr( reply->client_ptr );
687
    }
688 689 690 691
    SERVER_END_REQ;

    if (classPtr) CLASS_FreeClass( classPtr );
    return (classPtr != NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
692 693
}

Alexandre Julliard's avatar
Alexandre Julliard committed
694 695

/***********************************************************************
696
 *		GetClassWord (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
697
 */
698
WORD WINAPI GetClassWord( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
699
{
700
    CLASS *class;
701
    WORD retvalue = 0;
702 703 704

    if (offset < 0) return GetClassLongA( hwnd, offset );

705
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
706

707 708 709 710
    if (class == CLASS_OTHER_PROCESS)
    {
        SERVER_START_REQ( set_class_info )
        {
711
            req->window = wine_server_user_handle( hwnd );
712 713 714 715 716 717 718 719 720 721
            req->flags = 0;
            req->extra_offset = offset;
            req->extra_size = sizeof(retvalue);
            if (!wine_server_call_err( req ))
                memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
        }
        SERVER_END_REQ;
        return retvalue;
    }

722
    if (offset <= class->cbClsExtra - sizeof(WORD))
723
        memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
724 725 726
    else
        SetLastError( ERROR_INVALID_INDEX );
    release_class_ptr( class );
727
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
728 729 730
}


Alexandre Julliard's avatar
Alexandre Julliard committed
731
/***********************************************************************
732 733 734
 *             CLASS_GetClassLong
 *
 * Implementation of GetClassLong(Ptr)A/W
Alexandre Julliard's avatar
Alexandre Julliard committed
735
 */
736 737
static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
                                     BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
738
{
739
    CLASS *class;
740
    ULONG_PTR retvalue = 0;
741

742
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
743

744 745 746 747
    if (class == CLASS_OTHER_PROCESS)
    {
        SERVER_START_REQ( set_class_info )
        {
748
            req->window = wine_server_user_handle( hwnd );
749 750
            req->flags = 0;
            req->extra_offset = (offset >= 0) ? offset : -1;
751
            req->extra_size = (offset >= 0) ? size : 0;
752 753 754 755
            if (!wine_server_call_err( req ))
            {
                switch(offset)
                {
756 757 758 759 760 761
                case GCLP_HBRBACKGROUND:
                case GCLP_HCURSOR:
                case GCLP_HICON:
                case GCLP_HICONSM:
                case GCLP_WNDPROC:
                case GCLP_MENUNAME:
762 763
                    FIXME( "offset %d (%s) not supported on other process window %p\n",
			   offset, SPY_GetClassLongOffsetName(offset), hwnd );
764 765 766 767 768 769 770 771 772 773 774
                    SetLastError( ERROR_INVALID_HANDLE );
                    break;
                case GCL_STYLE:
                    retvalue = reply->old_style;
                    break;
                case GCL_CBWNDEXTRA:
                    retvalue = reply->old_win_extra;
                    break;
                case GCL_CBCLSEXTRA:
                    retvalue = reply->old_extra;
                    break;
775
                case GCLP_HMODULE:
776
                    retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
777 778 779 780 781
                    break;
                case GCW_ATOM:
                    retvalue = reply->old_atom;
                    break;
                default:
782 783 784 785 786 787 788 789 790 791 792 793
                    if (offset >= 0)
                    {
                        if (size == sizeof(DWORD))
                        {
                            DWORD retdword;
                            memcpy( &retdword, &reply->old_extra_value, sizeof(DWORD) );
                            retvalue = retdword;
                        }
                        else
                            memcpy( &retvalue, &reply->old_extra_value,
                                    sizeof(ULONG_PTR) );
                    }
794 795 796 797 798 799 800 801 802
                    else SetLastError( ERROR_INVALID_INDEX );
                    break;
                }
            }
        }
        SERVER_END_REQ;
        return retvalue;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
803 804
    if (offset >= 0)
    {
805 806 807 808 809 810 811 812 813 814 815
        if (offset <= class->cbClsExtra - size)
        {
            if (size == sizeof(DWORD))
            {
                DWORD retdword;
                memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) );
                retvalue = retdword;
            }
            else
                memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) );
        }
816 817 818 819
        else
            SetLastError( ERROR_INVALID_INDEX );
        release_class_ptr( class );
        return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
820
    }
821

Alexandre Julliard's avatar
Alexandre Julliard committed
822 823
    switch(offset)
    {
824
    case GCLP_HBRBACKGROUND:
825
        retvalue = (ULONG_PTR)class->hbrBackground;
826
        break;
827
    case GCLP_HCURSOR:
828
        retvalue = (ULONG_PTR)class->hCursor;
829
        break;
830
    case GCLP_HICON:
831
        retvalue = (ULONG_PTR)class->hIcon;
832
        break;
833
    case GCLP_HICONSM:
834
        retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern);
835 836
        break;
    case GCL_STYLE:
837
        retvalue = class->style;
838 839
        break;
    case GCL_CBWNDEXTRA:
840
        retvalue = class->cbWndExtra;
841 842
        break;
    case GCL_CBCLSEXTRA:
843
        retvalue = class->cbClsExtra;
844
        break;
845
    case GCLP_HMODULE:
846
        retvalue = (ULONG_PTR)class->hInstance;
847
        break;
848
    case GCLP_WNDPROC:
849
        retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
850
        break;
851
    case GCLP_MENUNAME:
852 853 854 855 856
        retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
        if (unicode)
            retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
        else
            retvalue = (ULONG_PTR)CLASS_GetMenuNameA( class );
857 858
        break;
    case GCW_ATOM:
859
        retvalue = class->atomName;
860 861 862 863
        break;
    default:
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
864
    }
865
    release_class_ptr( class );
866
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
867 868 869 870
}


/***********************************************************************
871
 *		GetClassLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
872
 */
873
DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
874
{
875 876
    return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
}
877

878

879

880 881 882 883 884 885
/***********************************************************************
 *		GetClassLongA (USER32.@)
 */
DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
{
    return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
886 887 888
}


Alexandre Julliard's avatar
Alexandre Julliard committed
889
/***********************************************************************
890
 *		SetClassWord (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
891
 */
892
WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
893
{
894
    CLASS *class;
Alexandre Julliard's avatar
Alexandre Julliard committed
895
    WORD retval = 0;
896 897 898

    if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );

899
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
900

901
    SERVER_START_REQ( set_class_info )
Alexandre Julliard's avatar
Alexandre Julliard committed
902
    {
903
        req->window = wine_server_user_handle( hwnd );
904 905 906 907 908 909 910 911 912 913
        req->flags = SET_CLASS_EXTRA;
        req->extra_offset = offset;
        req->extra_size = sizeof(newval);
        memcpy( &req->extra_value, &newval, sizeof(newval) );
        if (!wine_server_call_err( req ))
        {
            void *ptr = (char *)(class + 1) + offset;
            memcpy( &retval, ptr, sizeof(retval) );
            memcpy( ptr, &newval, sizeof(newval) );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
914
    }
915
    SERVER_END_REQ;
916
    release_class_ptr( class );
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918 919 920 921
    return retval;
}


/***********************************************************************
922 923 924
 *             CLASS_SetClassLong
 *
 * Implementation of SetClassLong(Ptr)A/W
Alexandre Julliard's avatar
Alexandre Julliard committed
925
 */
926 927
static ULONG_PTR CLASS_SetClassLong( HWND hwnd, INT offset, LONG_PTR newval,
                                     UINT size, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
928
{
929
    CLASS *class;
930
    ULONG_PTR retval = 0;
931

932
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
933

Alexandre Julliard's avatar
Alexandre Julliard committed
934 935
    if (offset >= 0)
    {
936
        if (set_server_info( hwnd, offset, newval, size ))
Alexandre Julliard's avatar
Alexandre Julliard committed
937
        {
938
            void *ptr = (char *)(class + 1) + offset;
939 940 941 942 943 944 945 946 947 948 949 950 951
            if ( size == sizeof(LONG) )
            {
                DWORD retdword;
                LONG newlong = newval;
                memcpy( &retdword, ptr, sizeof(DWORD) );
                memcpy( ptr, &newlong, sizeof(LONG) );
                retval = retdword;
            }
            else
            {
                memcpy( &retval, ptr, sizeof(ULONG_PTR) );
                memcpy( ptr, &newval, sizeof(LONG_PTR) );
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
952 953
        }
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
954 955
    else switch(offset)
    {
956
    case GCLP_MENUNAME:
957 958 959 960
        if ( unicode )
            CLASS_SetMenuNameW( class, (LPCWSTR)newval );
        else
            CLASS_SetMenuNameA( class, (LPCSTR)newval );
961 962
        retval = 0;  /* Old value is now meaningless anyway */
        break;
963
    case GCLP_WNDPROC:
964
        retval = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
965
        class->winproc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
966
        break;
967
    case GCLP_HBRBACKGROUND:
968
        retval = (ULONG_PTR)class->hbrBackground;
969
        class->hbrBackground = (HBRUSH)newval;
970
        break;
971
    case GCLP_HCURSOR:
972
        retval = (ULONG_PTR)class->hCursor;
973
        class->hCursor = (HCURSOR)newval;
974
        break;
975
    case GCLP_HICON:
976
        retval = (ULONG_PTR)class->hIcon;
977 978 979 980 981 982 983 984
        if (retval && class->hIconSmIntern)
        {
            DestroyIcon(class->hIconSmIntern);
            class->hIconSmIntern = NULL;
        }
        if (newval && !class->hIconSm)
            class->hIconSmIntern = CopyImage( (HICON)newval, IMAGE_ICON,
                      GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
985
        class->hIcon = (HICON)newval;
986
        break;
987
    case GCLP_HICONSM:
988
        retval = (ULONG_PTR)class->hIconSm;
989 990 991 992 993 994 995 996 997
        if (retval && !newval)
            class->hIconSmIntern = class->hIcon ? CopyImage( class->hIcon, IMAGE_ICON,
                                                GetSystemMetrics( SM_CXSMICON ),
                                                GetSystemMetrics( SM_CYSMICON ), 0 ) : NULL;
        else if (!retval && newval && class->hIconSmIntern)
        {
            DestroyIcon(class->hIconSmIntern);
            class->hIconSmIntern = NULL;
        }
998
        class->hIconSm = (HICON)newval;
999 1000
        break;
    case GCL_STYLE:
1001 1002
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->style;
1003 1004 1005
        class->style = newval;
        break;
    case GCL_CBWNDEXTRA:
1006 1007
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->cbWndExtra;
1008 1009
        class->cbWndExtra = newval;
        break;
1010
    case GCLP_HMODULE:
1011 1012
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = (ULONG_PTR)class->hInstance;
1013
        class->hInstance = (HINSTANCE)newval;
1014 1015
        break;
    case GCW_ATOM:
1016 1017
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->atomName;
1018
        class->atomName = newval;
1019
        GlobalGetAtomNameW( newval, class->name, sizeof(class->name)/sizeof(WCHAR) );
1020
        break;
1021 1022 1023
    case GCL_CBCLSEXTRA:  /* cannot change this one */
        SetLastError( ERROR_INVALID_PARAMETER );
        break;
1024 1025 1026
    default:
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027
    }
1028
    release_class_ptr( class );
Alexandre Julliard's avatar
Alexandre Julliard committed
1029 1030
    return retval;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1031 1032 1033


/***********************************************************************
1034
 *		SetClassLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1035
 */
1036
DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
1037
{
1038 1039
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), TRUE );
}
1040 1041


1042 1043 1044 1045 1046 1047
/***********************************************************************
 *		SetClassLongA (USER32.@)
 */
DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
{
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1050

Alexandre Julliard's avatar
Alexandre Julliard committed
1051
/***********************************************************************
1052
 *		GetClassNameA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1053
 */
1054
INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
1055
{
1056 1057
    WCHAR tmpbuf[MAX_ATOM_LEN + 1];
    DWORD len;
1058 1059

    if (count <= 0) return 0;
1060 1061 1062 1063
    if (!GetClassNameW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
    RtlUnicodeToMultiByteN( buffer, count - 1, &len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
    buffer[len] = 0;
    return len;
Alexandre Julliard's avatar
Alexandre Julliard committed
1064 1065 1066 1067
}


/***********************************************************************
1068
 *		GetClassNameW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1069
 */
1070
INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
1071
{
1072
    CLASS *class;
1073
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1074

1075 1076 1077 1078
    TRACE("%p %p %d\n", hwnd, buffer, count);

    if (count <= 0) return 0;

1079 1080 1081
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;

    if (class == CLASS_OTHER_PROCESS)
1082
    {
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
        WCHAR tmpbuf[MAX_ATOM_LEN + 1];

        ret = GlobalGetAtomNameW( GetClassLongW( hwnd, GCW_ATOM ), tmpbuf, MAX_ATOM_LEN + 1 );
        if (ret)
        {
            ret = min(count - 1, ret);
            memcpy(buffer, tmpbuf, ret * sizeof(WCHAR));
            buffer[ret] = 0;
        }
    }
    else
    {
        lstrcpynW( buffer, class->name, count );
        release_class_ptr( class );
        ret = strlenW( buffer );
1098
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101 1102
}


1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
/***********************************************************************
 *		RealGetWindowClassA (USER32.@)
 */
UINT WINAPI RealGetWindowClassA( HWND hwnd, LPSTR buffer, UINT count )
{
    return GetClassNameA( hwnd, buffer, count );
}


/***********************************************************************
 *		RealGetWindowClassW (USER32.@)
 */
UINT WINAPI RealGetWindowClassW( HWND hwnd, LPWSTR buffer, UINT count )
{
    return GetClassNameW( hwnd, buffer, count );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1121
/***********************************************************************
1122
 *		GetClassInfoA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1123
 */
1124
BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1125
{
1126 1127
    WNDCLASSEXA wcex;
    UINT ret = GetClassInfoExA( hInstance, name, &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
1128

1129
    if (ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
1130
    {
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
        wc->style         = wcex.style;
        wc->lpfnWndProc   = wcex.lpfnWndProc;
        wc->cbClsExtra    = wcex.cbClsExtra;
        wc->cbWndExtra    = wcex.cbWndExtra;
        wc->hInstance     = wcex.hInstance;
        wc->hIcon         = wcex.hIcon;
        wc->hCursor       = wcex.hCursor;
        wc->hbrBackground = wcex.hbrBackground;
        wc->lpszMenuName  = wcex.lpszMenuName;
        wc->lpszClassName = wcex.lpszClassName;
Alexandre Julliard's avatar
Alexandre Julliard committed
1141
    }
1142
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1143 1144 1145 1146
}


/***********************************************************************
1147
 *		GetClassInfoW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1148
 */
1149
BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1150
{
1151 1152
    WNDCLASSEXW wcex;
    UINT ret = GetClassInfoExW( hInstance, name, &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
1153

1154
    if (ret)
1155
    {
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
        wc->style         = wcex.style;
        wc->lpfnWndProc   = wcex.lpfnWndProc;
        wc->cbClsExtra    = wcex.cbClsExtra;
        wc->cbWndExtra    = wcex.cbWndExtra;
        wc->hInstance     = wcex.hInstance;
        wc->hIcon         = wcex.hIcon;
        wc->hCursor       = wcex.hCursor;
        wc->hbrBackground = wcex.hbrBackground;
        wc->lpszMenuName  = wcex.lpszMenuName;
        wc->lpszClassName = wcex.lpszClassName;
1166
    }
1167
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169 1170 1171
}


/***********************************************************************
1172
 *		GetClassInfoExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1173
 */
1174
BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1175
{
1176
    ATOM atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178
    CLASS *classPtr;

1179
    TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
1180

1181 1182 1183 1184 1185 1186
    if (!wc)
    {
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }

1187
    if (!hInstance) hInstance = user32_module;
1188

1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
    if (!IS_INTRESOURCE(name))
    {
        WCHAR nameW[MAX_ATOM_LEN + 1];
        if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ))
            return FALSE;
        classPtr = CLASS_FindClass( nameW, hInstance );
    }
    else classPtr = CLASS_FindClass( (LPCWSTR)name, hInstance );

    if (!classPtr)
1199 1200 1201 1202
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1203
    wc->style         = classPtr->style;
1204
    wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1205 1206
    wc->cbClsExtra    = classPtr->cbClsExtra;
    wc->cbWndExtra    = classPtr->cbWndExtra;
1207
    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1208
    wc->hIcon         = classPtr->hIcon;
1209
    wc->hIconSm       = classPtr->hIconSm ? classPtr->hIconSm : classPtr->hIconSmIntern;
1210 1211
    wc->hCursor       = classPtr->hCursor;
    wc->hbrBackground = classPtr->hbrBackground;
Alexandre Julliard's avatar
Alexandre Julliard committed
1212
    wc->lpszMenuName  = CLASS_GetMenuNameA( classPtr );
1213
    wc->lpszClassName = name;
1214
    atom = classPtr->atomName;
1215
    release_class_ptr( classPtr );
1216

1217 1218
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1219 1220 1221 1222
}


/***********************************************************************
1223
 *		GetClassInfoExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1224
 */
1225
BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1226
{
1227
    ATOM atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1228
    CLASS *classPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1229

1230
    TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
1231

1232 1233 1234 1235 1236 1237
    if (!wc)
    {
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }

1238
    if (!hInstance) hInstance = user32_module;
1239

1240
    if (!(classPtr = CLASS_FindClass( name, hInstance )))
1241 1242 1243 1244
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1245
    wc->style         = classPtr->style;
1246
    wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1247 1248
    wc->cbClsExtra    = classPtr->cbClsExtra;
    wc->cbWndExtra    = classPtr->cbWndExtra;
1249
    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1250
    wc->hIcon         = classPtr->hIcon;
1251
    wc->hIconSm       = classPtr->hIconSm ? classPtr->hIconSm : classPtr->hIconSmIntern;
1252 1253
    wc->hCursor       = classPtr->hCursor;
    wc->hbrBackground = classPtr->hbrBackground;
Alexandre Julliard's avatar
Alexandre Julliard committed
1254
    wc->lpszMenuName  = CLASS_GetMenuNameW( classPtr );
1255
    wc->lpszClassName = name;
1256
    atom = classPtr->atomName;
1257
    release_class_ptr( classPtr );
1258

1259 1260
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1261
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263


1264 1265
#if 0  /* toolhelp is in kernel, so this cannot work */

Alexandre Julliard's avatar
Alexandre Julliard committed
1266
/***********************************************************************
1267
 *		ClassFirst (TOOLHELP.69)
Alexandre Julliard's avatar
Alexandre Julliard committed
1268
 */
1269
BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
Alexandre Julliard's avatar
Alexandre Julliard committed
1270
{
1271
    TRACE("%p\n",pClassEntry);
Alexandre Julliard's avatar
Alexandre Julliard committed
1272
    pClassEntry->wNext = 1;
1273
    return ClassNext16( pClassEntry );
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275 1276 1277
}


/***********************************************************************
1278
 *		ClassNext (TOOLHELP.70)
Alexandre Julliard's avatar
Alexandre Julliard committed
1279
 */
1280
BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
Alexandre Julliard's avatar
Alexandre Julliard committed
1281
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1282 1283
    int i;
    CLASS *class = firstClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1284

1285
    TRACE("%p\n",pClassEntry);
1286

Alexandre Julliard's avatar
Alexandre Julliard committed
1287 1288 1289 1290 1291 1292 1293
    if (!pClassEntry->wNext) return FALSE;
    for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
    if (!class)
    {
        pClassEntry->wNext = 0;
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1294
    pClassEntry->hInst = class->hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
1295
    pClassEntry->wNext++;
1296
    GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
Alexandre Julliard's avatar
Alexandre Julliard committed
1297
                          sizeof(pClassEntry->szClassName) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299
    return TRUE;
}
1300
#endif
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

/* 64bit versions */

#ifdef GetClassLongPtrA
#undef GetClassLongPtrA
#endif

#ifdef GetClassLongPtrW
#undef GetClassLongPtrW
#endif

#ifdef SetClassLongPtrA
#undef SetClassLongPtrA
#endif

#ifdef SetClassLongPtrW
#undef SetClassLongPtrW
#endif

/***********************************************************************
 *		GetClassLongPtrA (USER32.@)
 */
ULONG_PTR WINAPI GetClassLongPtrA( HWND hwnd, INT offset )
{
1325
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1326 1327 1328 1329 1330 1331 1332
}

/***********************************************************************
 *		GetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
{
1333
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1334 1335 1336 1337 1338 1339 1340
}

/***********************************************************************
 *		SetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
{
1341
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1342 1343 1344 1345 1346 1347 1348
}

/***********************************************************************
 *		SetClassLongPtrA (USER32.@)
 */
ULONG_PTR WINAPI SetClassLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
{
1349
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), FALSE );
1350
}