class.c 36.5 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 35
#include "wingdi.h"
#include "wine/winuser16.h"
#include "wine/unicode.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36
#include "win.h"
37
#include "user_private.h"
38
#include "controls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
39
#include "winproc.h"
40 41
#include "wine/server.h"
#include "wine/list.h"
42
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
43

44
WINE_DEFAULT_DEBUG_CHANNEL(class);
45

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 55 56 57 58 59 60 61 62
    INT              cbClsExtra;    /* Class extra bytes */
    INT              cbWndExtra;    /* Window extra bytes */
    LPWSTR           menuName;      /* Default menu name (Unicode followed by ASCII) */
    HINSTANCE        hInstance;     /* Module that created the task */
    HICON            hIcon;         /* Default icon */
    HICON            hIconSm;       /* Default small icon */
    HCURSOR          hCursor;       /* Default cursor */
    HBRUSH           hbrBackground; /* Default background */
    ATOM             atomName;      /* Name of the class */
} CLASS;

63 64 65
static struct list class_list = LIST_INIT( class_list );

#define CLASS_OTHER_PROCESS ((CLASS *)1)
66
#define MAX_ATOM_LEN 255 /* from dlls/kernel32/atom.c */
Alexandre Julliard's avatar
Alexandre Julliard committed
67

68 69 70
/***********************************************************************
 *           get_class_ptr
 */
71
static CLASS *get_class_ptr( HWND hwnd, BOOL write_access )
72
{
73
    WND *ptr = WIN_GetPtr( hwnd );
74

75
    if (ptr)
76
    {
77
        if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP) return ptr->class;
78
        if (!write_access) return CLASS_OTHER_PROCESS;
79

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


/***********************************************************************
 *           release_class_ptr
 */
inline static void release_class_ptr( CLASS *ptr )
{
    USER_Unlock();
}

Alexandre Julliard's avatar
Alexandre Julliard committed
100

101 102 103 104 105
/***********************************************************************
 *           set_server_info
 *
 * Set class info with the wine server.
 */
106
static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
{
    BOOL ret;

    SERVER_START_REQ( set_class_info )
    {
        req->window = hwnd;
        req->extra_offset = -1;
        switch(offset)
        {
        case GCW_ATOM:
            req->flags = SET_CLASS_ATOM;
            req->atom = newval;
        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;
127
        case GCLP_HMODULE:
128 129 130 131 132 133 134
            req->flags = SET_CLASS_INSTANCE;
            req->instance = (void *)newval;
            break;
        default:
            assert( offset >= 0 );
            req->flags = SET_CLASS_EXTRA;
            req->extra_offset = offset;
135 136 137 138 139 140 141 142
            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) );
143 144 145 146 147 148 149 150 151
            break;
        }
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
152 153 154 155 156
/***********************************************************************
 *           CLASS_GetMenuNameA
 *
 * Get the menu name as a ASCII string.
 */
157
inline static LPSTR CLASS_GetMenuNameA( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
158
{
159 160
    if (!HIWORD(classPtr->menuName)) return (LPSTR)classPtr->menuName;
    return (LPSTR)(classPtr->menuName + strlenW(classPtr->menuName) + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
161 162 163 164 165 166 167 168
}


/***********************************************************************
 *           CLASS_GetMenuNameW
 *
 * Get the menu name as a Unicode string.
 */
169
inline static LPWSTR CLASS_GetMenuNameW( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
170
{
171
    return classPtr->menuName;
Alexandre Julliard's avatar
Alexandre Julliard committed
172 173 174 175 176 177 178 179 180 181
}


/***********************************************************************
 *           CLASS_SetMenuNameA
 *
 * Set the menu name in a class structure by copying the string.
 */
static void CLASS_SetMenuNameA( CLASS *classPtr, LPCSTR name )
{
182
    if (HIWORD(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
183 184 185 186
    if (HIWORD(name))
    {
        DWORD lenA = strlen(name) + 1;
        DWORD lenW = MultiByteToWideChar( CP_ACP, 0, name, lenA, NULL, 0 );
187
        classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
188 189 190 191
        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
192 193 194 195 196 197 198 199 200 201
}


/***********************************************************************
 *           CLASS_SetMenuNameW
 *
 * Set the menu name in a class structure by copying the string.
 */
static void CLASS_SetMenuNameW( CLASS *classPtr, LPCWSTR name )
{
202
    if (HIWORD(classPtr->menuName)) HeapFree( GetProcessHeap(), 0, classPtr->menuName );
203
    if (HIWORD(name))
204
    {
205 206
        DWORD lenW = strlenW(name) + 1;
        DWORD lenA = WideCharToMultiByte( CP_ACP, 0, name, lenW, NULL, 0, NULL, NULL );
207
        classPtr->menuName = HeapAlloc( GetProcessHeap(), 0, lenA + lenW*sizeof(WCHAR) );
208 209 210
        memcpy( classPtr->menuName, name, lenW*sizeof(WCHAR) );
        WideCharToMultiByte( CP_ACP, 0, name, lenW,
                             (char *)(classPtr->menuName + lenW), lenA, NULL, NULL );
211
    }
212
    else classPtr->menuName = (LPWSTR)name;
213 214 215
}


Alexandre Julliard's avatar
Alexandre Julliard committed
216 217 218 219 220
/***********************************************************************
 *           CLASS_FreeClass
 *
 * Free a class structure.
 */
221
static void CLASS_FreeClass( CLASS *classPtr )
Alexandre Julliard's avatar
Alexandre Julliard committed
222
{
223
    TRACE("%p\n", classPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
224

225
    USER_Lock();
226

227 228 229 230 231 232
    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
233 234 235 236 237 238
}


/***********************************************************************
 *           CLASS_FreeModuleClasses
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
239
void CLASS_FreeModuleClasses( HMODULE16 hModule )
Alexandre Julliard's avatar
Alexandre Julliard committed
240
{
241
    struct list *ptr, *next;
Alexandre Julliard's avatar
Alexandre Julliard committed
242

243 244 245
    TRACE("0x%08x\n", hModule);

    USER_Lock();
246
    for (ptr = list_head( &class_list ); ptr; ptr = next)
Alexandre Julliard's avatar
Alexandre Julliard committed
247
    {
248 249
        CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
        next = list_next( &class_list, ptr );
250 251 252 253 254 255 256 257 258 259 260 261 262
        if (class->hInstance == HINSTANCE_32(hModule))
        {
            BOOL ret;

            SERVER_START_REQ( destroy_class )
            {
                req->atom = class->atomName;
                req->instance = class->hInstance;
                ret = !wine_server_call_err( req );
            }
            SERVER_END_REQ;
            if (ret) CLASS_FreeClass( class );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
263
    }
264
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
265 266 267
}


Alexandre Julliard's avatar
Alexandre Julliard committed
268
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
269
 *           CLASS_FindClassByAtom
Alexandre Julliard's avatar
Alexandre Julliard committed
270
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
271
 * Return a pointer to the class.
Alexandre Julliard's avatar
Alexandre Julliard committed
272
 * hinstance has been normalized by the caller.
Alexandre Julliard's avatar
Alexandre Julliard committed
273
 */
274 275
static CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE hinstance )
{
276
    struct list *ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
277

278 279
    USER_Lock();

280
    LIST_FOR_EACH( ptr, &class_list )
Alexandre Julliard's avatar
Alexandre Julliard committed
281
    {
282 283 284
        CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
        if (class->atomName != atom) continue;
        if (!hinstance || !class->local || class->hInstance == hinstance)
Alexandre Julliard's avatar
Alexandre Julliard committed
285
        {
286
            TRACE("0x%04x %p -> %p\n", atom, hinstance, class);
Alexandre Julliard's avatar
Alexandre Julliard committed
287 288
            return class;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
289
    }
290
    USER_Unlock();
291 292
    TRACE("0x%04x %p -> not found\n", atom, hinstance);
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
293 294
}

Alexandre Julliard's avatar
Alexandre Julliard committed
295

Alexandre Julliard's avatar
Alexandre Julliard committed
296
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
297 298 299
 *           CLASS_RegisterClass
 *
 * The real RegisterClass() functionality.
300
 * The atom is deleted no matter what.
Alexandre Julliard's avatar
Alexandre Julliard committed
301
 */
302
static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance, BOOL local,
303
                                   DWORD style, INT classExtra, INT winExtra )
Alexandre Julliard's avatar
Alexandre Julliard committed
304
{
Alexandre Julliard's avatar
Alexandre Julliard committed
305
    CLASS *classPtr;
306
    BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
307

308
    TRACE("atom=0x%x hinst=%p style=0x%x clExtr=0x%x winExtr=0x%x\n",
309
          atom, hInstance, style, classExtra, winExtra );
Alexandre Julliard's avatar
Alexandre Julliard committed
310 311 312

    /* Fix the extra bytes value */

313 314 315 316 317 318
    if (classExtra < 0 || winExtra < 0)
    {
         SetLastError( ERROR_INVALID_PARAMETER );
         return NULL;
    }
    if (classExtra > 40)  /* Extra bytes are limited to 40 in Win32 */
319
        WARN("Class extra bytes %d is > 40\n", classExtra);
320
    if (winExtra > 40)    /* Extra bytes are limited to 40 in Win32 */
321
        WARN("Win extra bytes %d is > 40\n", winExtra );
Alexandre Julliard's avatar
Alexandre Julliard committed
322

323
    classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
324 325 326 327 328
    if (!classPtr)
    {
        GlobalDeleteAtom( atom );
        return NULL;
    }
329 330 331

    SERVER_START_REQ( create_class )
    {
332 333 334 335 336 337 338
        req->local      = local;
        req->atom       = atom;
        req->style      = style;
        req->instance   = hInstance;
        req->extra      = classExtra;
        req->win_extra  = winExtra;
        req->client_ptr = classPtr;
339 340 341
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
342
    GlobalDeleteAtom( atom );  /* the server increased the atom ref count */
343 344 345 346 347 348
    if (!ret)
    {
        HeapFree( GetProcessHeap(), 0, classPtr );
        return NULL;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
349
    classPtr->style       = style;
350
    classPtr->local       = local;
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352 353 354
    classPtr->cbWndExtra  = winExtra;
    classPtr->cbClsExtra  = classExtra;
    classPtr->hInstance   = hInstance;
    classPtr->atomName    = atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
355

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

358
    USER_Lock();
359 360
    if (local) list_add_head( &class_list, &classPtr->entry );
    else list_add_tail( &class_list, &classPtr->entry );
Alexandre Julliard's avatar
Alexandre Julliard committed
361 362 363 364
    return classPtr;
}


365
/***********************************************************************
366
 *           register_builtin
367 368 369 370
 *
 * Register a builtin control class.
 * This allows having both ASCII and Unicode winprocs for the same class.
 */
371
static CLASS *register_builtin( const struct builtin_class_descr *descr )
372 373 374 375
{
    ATOM atom;
    CLASS *classPtr;

376
    if (!(atom = GlobalAddAtomA( descr->name ))) return 0;
377

378
    if (!(classPtr = CLASS_RegisterClass( atom, user32_module, FALSE,
379
                                          descr->style, 0, descr->extra ))) return 0;
380

381
    classPtr->hCursor       = LoadCursorA( 0, (LPSTR)descr->cursor );
382
    classPtr->hbrBackground = descr->brush;
383
    classPtr->winproc       = WINPROC_AllocProc( descr->procA, descr->procW );
384 385
    release_class_ptr( classPtr );
    return classPtr;
386 387 388
}


389 390 391
/***********************************************************************
 *           CLASS_RegisterBuiltinClasses
 */
392
void CLASS_RegisterBuiltinClasses(void)
393 394 395 396 397 398 399 400 401 402 403 404 405 406
{
    extern const struct builtin_class_descr BUTTON_builtin_class;
    extern const struct builtin_class_descr COMBO_builtin_class;
    extern const struct builtin_class_descr COMBOLBOX_builtin_class;
    extern const struct builtin_class_descr DIALOG_builtin_class;
    extern const struct builtin_class_descr DESKTOP_builtin_class;
    extern const struct builtin_class_descr EDIT_builtin_class;
    extern const struct builtin_class_descr ICONTITLE_builtin_class;
    extern const struct builtin_class_descr LISTBOX_builtin_class;
    extern const struct builtin_class_descr MDICLIENT_builtin_class;
    extern const struct builtin_class_descr MENU_builtin_class;
    extern const struct builtin_class_descr SCROLL_builtin_class;
    extern const struct builtin_class_descr STATIC_builtin_class;

407
    register_builtin( &DESKTOP_builtin_class );
408 409 410 411 412 413 414 415 416 417 418 419 420 421
    register_builtin( &BUTTON_builtin_class );
    register_builtin( &COMBO_builtin_class );
    register_builtin( &COMBOLBOX_builtin_class );
    register_builtin( &DIALOG_builtin_class );
    register_builtin( &EDIT_builtin_class );
    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 );
}


422 423 424
/***********************************************************************
 *           CLASS_AddWindow
 *
425 426
 * Add a new window using this class, and set the necessary
 * information inside the window structure.
427
 */
428
void CLASS_AddWindow( CLASS *class, WND *win, BOOL unicode )
429
{
430 431
    win->class    = class;
    win->clsStyle = class->style;
432
    win->winproc  = class->winproc;
433
    if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
434 435 436
}


Alexandre Julliard's avatar
Alexandre Julliard committed
437
/***********************************************************************
438
 *		RegisterClassA (USER32.@)
439 440 441
 *
 * Register a window class.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
442 443 444
 * RETURNS
 *	>0: Unique identifier
 *	0: Failure
Alexandre Julliard's avatar
Alexandre Julliard committed
445
 */
446
ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
447
{
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    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
463
}
Alexandre Julliard's avatar
Alexandre Julliard committed
464

Alexandre Julliard's avatar
Alexandre Julliard committed
465 466

/***********************************************************************
467
 *		RegisterClassW (USER32.@)
468 469
 *
 * See RegisterClassA.
Alexandre Julliard's avatar
Alexandre Julliard committed
470
 */
471
ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
472
{
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
    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
488 489 490 491
}


/***********************************************************************
492
 *		RegisterClassExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
493
 */
494
ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
495 496 497
{
    ATOM atom;
    CLASS *classPtr;
498 499 500 501 502 503 504 505 506
    HINSTANCE instance;

    if (wc->hInstance == user32_module)
    {
        /* we can't register a class for user32 */
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }
    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
507

508 509
    if (!(atom = GlobalAddAtomA( wc->lpszClassName ))) return 0;

510 511
    if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
512
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
513

514
    TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
515 516
          atom, wc->lpfnWndProc, instance, wc->hbrBackground,
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
517

518 519 520 521
    classPtr->hIcon         = wc->hIcon;
    classPtr->hIconSm       = wc->hIconSm;
    classPtr->hCursor       = wc->hCursor;
    classPtr->hbrBackground = wc->hbrBackground;
522
    classPtr->winproc       = WINPROC_AllocProc( wc->lpfnWndProc, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
523
    CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
524
    release_class_ptr( classPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
525 526 527 528 529
    return atom;
}


/***********************************************************************
530
 *		RegisterClassExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
531
 */
532
ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
533 534 535
{
    ATOM atom;
    CLASS *classPtr;
536 537 538 539 540 541 542 543 544
    HINSTANCE instance;

    if (wc->hInstance == user32_module)
    {
        /* we can't register a class for user32 */
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }
    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
545

546 547
    if (!(atom = GlobalAddAtomW( wc->lpszClassName ))) return 0;

548 549
    if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
Alexandre Julliard's avatar
Alexandre Julliard committed
550 551
        return 0;

552
    TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
553 554
          atom, wc->lpfnWndProc, instance, wc->hbrBackground,
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
555

556 557 558 559
    classPtr->hIcon         = wc->hIcon;
    classPtr->hIconSm       = wc->hIconSm;
    classPtr->hCursor       = wc->hCursor;
    classPtr->hbrBackground = wc->hbrBackground;
560
    classPtr->winproc       = WINPROC_AllocProc( NULL, wc->lpfnWndProc );
Alexandre Julliard's avatar
Alexandre Julliard committed
561
    CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
562
    release_class_ptr( classPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
563
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
564 565 566
}


Alexandre Julliard's avatar
Alexandre Julliard committed
567
/***********************************************************************
568
 *		UnregisterClassA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
569
 */
570
BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
571
{
572
    ATOM atom = HIWORD(className) ? GlobalFindAtomA( className ) : LOWORD(className);
573
    return UnregisterClassW( (LPCWSTR)MAKEINTATOM(atom), hInstance );
Alexandre Julliard's avatar
Alexandre Julliard committed
574
}
Alexandre Julliard's avatar
Alexandre Julliard committed
575 576

/***********************************************************************
577
 *		UnregisterClassW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
578
 */
579
BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
580
{
581
    CLASS *classPtr = NULL;
582 583 584 585
    ATOM atom = HIWORD(className) ? GlobalFindAtomW( className ) : LOWORD(className);

    TRACE("%s %p %x\n",debugstr_w(className), hInstance, atom);

586 587 588 589 590 591 592
    if (!atom)
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }

    SERVER_START_REQ( destroy_class )
593
    {
594 595 596
        req->atom = atom;
        req->instance = hInstance;
        if (!wine_server_call_err( req )) classPtr = reply->client_ptr;
597
    }
598 599 600 601
    SERVER_END_REQ;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
604 605

/***********************************************************************
606
 *		GetClassWord (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
607
 */
608
WORD WINAPI GetClassWord( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
609
{
610
    CLASS *class;
611
    WORD retvalue = 0;
612 613 614

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

615
    TRACE("%p %x\n",hwnd, offset);
Alexandre Julliard's avatar
Alexandre Julliard committed
616

617
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
618

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
    if (class == CLASS_OTHER_PROCESS)
    {
        SERVER_START_REQ( set_class_info )
        {
            req->window = hwnd;
            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;
    }

634
    if (offset <= class->cbClsExtra - sizeof(WORD))
635
        memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
636 637 638
    else
        SetLastError( ERROR_INVALID_INDEX );
    release_class_ptr( class );
639
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
640 641 642
}


Alexandre Julliard's avatar
Alexandre Julliard committed
643
/***********************************************************************
644 645 646
 *             CLASS_GetClassLong
 *
 * Implementation of GetClassLong(Ptr)A/W
Alexandre Julliard's avatar
Alexandre Julliard committed
647
 */
648 649
static ULONG_PTR CLASS_GetClassLong( HWND hwnd, INT offset, UINT size,
                                     BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
650
{
651
    CLASS *class;
652
    ULONG_PTR retvalue = 0;
653

654
    TRACE("%p %d\n", hwnd, offset);
655

656
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
657

658 659 660 661 662 663 664
    if (class == CLASS_OTHER_PROCESS)
    {
        SERVER_START_REQ( set_class_info )
        {
            req->window = hwnd;
            req->flags = 0;
            req->extra_offset = (offset >= 0) ? offset : -1;
665
            req->extra_size = (offset >= 0) ? size : 0;
666 667 668 669
            if (!wine_server_call_err( req ))
            {
                switch(offset)
                {
670 671 672 673 674 675
                case GCLP_HBRBACKGROUND:
                case GCLP_HCURSOR:
                case GCLP_HICON:
                case GCLP_HICONSM:
                case GCLP_WNDPROC:
                case GCLP_MENUNAME:
676 677
                    FIXME( "offset %d (%s) not supported on other process window %p\n",
			   offset, SPY_GetClassLongOffsetName(offset), hwnd );
678 679 680 681 682 683 684 685 686 687 688
                    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;
689
                case GCLP_HMODULE:
690
                    retvalue = (ULONG_PTR)reply->old_instance;
691 692 693 694 695
                    break;
                case GCW_ATOM:
                    retvalue = reply->old_atom;
                    break;
                default:
696 697 698 699 700 701 702 703 704 705 706 707
                    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) );
                    }
708 709 710 711 712 713 714 715 716
                    else SetLastError( ERROR_INVALID_INDEX );
                    break;
                }
            }
        }
        SERVER_END_REQ;
        return retvalue;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
717 718
    if (offset >= 0)
    {
719 720 721 722 723 724 725 726 727 728 729
        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) );
        }
730 731 732 733
        else
            SetLastError( ERROR_INVALID_INDEX );
        release_class_ptr( class );
        return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
734
    }
735

Alexandre Julliard's avatar
Alexandre Julliard committed
736 737
    switch(offset)
    {
738
    case GCLP_HBRBACKGROUND:
739
        retvalue = (ULONG_PTR)class->hbrBackground;
740
        break;
741
    case GCLP_HCURSOR:
742
        retvalue = (ULONG_PTR)class->hCursor;
743
        break;
744
    case GCLP_HICON:
745
        retvalue = (ULONG_PTR)class->hIcon;
746
        break;
747
    case GCLP_HICONSM:
748
        retvalue = (ULONG_PTR)class->hIconSm;
749 750
        break;
    case GCL_STYLE:
751
        retvalue = class->style;
752 753
        break;
    case GCL_CBWNDEXTRA:
754
        retvalue = class->cbWndExtra;
755 756
        break;
    case GCL_CBCLSEXTRA:
757
        retvalue = class->cbClsExtra;
758
        break;
759
    case GCLP_HMODULE:
760
        retvalue = (ULONG_PTR)class->hInstance;
761
        break;
762
    case GCLP_WNDPROC:
763
        retvalue = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
764
        break;
765
    case GCLP_MENUNAME:
766 767 768 769 770
        retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
        if (unicode)
            retvalue = (ULONG_PTR)CLASS_GetMenuNameW( class );
        else
            retvalue = (ULONG_PTR)CLASS_GetMenuNameA( class );
771 772
        break;
    case GCW_ATOM:
773
        retvalue = class->atomName;
774 775 776 777
        break;
    default:
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
778
    }
779
    release_class_ptr( class );
780
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
781 782 783 784
}


/***********************************************************************
785
 *		GetClassLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
786
 */
787
DWORD WINAPI GetClassLongW( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
788
{
789 790
    return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), TRUE );
}
791

792

793

794 795 796 797 798 799
/***********************************************************************
 *		GetClassLongA (USER32.@)
 */
DWORD WINAPI GetClassLongA( HWND hwnd, INT offset )
{
    return CLASS_GetClassLong( hwnd, offset, sizeof(DWORD), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
800 801 802
}


Alexandre Julliard's avatar
Alexandre Julliard committed
803
/***********************************************************************
804
 *		SetClassWord (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
805
 */
806
WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
807
{
808
    CLASS *class;
Alexandre Julliard's avatar
Alexandre Julliard committed
809
    WORD retval = 0;
810 811 812

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

813
    TRACE("%p %d %x\n", hwnd, offset, newval);
814

815
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
816

817
    SERVER_START_REQ( set_class_info )
Alexandre Julliard's avatar
Alexandre Julliard committed
818
    {
819 820 821 822 823 824 825 826 827 828 829
        req->window = hwnd;
        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
830
    }
831
    SERVER_END_REQ;
832
    release_class_ptr( class );
Alexandre Julliard's avatar
Alexandre Julliard committed
833 834 835 836 837
    return retval;
}


/***********************************************************************
838 839 840
 *             CLASS_SetClassLong
 *
 * Implementation of SetClassLong(Ptr)A/W
Alexandre Julliard's avatar
Alexandre Julliard committed
841
 */
842 843
static ULONG_PTR CLASS_SetClassLong( HWND hwnd, INT offset, LONG_PTR newval,
                                     UINT size, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
844
{
845
    CLASS *class;
846
    ULONG_PTR retval = 0;
847

848
    TRACE("%p %d %lx\n", hwnd, offset, newval);
849

850
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
851

Alexandre Julliard's avatar
Alexandre Julliard committed
852 853
    if (offset >= 0)
    {
854
        if (set_server_info( hwnd, offset, newval, size ))
Alexandre Julliard's avatar
Alexandre Julliard committed
855
        {
856
            void *ptr = (char *)(class + 1) + offset;
857 858 859 860 861 862 863 864 865 866 867 868 869
            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
870 871
        }
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
872 873
    else switch(offset)
    {
874
    case GCLP_MENUNAME:
875 876 877 878
        if ( unicode )
            CLASS_SetMenuNameW( class, (LPCWSTR)newval );
        else
            CLASS_SetMenuNameA( class, (LPCSTR)newval );
879 880
        retval = 0;  /* Old value is now meaningless anyway */
        break;
881
    case GCLP_WNDPROC:
882 883 884
        retval = (ULONG_PTR)WINPROC_GetProc( class->winproc, unicode );
        class->winproc = WINPROC_AllocProc( unicode ? NULL : (WNDPROC)newval,
                                            unicode ? (WNDPROC)newval : NULL );
885
        break;
886
    case GCLP_HBRBACKGROUND:
887
        retval = (ULONG_PTR)class->hbrBackground;
888
        class->hbrBackground = (HBRUSH)newval;
889
        break;
890
    case GCLP_HCURSOR:
891
        retval = (ULONG_PTR)class->hCursor;
892
        class->hCursor = (HCURSOR)newval;
893
        break;
894
    case GCLP_HICON:
895
        retval = (ULONG_PTR)class->hIcon;
896
        class->hIcon = (HICON)newval;
897
        break;
898
    case GCLP_HICONSM:
899
        retval = (ULONG_PTR)class->hIconSm;
900
        class->hIconSm = (HICON)newval;
901 902
        break;
    case GCL_STYLE:
903 904
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->style;
905 906 907
        class->style = newval;
        break;
    case GCL_CBWNDEXTRA:
908 909
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->cbWndExtra;
910 911
        class->cbWndExtra = newval;
        break;
912
    case GCLP_HMODULE:
913 914
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = (ULONG_PTR)class->hInstance;
915
        class->hInstance = (HINSTANCE)newval;
916 917
        break;
    case GCW_ATOM:
918 919
        if (!set_server_info( hwnd, offset, newval, size )) break;
        retval = class->atomName;
920 921
        class->atomName = newval;
        break;
922 923 924
    case GCL_CBCLSEXTRA:  /* cannot change this one */
        SetLastError( ERROR_INVALID_PARAMETER );
        break;
925 926 927
    default:
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
928
    }
929
    release_class_ptr( class );
Alexandre Julliard's avatar
Alexandre Julliard committed
930 931
    return retval;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
932 933 934


/***********************************************************************
935
 *		SetClassLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
936
 */
937
DWORD WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
938
{
939
    TRACE("%p %d %x\n", hwnd, offset, newval);
Alexandre Julliard's avatar
Alexandre Julliard committed
940

941 942
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), TRUE );
}
943 944


945 946 947 948 949
/***********************************************************************
 *		SetClassLongA (USER32.@)
 */
DWORD WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
{
950
    TRACE("%p %d %x\n", hwnd, offset, newval);
951

952
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954
}

Alexandre Julliard's avatar
Alexandre Julliard committed
955

Alexandre Julliard's avatar
Alexandre Julliard committed
956
/***********************************************************************
957
 *		GetClassNameA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
958
 */
959
INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
960
{
961 962
    char tmpbuf[MAX_ATOM_LEN + 1];
    INT ret;
963

964 965 966 967 968 969 970 971 972 973 974
    TRACE("%p %p %d\n", hwnd, buffer, count);

    if (count <= 0) return 0;

    ret = GlobalGetAtomNameA( GetClassLongW( hwnd, GCW_ATOM ), tmpbuf, MAX_ATOM_LEN + 1 );
    if (ret)
    {
        ret = min(count - 1, ret);
        memcpy(buffer, tmpbuf, ret);
        buffer[ret] = 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
975
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
976 977 978 979
}


/***********************************************************************
980
 *		GetClassNameW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
981
 */
982
INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
983
{
984 985
    WCHAR tmpbuf[MAX_ATOM_LEN + 1];
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
986

987 988 989 990 991 992 993 994 995 996 997
    TRACE("%p %p %d\n", hwnd, buffer, count);

    if (count <= 0) return 0;

    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;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
998
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
999 1000 1001
}


1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
/***********************************************************************
 *		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
1020
/***********************************************************************
1021
 *		GetClassInfoA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1022
 */
1023
BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1024
{
1025 1026
    WNDCLASSEXA wcex;
    UINT ret = GetClassInfoExA( hInstance, name, &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
1027

1028
    if (ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
1029
    {
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
        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
1040
    }
1041
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1042 1043 1044 1045
}


/***********************************************************************
1046
 *		GetClassInfoW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
 */
1048
BOOL WINAPI GetClassInfoW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSW *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
{
1050 1051
    WNDCLASSEXW wcex;
    UINT ret = GetClassInfoExW( hInstance, name, &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
1052

1053
    if (ret)
1054
    {
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
        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;
1065
    }
1066
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1067 1068 1069 1070
}


/***********************************************************************
1071
 *		GetClassInfoExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1072
 */
1073
BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
{
1075
    ATOM atom = HIWORD(name) ? GlobalFindAtomA( name ) : LOWORD(name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077
    CLASS *classPtr;

1078 1079 1080
    TRACE("%p %s %x %p\n", hInstance, debugstr_a(name), atom, wc);

    if (!hInstance) hInstance = user32_module;
1081

1082 1083 1084 1085 1086
    if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1087
    wc->style         = classPtr->style;
1088
    wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1089 1090
    wc->cbClsExtra    = classPtr->cbClsExtra;
    wc->cbWndExtra    = classPtr->cbWndExtra;
1091
    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1092 1093 1094 1095
    wc->hIcon         = (HICON)classPtr->hIcon;
    wc->hIconSm       = (HICON)classPtr->hIconSm;
    wc->hCursor       = (HCURSOR)classPtr->hCursor;
    wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096
    wc->lpszMenuName  = CLASS_GetMenuNameA( classPtr );
1097
    wc->lpszClassName = name;
1098
    release_class_ptr( classPtr );
1099

1100 1101
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1102 1103 1104 1105
}


/***********************************************************************
1106
 *		GetClassInfoExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1107
 */
1108
BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1109
{
1110
    ATOM atom = HIWORD(name) ? GlobalFindAtomW( name ) : LOWORD(name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1111
    CLASS *classPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1112

1113 1114 1115
    TRACE("%p %s %x %p\n", hInstance, debugstr_w(name), atom, wc);

    if (!hInstance) hInstance = user32_module;
1116

1117 1118 1119 1120 1121
    if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
    wc->style         = classPtr->style;
1123
    wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1124 1125
    wc->cbClsExtra    = classPtr->cbClsExtra;
    wc->cbWndExtra    = classPtr->cbWndExtra;
1126
    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1127 1128 1129 1130
    wc->hIcon         = (HICON)classPtr->hIcon;
    wc->hIconSm       = (HICON)classPtr->hIconSm;
    wc->hCursor       = (HCURSOR)classPtr->hCursor;
    wc->hbrBackground = (HBRUSH)classPtr->hbrBackground;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131
    wc->lpszMenuName  = CLASS_GetMenuNameW( classPtr );
1132
    wc->lpszClassName = name;
1133
    release_class_ptr( classPtr );
1134

1135 1136
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1137
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1138 1139


1140 1141
#if 0  /* toolhelp is in kernel, so this cannot work */

Alexandre Julliard's avatar
Alexandre Julliard committed
1142
/***********************************************************************
1143
 *		ClassFirst (TOOLHELP.69)
Alexandre Julliard's avatar
Alexandre Julliard committed
1144
 */
1145
BOOL16 WINAPI ClassFirst16( CLASSENTRY *pClassEntry )
Alexandre Julliard's avatar
Alexandre Julliard committed
1146
{
1147
    TRACE("%p\n",pClassEntry);
Alexandre Julliard's avatar
Alexandre Julliard committed
1148
    pClassEntry->wNext = 1;
1149
    return ClassNext16( pClassEntry );
Alexandre Julliard's avatar
Alexandre Julliard committed
1150 1151 1152 1153
}


/***********************************************************************
1154
 *		ClassNext (TOOLHELP.70)
Alexandre Julliard's avatar
Alexandre Julliard committed
1155
 */
1156
BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
Alexandre Julliard's avatar
Alexandre Julliard committed
1157
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1158 1159
    int i;
    CLASS *class = firstClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1160

1161
    TRACE("%p\n",pClassEntry);
1162

Alexandre Julliard's avatar
Alexandre Julliard committed
1163 1164 1165 1166 1167 1168 1169
    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
1170
    pClassEntry->hInst = class->hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
1171
    pClassEntry->wNext++;
1172
    GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
Alexandre Julliard's avatar
Alexandre Julliard committed
1173
                          sizeof(pClassEntry->szClassName) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175
    return TRUE;
}
1176
#endif
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200

/* 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 )
{
1201
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1202 1203 1204 1205 1206 1207 1208
}

/***********************************************************************
 *		GetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
{
1209
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1210 1211 1212 1213 1214 1215 1216
}

/***********************************************************************
 *		SetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
{
1217
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1218 1219 1220 1221 1222 1223 1224
}

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