class.c 41.9 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
    list_remove( &classPtr->entry );
    if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
        DeleteObject( classPtr->hbrBackground );
295
    DestroyIcon( classPtr->hIconSmIntern );
296 297 298
    HeapFree( GetProcessHeap(), 0, classPtr->menuName );
    HeapFree( GetProcessHeap(), 0, classPtr );
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
299 300 301
}


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

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

315 316
    if (!name) return NULL;

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

        LIST_FOR_EACH( ptr, &class_list )
Alexandre Julliard's avatar
Alexandre Julliard committed
322
        {
323 324 325 326 327 328 329
            CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
            if (atom)
            {
                if (class->atomName != atom) continue;
            }
            else
            {
330
                if (strcmpiW( class->name, name )) continue;
331 332 333 334 335 336
            }
            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
337
        }
338 339
        USER_Unlock();

340
        if (atom) break;
341 342 343 344
        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
345
    }
346

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

Alexandre Julliard's avatar
Alexandre Julliard committed
351

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

363 364
    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
365 366 367

    /* Fix the extra bytes value */

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

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

376 377 378 379
    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) );

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

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

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

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


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

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

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


435
/***********************************************************************
436
 *           register_builtins
437
 */
438
static BOOL WINAPI register_builtins( INIT_ONCE *once, void *param, void **context )
439 440 441 442 443
{
    register_builtin( &BUTTON_builtin_class );
    register_builtin( &COMBO_builtin_class );
    register_builtin( &COMBOLBOX_builtin_class );
    register_builtin( &DIALOG_builtin_class );
444
    register_builtin( &EDIT_builtin_class );
445 446 447 448 449 450
    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 );
451
    register_builtin( &IME_builtin_class );
452 453 454 455 456
    return TRUE;
}


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


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


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


484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
/***********************************************************************
 *           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
504
/***********************************************************************
505
 *		RegisterClassA (USER32.@)
506 507 508
 *
 * Register a window class.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
509 510 511
 * RETURNS
 *	>0: Unique identifier
 *	0: Failure
Alexandre Julliard's avatar
Alexandre Julliard committed
512
 */
513
ATOM WINAPI RegisterClassA( const WNDCLASSA* wc ) /* [in] Address of structure with class data */
514
{
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
    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
530
}
Alexandre Julliard's avatar
Alexandre Julliard committed
531

Alexandre Julliard's avatar
Alexandre Julliard committed
532 533

/***********************************************************************
534
 *		RegisterClassW (USER32.@)
535 536
 *
 * See RegisterClassA.
Alexandre Julliard's avatar
Alexandre Julliard committed
537
 */
538
ATOM WINAPI RegisterClassW( const WNDCLASSW* wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
539
{
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    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
555 556 557 558
}


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

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

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

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

581 582 583 584 585 586 587 588 589 590 591 592
        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
593

594 595
    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,
596
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
597

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


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

623
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
624

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

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

637 638 639 640
    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,
641
          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
642

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


Alexandre Julliard's avatar
Alexandre Julliard committed
659
/***********************************************************************
660
 *		UnregisterClassA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
661
 */
662
BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
663
{
664 665 666 667 668 669 670 671 672
    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
673
}
Alexandre Julliard's avatar
Alexandre Julliard committed
674 675

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

682
    GetDesktopWindow();  /* create the desktop window to trigger builtin class registration */
683

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
697 698

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

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

708
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
709

710 711 712 713
    if (class == CLASS_OTHER_PROCESS)
    {
        SERVER_START_REQ( set_class_info )
        {
714
            req->window = wine_server_user_handle( hwnd );
715 716 717 718 719 720 721 722 723 724
            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;
    }

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


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

745
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
746

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

Alexandre Julliard's avatar
Alexandre Julliard committed
806 807
    if (offset >= 0)
    {
808 809 810 811 812 813 814 815 816 817 818
        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) );
        }
819 820 821 822
        else
            SetLastError( ERROR_INVALID_INDEX );
        release_class_ptr( class );
        return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
823
    }
824

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


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

881

882

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


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

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

902
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
903

904
    SERVER_START_REQ( set_class_info )
Alexandre Julliard's avatar
Alexandre Julliard committed
905
    {
906
        req->window = wine_server_user_handle( hwnd );
907 908 909 910 911 912 913 914 915 916
        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
917
    }
918
    SERVER_END_REQ;
919
    release_class_ptr( class );
Alexandre Julliard's avatar
Alexandre Julliard committed
920 921 922 923 924
    return retval;
}


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

935
    if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
936

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


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


1046 1047 1048 1049 1050 1051
/***********************************************************************
 *		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
1052 1053
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1054

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

    if (count <= 0) return 0;
1064 1065 1066 1067
    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
1068 1069 1070 1071
}


/***********************************************************************
1072
 *		GetClassNameW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
 */
1074
INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
1075
{
1076
    CLASS *class;
1077
    INT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1078

1079 1080 1081 1082
    TRACE("%p %p %d\n", hwnd, buffer, count);

    if (count <= 0) return 0;

1083 1084 1085
    if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;

    if (class == CLASS_OTHER_PROCESS)
1086
    {
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
        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 );
1102
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1103
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1104 1105 1106
}


1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
/***********************************************************************
 *		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
1125
/***********************************************************************
1126
 *		GetClassInfoA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1127
 */
1128
BOOL WINAPI GetClassInfoA( HINSTANCE hInstance, LPCSTR name, WNDCLASSA *wc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1129
{
1130 1131
    WNDCLASSEXA wcex;
    UINT ret = GetClassInfoExA( hInstance, name, &wcex );
Alexandre Julliard's avatar
Alexandre Julliard committed
1132

1133
    if (ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
1134
    {
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
        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
1145
    }
1146
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149 1150
}


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

1158
    if (ret)
1159
    {
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
        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;
1170
    }
1171
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1172 1173 1174 1175
}


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

1183
    TRACE("%p %s %p\n", hInstance, debugstr_a(name), wc);
1184

1185 1186 1187 1188 1189 1190
    if (!wc)
    {
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }

1191
    if (!hInstance) hInstance = user32_module;
1192

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
    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)
1203 1204 1205 1206
    {
        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1207
    wc->style         = classPtr->style;
1208
    wc->lpfnWndProc   = WINPROC_GetProc( classPtr->winproc, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1209 1210
    wc->cbClsExtra    = classPtr->cbClsExtra;
    wc->cbWndExtra    = classPtr->cbWndExtra;
1211
    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
1212
    wc->hIcon         = classPtr->hIcon;
1213
    wc->hIconSm       = classPtr->hIconSm ? classPtr->hIconSm : classPtr->hIconSmIntern;
1214 1215
    wc->hCursor       = classPtr->hCursor;
    wc->hbrBackground = classPtr->hbrBackground;
Alexandre Julliard's avatar
Alexandre Julliard committed
1216
    wc->lpszMenuName  = CLASS_GetMenuNameA( classPtr );
1217
    wc->lpszClassName = name;
1218
    atom = classPtr->atomName;
1219
    release_class_ptr( classPtr );
1220

1221 1222
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225 1226
}


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

1234
    TRACE("%p %s %p\n", hInstance, debugstr_w(name), wc);
1235

1236 1237 1238 1239 1240 1241
    if (!wc)
    {
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }

1242
    if (!hInstance) hInstance = user32_module;
1243

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

1263 1264
    /* We must return the atom of the class here instead of just TRUE. */
    return atom;
Alexandre Julliard's avatar
Alexandre Julliard committed
1265
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1266 1267


1268 1269
#if 0  /* toolhelp is in kernel, so this cannot work */

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


/***********************************************************************
1282
 *		ClassNext (TOOLHELP.70)
Alexandre Julliard's avatar
Alexandre Julliard committed
1283
 */
1284
BOOL16 WINAPI ClassNext16( CLASSENTRY *pClassEntry )
Alexandre Julliard's avatar
Alexandre Julliard committed
1285
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1286 1287
    int i;
    CLASS *class = firstClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1288

1289
    TRACE("%p\n",pClassEntry);
1290

Alexandre Julliard's avatar
Alexandre Julliard committed
1291 1292 1293 1294 1295 1296 1297
    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
1298
    pClassEntry->hInst = class->hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
1299
    pClassEntry->wNext++;
1300
    GlobalGetAtomNameA( class->atomName, pClassEntry->szClassName,
Alexandre Julliard's avatar
Alexandre Julliard committed
1301
                          sizeof(pClassEntry->szClassName) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1302 1303
    return TRUE;
}
1304
#endif
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328

/* 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 )
{
1329
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), FALSE );
1330 1331 1332 1333 1334 1335 1336
}

/***********************************************************************
 *		GetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI GetClassLongPtrW( HWND hwnd, INT offset )
{
1337
    return CLASS_GetClassLong( hwnd, offset, sizeof(ULONG_PTR), TRUE );
1338 1339 1340 1341 1342 1343 1344
}

/***********************************************************************
 *		SetClassLongPtrW (USER32.@)
 */
ULONG_PTR WINAPI SetClassLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
{
1345
    return CLASS_SetClassLong( hwnd, offset, newval, sizeof(LONG_PTR), TRUE );
1346 1347 1348 1349 1350 1351 1352
}

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