win.c 117 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Window related functions
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1993, 1994 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
20

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

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

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

41
WINE_DEFAULT_DEBUG_CHANNEL(win);
42

43 44
#define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
#define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45

46
static DWORD process_layout = ~0u;
47

48 49 50 51 52 53 54 55 56 57 58
static struct list window_surfaces = LIST_INIT( window_surfaces );

static CRITICAL_SECTION surfaces_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &surfaces_section,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
};
static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };

59 60
/**********************************************************************/

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/* helper for Get/SetWindowLong */
static inline LONG_PTR get_win_data( const void *ptr, UINT size )
{
    if (size == sizeof(WORD))
    {
        WORD ret;
        memcpy( &ret, ptr, sizeof(ret) );
        return ret;
    }
    else if (size == sizeof(DWORD))
    {
        DWORD ret;
        memcpy( &ret, ptr, sizeof(ret) );
        return ret;
    }
    else
    {
        LONG_PTR ret;
        memcpy( &ret, ptr, sizeof(ret) );
        return ret;
    }
}

/* helper for Get/SetWindowLong */
static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
{
    if (size == sizeof(WORD))
    {
        WORD newval = val;
        memcpy( ptr, &newval, sizeof(newval) );
    }
    else if (size == sizeof(DWORD))
    {
        DWORD newval = val;
        memcpy( ptr, &newval, sizeof(newval) );
    }
    else
    {
        memcpy( ptr, &val, sizeof(val) );
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
103

104
static void *user_handles[NB_USER_HANDLES];
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
/***********************************************************************
 *           alloc_user_handle
 */
HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
{
    HANDLE handle = 0;

    SERVER_START_REQ( alloc_user_handle )
    {
        if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
    }
    SERVER_END_REQ;

    if (handle)
    {
        UINT index = USER_HANDLE_TO_INDEX( handle );

        assert( index < NB_USER_HANDLES );
        ptr->handle = handle;
        ptr->type = type;
126
        InterlockedExchangePointer( &user_handles[index], ptr );
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
    }
    return handle;
}


/***********************************************************************
 *           get_user_handle_ptr
 */
void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
{
    struct user_object *ptr;
    WORD index = USER_HANDLE_TO_INDEX( handle );

    if (index >= NB_USER_HANDLES) return NULL;

    USER_Lock();
    if ((ptr = user_handles[index]))
    {
        if (ptr->type == type &&
            ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
             !HIWORD(handle) || HIWORD(handle) == 0xffff))
            return ptr;
        ptr = NULL;
    }
    else ptr = OBJ_OTHER_PROCESS;
    USER_Unlock();
    return ptr;
}


/***********************************************************************
 *           release_user_handle_ptr
 */
void release_user_handle_ptr( void *ptr )
{
162
    assert( ptr && ptr != OBJ_OTHER_PROCESS );
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    USER_Unlock();
}


/***********************************************************************
 *           free_user_handle
 */
void *free_user_handle( HANDLE handle, enum user_obj_type type )
{
    struct user_object *ptr;
    WORD index = USER_HANDLE_TO_INDEX( handle );

    if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
    {
        SERVER_START_REQ( free_user_handle )
        {
            req->handle = wine_server_user_handle( handle );
180 181
            if (wine_server_call( req )) ptr = NULL;
            else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
182 183
        }
        SERVER_END_REQ;
184
        USER_Unlock();
185 186 187 188 189
    }
    return ptr;
}


190 191 192 193 194
/***********************************************************************
 *           create_window_handle
 *
 * Create a window handle with the server.
 */
195
static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
196
                                  HINSTANCE instance, BOOL unicode )
197
{
198
    WORD index;
199
    WND *win;
200
    HWND handle = 0, full_parent = 0, full_owner = 0;
201 202
    struct tagCLASS *class = NULL;
    int extra_bytes = 0;
203

204
    SERVER_START_REQ( create_window )
205
    {
206 207
        req->parent   = wine_server_user_handle( parent );
        req->owner    = wine_server_user_handle( owner );
208
        req->instance = wine_server_client_ptr( instance );
209 210
        if (!(req->atom = get_int_atom_value( name )) && name)
            wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
211 212
        if (!wine_server_call_err( req ))
        {
213
            handle      = wine_server_ptr_handle( reply->handle );
214 215
            full_parent = wine_server_ptr_handle( reply->parent );
            full_owner  = wine_server_ptr_handle( reply->owner );
216
            extra_bytes = reply->extra;
217
            class       = wine_server_get_ptr( reply->class_ptr );
218
        }
219
    }
220
    SERVER_END_REQ;
221

222 223
    if (!handle)
    {
224
        WARN( "error %d creating window\n", GetLastError() );
225 226 227
        return NULL;
    }

228 229
    if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                           sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
230
    {
231 232
        SERVER_START_REQ( destroy_window )
        {
233
            req->handle = wine_server_user_handle( handle );
234 235 236 237
            wine_server_call( req );
        }
        SERVER_END_REQ;
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
238 239
        return NULL;
    }
240

241 242 243 244
    if (!parent)  /* if parent is 0 we don't have a desktop window yet */
    {
        struct user_thread_info *thread_info = get_user_thread_info();

245 246 247 248 249 250 251 252 253 254 255
        if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
        {
            if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
            else assert( full_parent == thread_info->top_window );
            if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
                ERR( "failed to create desktop window\n" );
        }
        else  /* HWND_MESSAGE parent */
        {
            if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
        }
256 257
    }

258 259
    USER_Lock();

260
    index = USER_HANDLE_TO_INDEX(handle);
261
    assert( index < NB_USER_HANDLES );
262 263
    win->obj.handle = handle;
    win->obj.type   = USER_WINDOW;
264 265
    win->parent     = full_parent;
    win->owner      = full_owner;
266 267
    win->class      = class;
    win->winproc    = get_class_winproc( class );
268
    win->cbWndExtra = extra_bytes;
269
    InterlockedExchangePointer( &user_handles[index], win );
270
    if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
271 272 273 274 275 276 277 278 279
    return win;
}


/***********************************************************************
 *           free_window_handle
 *
 * Free a window handle.
 */
280
static void free_window_handle( HWND hwnd )
281
{
282
    struct user_object *ptr;
283
    WORD index = USER_HANDLE_TO_INDEX(hwnd);
284

285
    if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
286 287 288
    {
        SERVER_START_REQ( destroy_window )
        {
289
            req->handle = wine_server_user_handle( hwnd );
290 291
            if (wine_server_call_err( req )) ptr = NULL;
            else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
292 293
        }
        SERVER_END_REQ;
294
        USER_Unlock();
295
        HeapFree( GetProcessHeap(), 0, ptr );
296 297 298 299
    }
}


300 301 302 303 304 305
/*******************************************************************
 *           list_window_children
 *
 * Build an array of the children of a given window. The array must be
 * freed with HeapFree. Returns NULL when no windows are found.
 */
306
static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
307
{
308
    HWND *list;
309
    int i, size = 128;
310 311 312 313
    ATOM atom = get_int_atom_value( class );

    /* empty class is not the same as NULL class */
    if (!atom && class && !class[0]) return NULL;
314

315
    for (;;)
316
    {
317 318 319 320 321
        int count = 0;

        if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;

        SERVER_START_REQ( get_window_children )
322
        {
323
            req->desktop = wine_server_obj_handle( desktop );
324
            req->parent = wine_server_user_handle( hwnd );
325
            req->tid = tid;
326 327
            req->atom = atom;
            if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
328
            wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
329
            if (!wine_server_call( req )) count = reply->count;
330
        }
331 332 333
        SERVER_END_REQ;
        if (count && count < size)
        {
334 335 336
            /* start from the end since HWND is potentially larger than user_handle_t */
            for (i = count - 1; i >= 0; i--)
                list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
337 338 339 340 341 342
            list[count] = 0;
            return list;
        }
        HeapFree( GetProcessHeap(), 0, list );
        if (!count) break;
        size = count + 1;  /* restart with a large enough buffer */
343
    }
344
    return NULL;
345 346 347
}


348 349 350 351 352 353 354 355 356 357
/*******************************************************************
 *           list_window_parents
 *
 * Build an array of all parents of a given window, starting with
 * the immediate parent. The array must be freed with HeapFree.
 */
static HWND *list_window_parents( HWND hwnd )
{
    WND *win;
    HWND current, *list;
358
    int i, pos = 0, size = 16, count;
359 360 361 362 363 364 365 366

    if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;

    current = hwnd;
    for (;;)
    {
        if (!(win = WIN_GetPtr( current ))) goto empty;
        if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
367
        if (win == WND_DESKTOP)
368 369
        {
            if (!pos) goto empty;
370
            list[pos] = 0;
371 372
            return list;
        }
373 374
        list[pos] = current = win->parent;
        WIN_ReleasePtr( win );
375
        if (!current) return list;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        if (++pos == size - 1)
        {
            /* need to grow the list */
            HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
            if (!new_list) goto empty;
            list = new_list;
            size += 16;
        }
    }

    /* at least one parent belongs to another process, have to query the server */

    for (;;)
    {
        count = 0;
        SERVER_START_REQ( get_window_parents )
        {
393 394
            req->handle = wine_server_user_handle( hwnd );
            wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
395 396 397 398 399 400
            if (!wine_server_call( req )) count = reply->count;
        }
        SERVER_END_REQ;
        if (!count) goto empty;
        if (size > count)
        {
401 402 403
            /* start from the end since HWND is potentially larger than user_handle_t */
            for (i = count - 1; i >= 0; i--)
                list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
404 405 406 407 408 409 410 411 412 413 414 415 416 417
            list[count] = 0;
            return list;
        }
        HeapFree( GetProcessHeap(), 0, list );
        size = count + 1;
        if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
    }

 empty:
    HeapFree( GetProcessHeap(), 0, list );
    return NULL;
}


418 419 420 421 422
/*******************************************************************
 *           send_parent_notify
 */
static void send_parent_notify( HWND hwnd, UINT msg )
{
423 424
    if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
        !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
425 426 427 428 429 430
    {
        HWND parent = GetParent(hwnd);
        if (parent && parent != GetDesktopWindow())
            SendMessageW( parent, WM_PARENTNOTIFY,
                          MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
    }
431 432 433
}


434 435 436 437 438 439 440
/*******************************************************************
 *		update_window_state
 *
 * Trigger an update of the window's driver state and surface.
 */
static void update_window_state( HWND hwnd )
{
441
    RECT window_rect, client_rect, valid_rects[2];
442 443

    WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
444
    valid_rects[0] = valid_rects[1] = client_rect;
445
    set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
446 447
                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW,
                    &window_rect, &client_rect, valid_rects );
448 449 450
}


451 452 453 454 455 456 457
/*******************************************************************
 *		get_server_window_text
 *
 * Retrieve the window text from the server.
 */
static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
{
458 459 460
    size_t len = 0;

    SERVER_START_REQ( get_window_text )
461
    {
462
        req->handle = wine_server_user_handle( hwnd );
463 464
        wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
        if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
465
    }
466
    SERVER_END_REQ;
467 468 469 470
    text[len / sizeof(WCHAR)] = 0;
}


471 472 473 474 475
/*******************************************************************
 *           get_hwnd_message_parent
 *
 * Return the parent for HWND_MESSAGE windows.
 */
476
HWND get_hwnd_message_parent(void)
477 478 479 480 481 482 483 484
{
    struct user_thread_info *thread_info = get_user_thread_info();

    if (!thread_info->msg_window) GetDesktopWindow();  /* trigger creation */
    return thread_info->msg_window;
}


485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
/*******************************************************************
 *           is_desktop_window
 *
 * Check if window is the desktop or the HWND_MESSAGE top parent.
 */
BOOL is_desktop_window( HWND hwnd )
{
    struct user_thread_info *thread_info = get_user_thread_info();

    if (!hwnd) return FALSE;
    if (hwnd == thread_info->top_window) return TRUE;
    if (hwnd == thread_info->msg_window) return TRUE;

    if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
    {
        if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
        if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
    }
    return FALSE;
}


507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
/*******************************************************************
 * Dummy window surface for windows that shouldn't get painted.
 */

static void dummy_surface_lock( struct window_surface *window_surface )
{
    /* nothing to do */
}

static void dummy_surface_unlock( struct window_surface *window_surface )
{
    /* nothing to do */
}

static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
{
    static DWORD dummy_data;

    info->bmiHeader.biSize          = sizeof( info->bmiHeader );
    info->bmiHeader.biWidth         = dummy_surface.rect.right;
    info->bmiHeader.biHeight        = dummy_surface.rect.bottom;
    info->bmiHeader.biPlanes        = 1;
    info->bmiHeader.biBitCount      = 32;
    info->bmiHeader.biCompression   = BI_RGB;
    info->bmiHeader.biSizeImage     = 0;
    info->bmiHeader.biXPelsPerMeter = 0;
    info->bmiHeader.biYPelsPerMeter = 0;
    info->bmiHeader.biClrUsed       = 0;
    info->bmiHeader.biClrImportant  = 0;
    return &dummy_data;
}

static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
{
    static RECT dummy_bounds;
    return &dummy_bounds;
}

545 546 547 548 549
static void dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
{
    /* nothing to do */
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
static void dummy_surface_flush( struct window_surface *window_surface )
{
    /* nothing to do */
}

static void dummy_surface_destroy( struct window_surface *window_surface )
{
    /* nothing to do */
}

static const struct window_surface_funcs dummy_surface_funcs =
{
    dummy_surface_lock,
    dummy_surface_unlock,
    dummy_surface_get_bitmap_info,
    dummy_surface_get_bounds,
566
    dummy_surface_set_region,
567 568 569 570 571 572 573
    dummy_surface_flush,
    dummy_surface_destroy
};

struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };


574 575 576 577 578 579 580 581 582
/*******************************************************************
 *           register_window_surface
 *
 * Register a window surface in the global list, possibly replacing another one.
 */
void register_window_surface( struct window_surface *old, struct window_surface *new )
{
    if (old == new) return;
    EnterCriticalSection( &surfaces_section );
583 584
    if (old && old != &dummy_surface) list_remove( &old->entry );
    if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    LeaveCriticalSection( &surfaces_section );
}


/*******************************************************************
 *           flush_window_surfaces
 *
 * Flush pending output from all window surfaces.
 */
void flush_window_surfaces( BOOL idle )
{
    static DWORD last_idle;
    DWORD now;
    struct window_surface *surface;

    EnterCriticalSection( &surfaces_section );
    now = GetTickCount();
    if (idle) last_idle = now;
    /* if not idle, we only flush if there's evidence that the app never goes idle */
604
    else if ((int)(now - last_idle) < 50) goto done;
605 606 607 608 609 610 611 612

    LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
        surface->funcs->flush( surface );
done:
    LeaveCriticalSection( &surfaces_section );
}


613
/***********************************************************************
614
 *           WIN_GetPtr
615
 *
616
 * Return a pointer to the WND structure if local to the process,
Andreas Mohr's avatar
Andreas Mohr committed
617
 * or WND_OTHER_PROCESS if handle may be valid in other process.
618
 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
619
 */
620
WND *WIN_GetPtr( HWND hwnd )
621
{
622
    WND *ptr;
623

624
    if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
625
    {
626
        if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
627
    }
628 629 630 631 632 633 634
    return ptr;
}


/***********************************************************************
 *           WIN_IsCurrentProcess
 *
635
 * Check whether a given window belongs to the current process (and return the full handle).
636
 */
637
HWND WIN_IsCurrentProcess( HWND hwnd )
638 639
{
    WND *ptr;
640
    HWND ret;
641

642
    if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
643
    ret = ptr->obj.handle;
644 645
    WIN_ReleasePtr( ptr );
    return ret;
646 647 648 649 650 651
}


/***********************************************************************
 *           WIN_IsCurrentThread
 *
652
 * Check whether a given window belongs to the current thread (and return the full handle).
653
 */
654
HWND WIN_IsCurrentThread( HWND hwnd )
655 656
{
    WND *ptr;
657
    HWND ret = 0;
658

659
    if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
660
    if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
661
    WIN_ReleasePtr( ptr );
662
    return ret;
663 664 665 666
}


/***********************************************************************
667
 *           WIN_GetFullHandle
668
 *
669
 * Convert a possibly truncated window handle to a full 32-bit handle.
670
 */
671
HWND WIN_GetFullHandle( HWND hwnd )
672 673 674
{
    WND *ptr;

675 676
    if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
    if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
677
    /* do sign extension for -2 and -3 */
678
    if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
679

680 681
    if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;

682 683 684 685 686
    if (ptr == WND_DESKTOP)
    {
        if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
        else return get_hwnd_message_parent();
    }
687

688
    if (ptr != WND_OTHER_PROCESS)
689
    {
690
        hwnd = ptr->obj.handle;
691
        WIN_ReleasePtr( ptr );
692 693
    }
    else  /* may belong to another process */
694 695 696
    {
        SERVER_START_REQ( get_window_info )
        {
697 698
            req->handle = wine_server_user_handle( hwnd );
            if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
699 700 701 702 703 704 705
        }
        SERVER_END_REQ;
    }
    return hwnd;
}


706 707 708 709 710
/***********************************************************************
 *           WIN_SetOwner
 *
 * Change the owner of a window.
 */
711
HWND WIN_SetOwner( HWND hwnd, HWND owner )
712
{
713
    WND *win = WIN_GetPtr( hwnd );
714
    HWND ret = 0;
715

716
    if (!win || win == WND_DESKTOP) return 0;
717
    if (win == WND_OTHER_PROCESS)
Alexandre Julliard's avatar
Alexandre Julliard committed
718
    {
719
        if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
720
        return 0;
721
    }
722 723
    SERVER_START_REQ( set_window_owner )
    {
724 725
        req->handle = wine_server_user_handle( hwnd );
        req->owner  = wine_server_user_handle( owner );
726 727
        if (!wine_server_call( req ))
        {
728 729
            win->owner = wine_server_ptr_handle( reply->full_owner );
            ret = wine_server_ptr_handle( reply->prev_owner );
730
        }
731 732 733
    }
    SERVER_END_REQ;
    WIN_ReleasePtr( win );
734
    return ret;
735 736 737 738 739 740 741 742
}


/***********************************************************************
 *           WIN_SetStyle
 *
 * Change the style of a window.
 */
743
ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
744
{
745
    BOOL ok, made_visible = FALSE;
746
    STYLESTRUCT style;
747 748
    WND *win = WIN_GetPtr( hwnd );

749
    if (!win || win == WND_DESKTOP) return 0;
750 751 752
    if (win == WND_OTHER_PROCESS)
    {
        if (IsWindow(hwnd))
753
            ERR( "cannot set style %x/%x on other process window %p\n",
754
                 set_bits, clear_bits, hwnd );
755 756
        return 0;
    }
757 758 759
    style.styleOld = win->dwStyle;
    style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
    if (style.styleNew == style.styleOld)
760 761
    {
        WIN_ReleasePtr( win );
762
        return style.styleNew;
763 764 765
    }
    SERVER_START_REQ( set_window_info )
    {
766
        req->handle = wine_server_user_handle( hwnd );
767
        req->flags  = SET_WIN_STYLE;
768
        req->style  = style.styleNew;
769
        req->extra_offset = -1;
770
        if ((ok = !wine_server_call( req )))
771
        {
772 773
            style.styleOld = reply->old_style;
            win->dwStyle = style.styleNew;
774 775 776
        }
    }
    SERVER_END_REQ;
777 778

    if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
779
    {
780
        made_visible = (style.styleNew & WS_VISIBLE) != 0;
781 782 783
        invalidate_dce( win, NULL );
    }
    WIN_ReleasePtr( win );
784

785 786
    if (!ok) return 0;

787
    USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
788
    if (made_visible) update_window_state( hwnd );
789

790
    return style.styleOld;
791 792 793
}


794 795 796 797 798
/***********************************************************************
 *           WIN_GetRectangles
 *
 * Get the window and client rectangles.
 */
799
BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
800 801 802 803
{
    WND *win = WIN_GetPtr( hwnd );
    BOOL ret = TRUE;

804 805 806 807 808
    if (!win)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return FALSE;
    }
809 810 811 812
    if (win == WND_DESKTOP)
    {
        RECT rect;
        rect.left = rect.top = 0;
813 814 815 816 817 818 819 820 821 822
        if (hwnd == get_hwnd_message_parent())
        {
            rect.right  = 100;
            rect.bottom = 100;
        }
        else
        {
            rect.right  = GetSystemMetrics(SM_CXSCREEN);
            rect.bottom = GetSystemMetrics(SM_CYSCREEN);
        }
823 824
        if (rectWindow) *rectWindow = rect;
        if (rectClient) *rectClient = rect;
825
        return TRUE;
826
    }
827
    if (win != WND_OTHER_PROCESS)
828
    {
829 830 831
        RECT window_rect = win->rectWindow, client_rect = win->rectClient;

        switch (relative)
832
        {
833 834 835
        case COORDS_CLIENT:
            OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
            OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
836 837
            if (win->dwExStyle & WS_EX_LAYOUTRTL)
                mirror_rect( &win->rectClient, &window_rect );
838 839 840 841
            break;
        case COORDS_WINDOW:
            OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
            OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
842 843
            if (win->dwExStyle & WS_EX_LAYOUTRTL)
                mirror_rect( &win->rectWindow, &client_rect );
844 845
            break;
        case COORDS_PARENT:
846 847 848 849 850 851 852 853 854
            if (win->parent)
            {
                WND *parent = WIN_GetPtr( win->parent );
                if (parent == WND_DESKTOP) break;
                if (!parent || parent == WND_OTHER_PROCESS)
                {
                    WIN_ReleasePtr( win );
                    goto other_process;
                }
855 856 857 858 859 860
                if (parent->flags & WIN_CHILDREN_MOVED)
                {
                    WIN_ReleasePtr( parent );
                    WIN_ReleasePtr( win );
                    goto other_process;
                }
861 862 863 864 865 866 867
                if (parent->dwExStyle & WS_EX_LAYOUTRTL)
                {
                    mirror_rect( &parent->rectClient, &window_rect );
                    mirror_rect( &parent->rectClient, &client_rect );
                }
                WIN_ReleasePtr( parent );
            }
868 869 870
            break;
        case COORDS_SCREEN:
            while (win->parent)
871
            {
872 873 874
                WND *parent = WIN_GetPtr( win->parent );
                if (parent == WND_DESKTOP) break;
                if (!parent || parent == WND_OTHER_PROCESS)
875
                {
876 877
                    WIN_ReleasePtr( win );
                    goto other_process;
878
                }
879
                WIN_ReleasePtr( win );
880 881 882 883 884
                if (parent->flags & WIN_CHILDREN_MOVED)
                {
                    WIN_ReleasePtr( parent );
                    goto other_process;
                }
885
                win = parent;
886 887 888 889 890
                if (win->parent)
                {
                    OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
                    OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
                }
891
            }
892
            break;
893
        }
894 895 896
        if (rectWindow) *rectWindow = window_rect;
        if (rectClient) *rectClient = client_rect;
        WIN_ReleasePtr( win );
897
        return TRUE;
898
    }
899 900 901

other_process:
    SERVER_START_REQ( get_window_rectangles )
902
    {
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
        req->handle = wine_server_user_handle( hwnd );
        req->relative = relative;
        if ((ret = !wine_server_call_err( req )))
        {
            if (rectWindow)
            {
                rectWindow->left   = reply->window.left;
                rectWindow->top    = reply->window.top;
                rectWindow->right  = reply->window.right;
                rectWindow->bottom = reply->window.bottom;
            }
            if (rectClient)
            {
                rectClient->left   = reply->client.left;
                rectClient->top    = reply->client.top;
                rectClient->right  = reply->client.right;
                rectClient->bottom = reply->client.bottom;
            }
        }
922
    }
923
    SERVER_END_REQ;
924 925 926 927
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
928 929 930
/***********************************************************************
 *           WIN_DestroyWindow
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
931
 * Destroy storage associated to a window. "Internals" p.358
Alexandre Julliard's avatar
Alexandre Julliard committed
932
 */
933
LRESULT WIN_DestroyWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
934
{
935 936
    WND *wndPtr;
    HWND *list;
937
    HMENU menu = 0, sys_menu;
938
    HWND icon_title;
939
    struct window_surface *surface;
Alexandre Julliard's avatar
Alexandre Julliard committed
940

941
    TRACE("%p\n", hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
942

Alexandre Julliard's avatar
Alexandre Julliard committed
943
    /* free child windows */
944
    if ((list = WIN_ListChildren( hwnd )))
945
    {
946
        int i;
947 948 949 950 951
        for (i = 0; list[i]; i++)
        {
            if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
            else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
        }
952
        HeapFree( GetProcessHeap(), 0, list );
953
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
954

955
    /* Unlink now so we won't bother with the children later on */
956 957
    SERVER_START_REQ( set_parent )
    {
958
        req->handle = wine_server_user_handle( hwnd );
959 960 961 962
        req->parent = 0;
        wine_server_call( req );
    }
    SERVER_END_REQ;
963

964 965 966
    /*
     * Send the WM_NCDESTROY to the window being destroyed.
     */
967
    SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
968 969 970 971 972

    /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */

    /* free resources associated with the window */

973
    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
974 975
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
        menu = (HMENU)wndPtr->wIDmenu;
976
    sys_menu = wndPtr->hSysMenu;
977 978
    free_dce( wndPtr->dce, hwnd );
    wndPtr->dce = NULL;
979
    icon_title = wndPtr->icon_title;
980 981 982
    HeapFree( GetProcessHeap(), 0, wndPtr->text );
    wndPtr->text = NULL;
    HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
983
    wndPtr->pScroll = NULL;
984
    DestroyIcon( wndPtr->hIconSmall2 );
985 986
    surface = wndPtr->surface;
    wndPtr->surface = NULL;
987 988
    WIN_ReleasePtr( wndPtr );

989
    if (icon_title) DestroyWindow( icon_title );
990 991
    if (menu) DestroyMenu( menu );
    if (sys_menu) DestroyMenu( sys_menu );
992 993 994 995 996
    if (surface)
    {
        register_window_surface( surface, NULL );
        window_surface_release( surface );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
997

998
    USER_Driver->pDestroyWindow( hwnd );
999 1000

    free_window_handle( hwnd );
1001
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1002 1003
}

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014

/***********************************************************************
 *		destroy_thread_window
 *
 * Destroy a window upon exit of its thread.
 */
static void destroy_thread_window( HWND hwnd )
{
    WND *wndPtr;
    HWND *list;
    HMENU menu = 0, sys_menu = 0;
1015
    struct window_surface *surface = NULL;
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
    WORD index;

    /* free child windows */

    if ((list = WIN_ListChildren( hwnd )))
    {
        int i;
        for (i = 0; list[i]; i++)
        {
            if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
            else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
        }
        HeapFree( GetProcessHeap(), 0, list );
    }

    /* destroy the client-side storage */

    index = USER_HANDLE_TO_INDEX(hwnd);
    if (index >= NB_USER_HANDLES) return;
    USER_Lock();
    if ((wndPtr = user_handles[index]))
    {
        if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
        sys_menu = wndPtr->hSysMenu;
        free_dce( wndPtr->dce, hwnd );
1041 1042
        surface = wndPtr->surface;
        wndPtr->surface = NULL;
1043
        InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1044 1045 1046 1047 1048 1049
    }
    USER_Unlock();

    HeapFree( GetProcessHeap(), 0, wndPtr );
    if (menu) DestroyMenu( menu );
    if (sys_menu) DestroyMenu( sys_menu );
1050 1051 1052 1053 1054
    if (surface)
    {
        register_window_surface( surface, NULL );
        window_surface_release( surface );
    }
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
}


/***********************************************************************
 *		destroy_thread_child_windows
 *
 * Destroy child windows upon exit of its thread.
 */
static void destroy_thread_child_windows( HWND hwnd )
{
    HWND *list;
    int i;

    if (WIN_IsCurrentThread( hwnd ))
    {
        destroy_thread_window( hwnd );
    }
    else if ((list = WIN_ListChildren( hwnd )))
    {
        for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
        HeapFree( GetProcessHeap(), 0, list );
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1080
/***********************************************************************
1081
 *           WIN_DestroyThreadWindows
Alexandre Julliard's avatar
Alexandre Julliard committed
1082
 *
1083
 * Destroy all children of 'wnd' owned by the current thread.
Alexandre Julliard's avatar
Alexandre Julliard committed
1084
 */
1085
void WIN_DestroyThreadWindows( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1086
{
1087 1088
    HWND *list;
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1089

1090
    if (!(list = WIN_ListChildren( hwnd ))) return;
1091 1092

    /* reset owners of top-level windows */
1093
    for (i = 0; list[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
1094
    {
1095 1096 1097 1098 1099
        if (!WIN_IsCurrentThread( list[i] ))
        {
            HWND owner = GetWindow( list[i], GW_OWNER );
            if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1100
    }
1101 1102

    for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1103
    HeapFree( GetProcessHeap(), 0, list );
Alexandre Julliard's avatar
Alexandre Julliard committed
1104 1105
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1106

1107
/***********************************************************************
1108
 *           WIN_FixCoordinates
1109 1110 1111 1112
 *
 * Fix the coordinates - Helper for WIN_CreateWindowEx.
 * returns default show mode in sw.
 */
1113
static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1114
{
1115
#define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1116 1117 1118 1119 1120 1121 1122
    POINT pos[2];

    if (cs->dwExStyle & WS_EX_MDICHILD)
    {
        UINT id = 0;

        MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1123
        if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1124 1125 1126 1127

        TRACE("MDI child id %04x\n", id);
    }

1128
    if (cs->style & (WS_CHILD | WS_POPUP))
1129
    {
1130
        if (cs->dwExStyle & WS_EX_MDICHILD)
1131
        {
1132
            if (IS_DEFAULT(cs->x))
1133
            {
1134 1135
                cs->x = pos[0].x;
                cs->y = pos[0].y;
1136
            }
1137 1138
            if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
            if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1139
        }
1140
        else
1141
        {
1142 1143 1144 1145 1146 1147 1148 1149 1150
            if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
            if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
        }
    }
    else  /* overlapped window */
    {
        HMONITOR monitor;
        MONITORINFO mon_info;
        STARTUPINFOW info;
1151

1152
        if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1153

1154
        monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        mon_info.cbSize = sizeof(mon_info);
        GetMonitorInfoW( monitor, &mon_info );
        GetStartupInfoW( &info );

        if (IS_DEFAULT(cs->x))
        {
            if (!IS_DEFAULT(cs->y)) *sw = cs->y;
            cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
            cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
        }
1165

1166 1167 1168
        if (IS_DEFAULT(cs->cx))
        {
            if (info.dwFlags & STARTF_USESIZE)
1169
            {
1170 1171
                cs->cx = info.dwXSize;
                cs->cy = info.dwYSize;
1172
            }
1173
            else
1174
            {
1175 1176
                cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
                cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1177
            }
1178
        }
1179 1180 1181 1182
        /* neither x nor cx are default. Check the y values .
         * In the trace we see Outlook and Outlook Express using
         * cy set to CW_USEDEFAULT when opening the address book.
         */
1183 1184
        else if (IS_DEFAULT(cs->cy))
        {
1185
            FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1186
            cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1187
        }
1188
    }
1189
#undef IS_DEFAULT
1190 1191
}

1192 1193 1194 1195 1196 1197
/***********************************************************************
 *           dump_window_styles
 */
static void dump_window_styles( DWORD style, DWORD exstyle )
{
    TRACE( "style:" );
1198 1199 1200 1201 1202 1203 1204 1205 1206
    if(style & WS_POPUP) TRACE(" WS_POPUP");
    if(style & WS_CHILD) TRACE(" WS_CHILD");
    if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
    if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
    if(style & WS_DISABLED) TRACE(" WS_DISABLED");
    if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
    if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
    if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
    if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1207 1208
    else
    {
1209 1210
        if(style & WS_BORDER) TRACE(" WS_BORDER");
        if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1211
    }
1212 1213 1214 1215
    if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
    if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
    if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
    if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
    if (style & WS_CHILD)
    {
        if(style & WS_GROUP) TRACE(" WS_GROUP");
        if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
    }
    else
    {
        if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
        if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
    }
1226 1227 1228

    /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
#define DUMPED_STYLES \
1229
    ((DWORD)(WS_POPUP | \
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
     WS_CHILD | \
     WS_MINIMIZE | \
     WS_VISIBLE | \
     WS_DISABLED | \
     WS_CLIPSIBLINGS | \
     WS_CLIPCHILDREN | \
     WS_MAXIMIZE | \
     WS_BORDER | \
     WS_DLGFRAME | \
     WS_VSCROLL | \
     WS_HSCROLL | \
     WS_SYSMENU | \
     WS_THICKFRAME | \
     WS_GROUP | \
     WS_TABSTOP | \
     WS_MINIMIZEBOX | \
1246
     WS_MAXIMIZEBOX))
1247

1248
    if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1249
    TRACE("\n");
1250 1251 1252
#undef DUMPED_STYLES

    TRACE( "exstyle:" );
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
    if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
    if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
    if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
    if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
    if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
    if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
    if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
    if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
    if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
    if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
    if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
    if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
    if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
    if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
    if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
    if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
    if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
    if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1271
    if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1272 1273

#define DUMPED_EX_STYLES \
1274
    ((DWORD)(WS_EX_DLGMODALFRAME | \
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
     WS_EX_DRAGDETECT | \
     WS_EX_NOPARENTNOTIFY | \
     WS_EX_TOPMOST | \
     WS_EX_ACCEPTFILES | \
     WS_EX_TRANSPARENT | \
     WS_EX_MDICHILD | \
     WS_EX_TOOLWINDOW | \
     WS_EX_WINDOWEDGE | \
     WS_EX_CLIENTEDGE | \
     WS_EX_CONTEXTHELP | \
     WS_EX_RIGHT | \
     WS_EX_RTLREADING | \
     WS_EX_LEFTSCROLLBAR | \
     WS_EX_CONTROLPARENT | \
     WS_EX_STATICEDGE | \
     WS_EX_APPWINDOW | \
1291
     WS_EX_LAYERED | \
1292
     WS_EX_LAYOUTRTL))
1293

1294
    if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1295
    TRACE("\n");
1296 1297 1298 1299
#undef DUMPED_EX_STYLES
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1300
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1301 1302 1303
 *           WIN_CreateWindowEx
 *
 * Implementation of CreateWindowEx().
Alexandre Julliard's avatar
Alexandre Julliard committed
1304
 */
1305
HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1306
{
1307
    INT cx, cy, style, sw = SW_SHOW;
1308 1309
    LRESULT result;
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1310
    WND *wndPtr;
1311
    HWND hwnd, parent, owner, top_child = 0;
1312 1313 1314
    MDICREATESTRUCTW mdi_cs;
    CBT_CREATEWNDW cbtc;
    CREATESTRUCTW cbcs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1315

1316
    TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1317
          unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1318
          debugstr_w(className),
Alexandre Julliard's avatar
Alexandre Julliard committed
1319 1320
          cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
          cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1321 1322
    if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );

1323 1324 1325 1326 1327 1328
    /* Fix the styles for MDI children */
    if (cs->dwExStyle & WS_EX_MDICHILD)
    {
        UINT flags = 0;

        wndPtr = WIN_GetPtr(cs->hwndParent);
1329
        if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
        {
            flags = wndPtr->flags;
            WIN_ReleasePtr(wndPtr);
        }

        if (!(flags & WIN_ISMDICLIENT))
        {
            WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
            return 0;
        }

        /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
         * MDICREATESTRUCT members have the originally passed values.
         *
         * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
         * have the same layout.
         */
        mdi_cs.szClass = cs->lpszClass;
        mdi_cs.szTitle = cs->lpszName;
        mdi_cs.hOwner = cs->hInstance;
        mdi_cs.x = cs->x;
        mdi_cs.y = cs->y;
        mdi_cs.cx = cs->cx;
        mdi_cs.cy = cs->cy;
        mdi_cs.style = cs->style;
        mdi_cs.lParam = (LPARAM)cs->lpCreateParams;

1357
        cs->lpCreateParams = &mdi_cs;
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375

        if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
        {
            if (cs->style & WS_POPUP)
            {
                TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
                return 0;
            }
            cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
        }
        else
        {
            cs->style &= ~WS_POPUP;
            cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
                WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
        }

        top_child = GetWindow(cs->hwndParent, GW_CHILD);
1376 1377 1378 1379 1380 1381 1382

        if (top_child)
        {
            /* Restore current maximized child */
            if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
            {
                TRACE("Restoring current maximized child %p\n", top_child);
1383 1384 1385 1386 1387 1388 1389 1390
                if (cs->style & WS_MAXIMIZE)
                {
                    /* if the new window is maximized don't bother repainting */
                    SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
                    ShowWindow( top_child, SW_SHOWNORMAL );
                    SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
                }
                else ShowWindow( top_child, SW_SHOWNORMAL );
1391 1392
            }
        }
1393 1394
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1395
    /* Find the parent window */
Alexandre Julliard's avatar
Alexandre Julliard committed
1396

1397
    parent = cs->hwndParent;
1398
    owner = 0;
1399 1400 1401

    if (cs->hwndParent == HWND_MESSAGE)
    {
1402
        cs->hwndParent = parent = get_hwnd_message_parent();
1403 1404
    }
    else if (cs->hwndParent)
Alexandre Julliard's avatar
Alexandre Julliard committed
1405
    {
1406
        if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
Alexandre Julliard's avatar
Alexandre Julliard committed
1407
        {
1408 1409 1410
            parent = GetDesktopWindow();
            owner = cs->hwndParent;
        }
1411 1412 1413 1414 1415 1416
        else
        {
            DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
            if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
                cs->dwExStyle |= WS_EX_LAYOUTRTL;
        }
1417
    }
1418
    else
1419
    {
1420 1421
        static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};

1422 1423 1424
        if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
        {
            WARN("No parent for child window\n" );
1425
            SetLastError(ERROR_TLW_WITH_WSCHILD);
1426 1427
            return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
        }
1428

1429 1430 1431
        /* are we creating the desktop or HWND_MESSAGE parent itself? */
        if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
            (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1432
        {
1433 1434 1435
            DWORD layout;
            GetProcessDefaultLayout( &layout );
            if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1436
            parent = GetDesktopWindow();
1437
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1438
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1439

1440
    WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
Alexandre Julliard's avatar
Alexandre Julliard committed
1441

1442 1443 1444 1445 1446 1447 1448
    if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
        ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
          (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
        cs->dwExStyle |= WS_EX_WINDOWEDGE;
    else
        cs->dwExStyle &= ~WS_EX_WINDOWEDGE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1449
    /* Create the window structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
1450

1451
    if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1452 1453 1454 1455 1456 1457 1458 1459
    {
        WNDCLASSW wc;
        /* if it's a comctl32 class, GetClassInfo will load it, then we can retry */
        if (GetLastError() != ERROR_INVALID_HANDLE ||
            !GetClassInfoW( 0, className, &wc ) ||
            !(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
            return 0;
    }
1460
    hwnd = wndPtr->obj.handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1461

Alexandre Julliard's avatar
Alexandre Julliard committed
1462
    /* Fill the window structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
1463

1464
    wndPtr->tid            = GetCurrentThreadId();
Alexandre Julliard's avatar
Alexandre Julliard committed
1465
    wndPtr->hInstance      = cs->hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
1466
    wndPtr->text           = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1467 1468
    wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
    wndPtr->dwExStyle      = cs->dwExStyle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1469
    wndPtr->wIDmenu        = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1470
    wndPtr->helpContext    = 0;
1471
    wndPtr->pScroll        = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1472
    wndPtr->userdata       = 0;
1473 1474
    wndPtr->hIcon          = 0;
    wndPtr->hIconSmall     = 0;
1475
    wndPtr->hIconSmall2    = 0;
1476 1477
    wndPtr->hSysMenu       = 0;

1478 1479
    wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
    wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1480
    SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1481

1482
    if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1483

1484 1485 1486 1487 1488 1489
    /*
     * Correct the window styles.
     *
     * It affects only the style loaded into the WIN structure.
     */

1490
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1491 1492 1493 1494 1495 1496
    {
        wndPtr->dwStyle |= WS_CLIPSIBLINGS;
        if (!(wndPtr->dwStyle & WS_POPUP))
            wndPtr->dwStyle |= WS_CAPTION;
    }

1497 1498
    /* WS_EX_WINDOWEDGE depends on some other styles */
    if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1499
        wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1500 1501 1502 1503 1504 1505
    else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
    {
        if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
            (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
            wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
    }
1506 1507 1508 1509
    else
        wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;

    if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1510
        wndPtr->flags |= WIN_NEED_SIZE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1511

1512 1513
    SERVER_START_REQ( set_window_info )
    {
1514
        req->handle    = wine_server_user_handle( hwnd );
1515
        req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1516 1517
        req->style     = wndPtr->dwStyle;
        req->ex_style  = wndPtr->dwExStyle;
1518
        req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1519
        req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1520
        req->extra_offset = -1;
1521
        wine_server_call( req );
1522 1523
    }
    SERVER_END_REQ;
Alexandre Julliard's avatar
Alexandre Julliard committed
1524

Alexandre Julliard's avatar
Alexandre Julliard committed
1525 1526
    /* Set the window menu */

1527
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
    {
1529 1530 1531 1532 1533 1534 1535 1536 1537
        if (cs->hMenu)
        {
            if (!MENU_SetMenu(hwnd, cs->hMenu))
            {
                WIN_ReleasePtr( wndPtr );
                free_window_handle( hwnd );
                return 0;
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1538 1539
        else
        {
1540
            LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
Alexandre Julliard's avatar
Alexandre Julliard committed
1541 1542
            if (menuName)
            {
1543
                cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1544
                if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
1545
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1546
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1547
    }
1548
    else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559

    /* call the WH_CBT hook */

    /* the window style passed to the hook must be the real window style,
     * rather than just the window style that the caller to CreateWindowEx
     * passed in, so we have to copy the original CREATESTRUCT and get the
     * the real style. */
    cbcs = *cs;
    cbcs.style = wndPtr->dwStyle;
    cbtc.lpcs = &cbcs;
    cbtc.hwndInsertAfter = HWND_TOP;
1560
    WIN_ReleasePtr( wndPtr );
1561
    if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
Alexandre Julliard's avatar
Alexandre Julliard committed
1562

1563 1564 1565 1566 1567
    /* send the WM_GETMINMAXINFO message and fix the size if needed */

    cx = cs->cx;
    cy = cs->cy;
    if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1568
    {
1569 1570 1571 1572
        POINT maxSize, maxPos, minTrack, maxTrack;
        WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
        if (maxTrack.x < cx) cx = maxTrack.x;
        if (maxTrack.y < cy) cy = maxTrack.y;
1573 1574
        if (minTrack.x > cx) cx = minTrack.x;
        if (minTrack.y > cy) cy = minTrack.y;
1575 1576 1577 1578 1579
    }

    if (cx < 0) cx = 0;
    if (cy < 0) cy = 0;
    SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1580 1581 1582
    /* check for wraparound */
    if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
    if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
    if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;

    /* send WM_NCCREATE */

    TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
    if (unicode)
        result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
    else
        result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
    if (!result)
    {
        WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
        goto failed;
    }

    /* send WM_NCCALCSIZE */

1600
    if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1601 1602
    {
        /* yes, even if the CBT hook was called with HWND_TOP */
1603 1604
        HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
        RECT client_rect = rect;
1605 1606

        /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1607
        MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1608
        SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1609 1610
        MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
        set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1611
    }
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
    else return 0;

    /* send WM_CREATE */

    if (unicode)
        result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
    else
        result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
    if (result == -1) goto failed;

1622 1623 1624 1625
    /* call the driver */

    if (!USER_Driver->pCreateWindow( hwnd )) goto failed;

1626 1627 1628 1629
    NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);

    /* send the size messages */

1630 1631
    if (!(wndPtr = WIN_GetPtr( hwnd )) ||
          wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1632 1633 1634
    if (!(wndPtr->flags & WIN_NEED_SIZE))
    {
        WIN_ReleasePtr( wndPtr );
1635
        WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1636 1637 1638 1639 1640 1641
        SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
                      MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
        SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
    }
    else WIN_ReleasePtr( wndPtr );

1642
    /* Show the window, maximizing or minimizing if needed */
1643

1644 1645 1646 1647 1648 1649 1650 1651 1652
    style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
    if (style & (WS_MINIMIZE | WS_MAXIMIZE))
    {
        RECT newPos;
        UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;

        swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
        swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
        if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1653 1654
        SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
                      newPos.bottom - newPos.top, swFlag );
1655
    }
1656

1657
    /* Notify the parent window only */
1658

1659
    send_parent_notify( hwnd, WM_CREATE );
1660
    if (!IsWindow( hwnd )) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1661

1662
    if (cs->style & WS_VISIBLE)
1663
    {
1664
        if (cs->style & WS_MAXIMIZE)
1665
            sw = SW_SHOW;
1666 1667 1668 1669 1670
        else if (cs->style & WS_MINIMIZE)
            sw = SW_SHOWMINIMIZED;

        ShowWindow( hwnd, sw );
        if (cs->dwExStyle & WS_EX_MDICHILD)
1671
        {
1672 1673 1674
            SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
            /* ShowWindow won't activate child windows */
            SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1675 1676 1677
        }
    }

1678
    /* Call WH_SHELL hook */
1679

1680
    if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1681
        HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1682

1683
    TRACE("created window %p\n", hwnd);
1684
    return hwnd;
1685 1686 1687 1688

failed:
    WIN_DestroyWindow( hwnd );
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1689 1690 1691
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1692
/***********************************************************************
1693
 *		CreateWindowExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1694
 */
1695
HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className,
1696 1697 1698 1699
                                 LPCSTR windowName, DWORD style, INT x,
                                 INT y, INT width, INT height,
                                 HWND parent, HMENU menu,
                                 HINSTANCE instance, LPVOID data )
Alexandre Julliard's avatar
Alexandre Julliard committed
1700
{
1701
    CREATESTRUCTA cs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1702 1703

    cs.lpCreateParams = data;
Alexandre Julliard's avatar
Alexandre Julliard committed
1704 1705
    cs.hInstance      = instance;
    cs.hMenu          = menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1706
    cs.hwndParent     = parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1707 1708 1709 1710 1711
    cs.x              = x;
    cs.y              = y;
    cs.cx             = width;
    cs.cy             = height;
    cs.style          = style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1712 1713
    cs.lpszName       = windowName;
    cs.lpszClass      = className;
Alexandre Julliard's avatar
Alexandre Julliard committed
1714
    cs.dwExStyle      = exStyle;
1715

1716 1717 1718 1719 1720
    if (!IS_INTRESOURCE(className))
    {
        WCHAR bufferW[256];
        if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
            return 0;
1721
        return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1722
    }
1723 1724
    /* Note: we rely on the fact that CREATESTRUCTA and */
    /* CREATESTRUCTW have the same layout. */
1725
    return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1726
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1727 1728


Alexandre Julliard's avatar
Alexandre Julliard committed
1729
/***********************************************************************
1730
 *		CreateWindowExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1731
 */
1732
HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className,
1733 1734 1735 1736
                                 LPCWSTR windowName, DWORD style, INT x,
                                 INT y, INT width, INT height,
                                 HWND parent, HMENU menu,
                                 HINSTANCE instance, LPVOID data )
Alexandre Julliard's avatar
Alexandre Julliard committed
1737
{
1738
    CREATESTRUCTW cs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1739 1740

    cs.lpCreateParams = data;
Alexandre Julliard's avatar
Alexandre Julliard committed
1741 1742
    cs.hInstance      = instance;
    cs.hMenu          = menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1743
    cs.hwndParent     = parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1744 1745 1746 1747 1748
    cs.x              = x;
    cs.y              = y;
    cs.cx             = width;
    cs.cy             = height;
    cs.style          = style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1749 1750
    cs.lpszName       = windowName;
    cs.lpszClass      = className;
Alexandre Julliard's avatar
Alexandre Julliard committed
1751
    cs.dwExStyle      = exStyle;
1752

1753
    return wow_handlers.create_window( &cs, className, instance, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1754 1755
}

1756

Alexandre Julliard's avatar
Alexandre Julliard committed
1757 1758 1759
/***********************************************************************
 *           WIN_SendDestroyMsg
 */
1760
static void WIN_SendDestroyMsg( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1761
{
1762 1763
    GUITHREADINFO info;

1764
    info.cbSize = sizeof(info);
1765 1766 1767
    if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
    {
        if (hwnd == info.hwndCaret) DestroyCaret();
1768
        if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1769
    }
1770 1771 1772 1773

    /*
     * Send the WM_DESTROY to the window.
     */
1774
    SendMessageW( hwnd, WM_DESTROY, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1775

1776 1777 1778 1779
    /*
     * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
     * make sure that the window still exists when we come back.
     */
1780 1781 1782 1783
    if (IsWindow(hwnd))
    {
        HWND* pWndArray;
        int i;
1784

1785
        if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1786

1787
        for (i = 0; pWndArray[i]; i++)
1788 1789 1790
        {
            if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
        }
1791
        HeapFree( GetProcessHeap(), 0, pWndArray );
Alexandre Julliard's avatar
Alexandre Julliard committed
1792 1793
    }
    else
1794
      WARN("\tdestroyed itself while in WM_DESTROY!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1795 1796 1797
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1798
/***********************************************************************
1799
 *		DestroyWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1800
 */
1801
BOOL WINAPI DestroyWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1802
{
1803
    BOOL is_child;
Alexandre Julliard's avatar
Alexandre Julliard committed
1804

1805
    if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1806 1807 1808 1809
    {
        SetLastError( ERROR_ACCESS_DENIED );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1810

1811
    TRACE("(%p)\n", hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1812

Alexandre Julliard's avatar
Alexandre Julliard committed
1813 1814
      /* Call hooks */

1815
    if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1816

1817 1818 1819
    if (MENU_IsMenuActive() == hwnd)
        EndMenu();

1820 1821 1822 1823 1824 1825 1826 1827
    is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;

    if (is_child)
    {
        if (!USER_IsExitingThread( GetCurrentThreadId() ))
            send_parent_notify( hwnd, WM_DESTROY );
    }
    else if (!GetWindow( hwnd, GW_OWNER ))
Alexandre Julliard's avatar
Alexandre Julliard committed
1828
    {
1829
        HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1830 1831 1832
        /* FIXME: clean up palette - see "Internals" p.352 */
    }

1833
    if (!IsWindow(hwnd)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1834

Alexandre Julliard's avatar
Alexandre Julliard committed
1835
      /* Hide the window */
1836 1837 1838 1839 1840 1841 1842 1843 1844
    if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
    {
        /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
        if (is_child)
            ShowWindow( hwnd, SW_HIDE );
        else
            SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
                          SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
    }
1845

1846
    if (!IsWindow(hwnd)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1847

Alexandre Julliard's avatar
Alexandre Julliard committed
1848 1849
      /* Recursively destroy owned windows */

1850
    if (!is_child)
Alexandre Julliard's avatar
Alexandre Julliard committed
1851
    {
1852 1853
        for (;;)
        {
1854 1855
            int i;
            BOOL got_one = FALSE;
1856 1857 1858 1859 1860 1861 1862 1863 1864
            HWND *list = WIN_ListChildren( GetDesktopWindow() );
            if (list)
            {
                for (i = 0; list[i]; i++)
                {
                    if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
                    if (WIN_IsCurrentThread( list[i] ))
                    {
                        DestroyWindow( list[i] );
1865
                        got_one = TRUE;
1866 1867 1868 1869 1870 1871 1872 1873
                        continue;
                    }
                    WIN_SetOwner( list[i], 0 );
                }
                HeapFree( GetProcessHeap(), 0, list );
            }
            if (!got_one) break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1874 1875
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1876
      /* Send destroy messages */
Alexandre Julliard's avatar
Alexandre Julliard committed
1877

1878
    WIN_SendDestroyMsg( hwnd );
1879
    if (!IsWindow( hwnd )) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1880

1881
    CLIPBOARD_ReleaseOwner( hwnd );
1882

Alexandre Julliard's avatar
Alexandre Julliard committed
1883 1884
      /* Destroy the window storage */

1885
    WIN_DestroyWindow( hwnd );
1886
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1887 1888 1889
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1890
/***********************************************************************
1891
 *		CloseWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1892
 */
1893
BOOL WINAPI CloseWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1894
{
1895
    if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1896
    ShowWindow( hwnd, SW_MINIMIZE );
1897
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1898 1899
}

1900

Alexandre Julliard's avatar
Alexandre Julliard committed
1901
/***********************************************************************
1902
 *		OpenIcon (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1903
 */
1904
BOOL WINAPI OpenIcon( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1905
{
1906 1907
    if (!IsIconic( hwnd )) return FALSE;
    ShowWindow( hwnd, SW_SHOWNORMAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1908
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1909 1910
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1911

Alexandre Julliard's avatar
Alexandre Julliard committed
1912
/***********************************************************************
1913
 *		FindWindowExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1914
 */
1915
HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1916
{
1917
    HWND *list;
1918
    HWND retvalue = 0;
1919 1920
    int i = 0, len = 0;
    WCHAR *buffer = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1921

1922 1923 1924
    if (!parent && child) parent = GetDesktopWindow();
    else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();

1925
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1926
    {
1927 1928
        len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1929
    }
1930

1931
    if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1932 1933

    if (child)
1934
    {
1935
        child = WIN_GetFullHandle( child );
1936
        while (list[i] && list[i] != child) i++;
1937
        if (!list[i]) goto done;
1938
        i++;  /* start from next window */
Alexandre Julliard's avatar
Alexandre Julliard committed
1939 1940
    }

1941
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1942
    {
1943 1944
        while (list[i])
        {
1945
            if (InternalGetWindowText( list[i], buffer, len + 1 ))
1946 1947 1948 1949 1950 1951 1952
            {
                if (!strcmpiW( buffer, title )) break;
            }
            else
            {
                if (!title[0]) break;
            }
1953 1954
            i++;
        }
1955
    }
1956 1957
    retvalue = list[i];

1958
 done:
1959 1960
    HeapFree( GetProcessHeap(), 0, list );
    HeapFree( GetProcessHeap(), 0, buffer );
1961
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1962
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1963 1964 1965 1966



/***********************************************************************
1967
 *		FindWindowA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1968
 */
1969
HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1970
{
1971
    HWND ret = FindWindowExA( 0, 0, className, title );
Alexandre Julliard's avatar
Alexandre Julliard committed
1972 1973
    if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1974 1975 1976 1977
}


/***********************************************************************
1978
 *		FindWindowExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1979
 */
1980
HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1981
{
1982 1983
    LPWSTR titleW = NULL;
    HWND hwnd = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1984

1985
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1986
    {
1987 1988 1989
        DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
        if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
        MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
Alexandre Julliard's avatar
Alexandre Julliard committed
1990
    }
1991

1992
    if (!IS_INTRESOURCE(className))
Alexandre Julliard's avatar
Alexandre Julliard committed
1993
    {
1994 1995 1996 1997 1998 1999 2000
        WCHAR classW[256];
        if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
            hwnd = FindWindowExW( parent, child, classW, titleW );
    }
    else
    {
        hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
Alexandre Julliard's avatar
Alexandre Julliard committed
2001
    }
2002 2003 2004

    HeapFree( GetProcessHeap(), 0, titleW );
    return hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
2005 2006 2007 2008
}


/***********************************************************************
2009
 *		FindWindowW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2010
 */
2011
HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
2012
{
2013
    return FindWindowExW( 0, 0, className, title );
Alexandre Julliard's avatar
Alexandre Julliard committed
2014 2015 2016
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2017
/**********************************************************************
2018
 *		GetDesktopWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2019
 */
2020
HWND WINAPI GetDesktopWindow(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2021
{
2022 2023
    struct user_thread_info *thread_info = get_user_thread_info();

2024
    if (thread_info->top_window) return thread_info->top_window;
2025 2026 2027 2028

    SERVER_START_REQ( get_desktop_window )
    {
        req->force = 0;
2029 2030
        if (!wine_server_call( req ))
        {
2031 2032
            thread_info->top_window = wine_server_ptr_handle( reply->top_window );
            thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2033
        }
2034 2035 2036
    }
    SERVER_END_REQ;

2037
    if (!thread_info->top_window)
2038
    {
2039 2040 2041 2042 2043 2044 2045
        static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
        static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
        STARTUPINFOW si;
        PROCESS_INFORMATION pi;
        WCHAR windir[MAX_PATH];
        WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
        WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2046
        WCHAR desktop[MAX_PATH];
2047 2048
        void *redir;

2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064
        SERVER_START_REQ( set_user_object_info )
        {
            req->handle = wine_server_obj_handle( GetThreadDesktop(GetCurrentThreadId()) );
            req->flags  = SET_USER_OBJECT_GET_FULL_NAME;
            wine_server_set_reply( req, desktop, sizeof(desktop) - sizeof(WCHAR) );
            if (!wine_server_call( req ))
            {
                size_t size = wine_server_reply_size( reply );
                desktop[size / sizeof(WCHAR)] = 0;
                TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop) );
            }
            else
                desktop[0] = 0;
        }
        SERVER_END_REQ;

2065 2066
        memset( &si, 0, sizeof(si) );
        si.cb = sizeof(si);
2067
        si.lpDesktop = *desktop ? desktop : NULL;
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081
        si.dwFlags = STARTF_USESTDHANDLES;
        si.hStdInput  = 0;
        si.hStdOutput = 0;
        si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );

        GetSystemDirectoryW( windir, MAX_PATH );
        strcpyW( app, windir );
        strcatW( app, explorer );
        strcpyW( cmdline, app );
        strcatW( cmdline, args );

        Wow64DisableWow64FsRedirection( &redir );
        if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
                            NULL, windir, &si, &pi ))
2082
        {
2083 2084 2085 2086
            TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
            WaitForInputIdle( pi.hProcess, 10000 );
            CloseHandle( pi.hThread );
            CloseHandle( pi.hProcess );
2087
        }
2088 2089
        else WARN( "failed to start explorer, err %d\n", GetLastError() );
        Wow64RevertWow64FsRedirection( redir );
2090

2091 2092
        SERVER_START_REQ( get_desktop_window )
        {
2093
            req->force = 1;
2094 2095
            if (!wine_server_call( req ))
            {
2096 2097
                thread_info->top_window = wine_server_ptr_handle( reply->top_window );
                thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2098
            }
2099 2100 2101
        }
        SERVER_END_REQ;
    }
2102

2103
    if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2104 2105
        ERR( "failed to create desktop window\n" );

2106
    return thread_info->top_window;
Alexandre Julliard's avatar
Alexandre Julliard committed
2107 2108 2109
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2110
/*******************************************************************
2111
 *		EnableWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2112
 */
2113
BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
Alexandre Julliard's avatar
Alexandre Julliard committed
2114
{
2115
    BOOL retvalue;
2116
    HWND full_handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
2117

2118 2119 2120 2121 2122 2123
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }

2124 2125
    if (!(full_handle = WIN_IsCurrentThread( hwnd )))
        return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2126

2127
    hwnd = full_handle;
2128

2129
    TRACE("( %p, %d )\n", hwnd, enable);
2130

2131
    retvalue = !IsWindowEnabled( hwnd );
2132

2133
    if (enable && retvalue)
2134
    {
2135
        WIN_SetStyle( hwnd, 0, WS_DISABLED );
2136
        SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2137
    }
2138
    else if (!enable && !retvalue)
Alexandre Julliard's avatar
Alexandre Julliard committed
2139
    {
2140
        HWND capture_wnd;
2141

2142
        SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2143

2144
        WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2145

2146
        if (hwnd == GetFocus())
2147
            SetFocus( 0 );  /* A disabled window can't have the focus */
2148

2149 2150
        capture_wnd = GetCapture();
        if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2151 2152
            ReleaseCapture();  /* A disabled window can't capture the mouse */

2153
        SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2154
    }
2155
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2156 2157 2158
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2159
/***********************************************************************
2160
 *		IsWindowEnabled (USER32.@)
2161
 */
2162
BOOL WINAPI IsWindowEnabled(HWND hWnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
2163
{
2164
    return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
Alexandre Julliard's avatar
Alexandre Julliard committed
2165 2166
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2167

Alexandre Julliard's avatar
Alexandre Julliard committed
2168
/***********************************************************************
2169
 *		IsWindowUnicode (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2170
 */
2171
BOOL WINAPI IsWindowUnicode( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2172
{
2173
    WND * wndPtr;
2174 2175 2176
    BOOL retvalue = FALSE;

    if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2177

2178
    if (wndPtr == WND_DESKTOP) return TRUE;
2179 2180 2181

    if (wndPtr != WND_OTHER_PROCESS)
    {
2182
        retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2183 2184 2185 2186 2187 2188
        WIN_ReleasePtr( wndPtr );
    }
    else
    {
        SERVER_START_REQ( get_window_info )
        {
2189
            req->handle = wine_server_user_handle( hwnd );
2190 2191 2192 2193
            if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
        }
        SERVER_END_REQ;
    }
2194
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2195 2196 2197
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2198
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
2199 2200 2201
 *	     WIN_GetWindowLong
 *
 * Helper function for GetWindowLong().
Alexandre Julliard's avatar
Alexandre Julliard committed
2202
 */
2203
static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
2204
{
2205
    LONG_PTR retvalue = 0;
2206 2207
    WND *wndPtr;

2208
    if (offset == GWLP_HWNDPARENT)
2209 2210 2211
    {
        HWND parent = GetAncestor( hwnd, GA_PARENT );
        if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2212
        return (ULONG_PTR)parent;
2213
    }
2214 2215 2216 2217 2218 2219 2220

    if (!(wndPtr = WIN_GetPtr( hwnd )))
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }

2221
    if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2222
    {
2223
        if (offset == GWLP_WNDPROC)
2224 2225 2226 2227 2228 2229
        {
            SetLastError( ERROR_ACCESS_DENIED );
            return 0;
        }
        SERVER_START_REQ( set_window_info )
        {
2230
            req->handle = wine_server_user_handle( hwnd );
2231
            req->flags  = 0;  /* don't set anything, just retrieve */
2232
            req->extra_offset = (offset >= 0) ? offset : -1;
2233
            req->extra_size = (offset >= 0) ? size : 0;
2234
            if (!wine_server_call_err( req ))
2235 2236 2237
            {
                switch(offset)
                {
2238 2239 2240
                case GWL_STYLE:      retvalue = reply->old_style; break;
                case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
                case GWLP_ID:        retvalue = reply->old_id; break;
2241
                case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2242
                case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2243
                default:
2244
                    if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2245
                    else SetLastError( ERROR_INVALID_INDEX );
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255
                    break;
                }
            }
        }
        SERVER_END_REQ;
        return retvalue;
    }

    /* now we have a valid wndPtr */

Alexandre Julliard's avatar
Alexandre Julliard committed
2256 2257
    if (offset >= 0)
    {
2258
        if (offset > (int)(wndPtr->cbWndExtra - size))
Alexandre Julliard's avatar
Alexandre Julliard committed
2259
        {
2260
            WARN("Invalid offset %d\n", offset );
2261 2262 2263
            WIN_ReleasePtr( wndPtr );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2264
        }
2265 2266
        retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );

Alexandre Julliard's avatar
Alexandre Julliard committed
2267
        /* Special case for dialog window procedure */
2268
        if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2269
            retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2270 2271
        WIN_ReleasePtr( wndPtr );
        return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2272
    }
2273

Alexandre Julliard's avatar
Alexandre Julliard committed
2274 2275
    switch(offset)
    {
2276
    case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2277 2278
    case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
    case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2279
    case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2280
    case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2281 2282 2283 2284 2285
    case GWLP_WNDPROC:
        /* This looks like a hack only for the edit control (see tests). This makes these controls
         * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
         * that the hack is in GetWindowLongPtr[AW], not in winprocs.
         */
2286
        if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2287 2288 2289 2290
            retvalue = (ULONG_PTR)wndPtr->winproc;
        else
            retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
        break;
2291 2292 2293 2294
    default:
        WARN("Unknown offset %d\n", offset );
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2295
    }
2296
    WIN_ReleasePtr(wndPtr);
2297
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2298 2299 2300
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2301
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
2302 2303 2304
 *	     WIN_SetWindowLong
 *
 * Helper function for SetWindowLong().
Alexandre Julliard's avatar
Alexandre Julliard committed
2305 2306 2307
 *
 * 0 is the failure code. However, in the case of failure SetLastError
 * must be set to distinguish between a 0 return value and a failure.
Alexandre Julliard's avatar
Alexandre Julliard committed
2308
 */
2309
LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
2310
{
2311
    STYLESTRUCT style;
2312
    BOOL ok, made_visible = FALSE;
2313
    LONG_PTR retval = 0;
2314
    WND *wndPtr;
2315

2316
    TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
Alexandre Julliard's avatar
Alexandre Julliard committed
2317

2318 2319 2320 2321 2322
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335

    if (!(wndPtr = WIN_GetPtr( hwnd )))
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }
    if (wndPtr == WND_DESKTOP)
    {
        /* can't change anything on the desktop window */
        SetLastError( ERROR_ACCESS_DENIED );
        return 0;
    }
    if (wndPtr == WND_OTHER_PROCESS)
Alexandre Julliard's avatar
Alexandre Julliard committed
2336
    {
2337
        if (offset == GWLP_WNDPROC)
2338 2339 2340 2341
        {
            SetLastError( ERROR_ACCESS_DENIED );
            return 0;
        }
2342 2343 2344 2345 2346 2347
        if (offset > 32767 || offset < -32767)
        {
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
        }
        return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
Alexandre Julliard's avatar
Alexandre Julliard committed
2348 2349
    }

2350 2351
    /* first some special cases */
    switch( offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2352
    {
2353
    case GWL_STYLE:
2354
        style.styleOld = wndPtr->dwStyle;
2355 2356
        style.styleNew = newval;
        WIN_ReleasePtr( wndPtr );
2357
        SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2358 2359
        if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
        newval = style.styleNew;
2360 2361
        /* WS_CLIPSIBLINGS can't be reset on top-level windows */
        if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2362 2363
        /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
           WS_EX_WINDOWEDGE too */
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
        break;
    case GWL_EXSTYLE:
        style.styleOld = wndPtr->dwExStyle;
        style.styleNew = newval;
        WIN_ReleasePtr( wndPtr );
        SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
        if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
        /* WS_EX_TOPMOST can only be changed through SetWindowPos */
        newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
        /* WS_EX_WINDOWEDGE depends on some other styles */
2374 2375 2376
        if (newval & WS_EX_DLGMODALFRAME)
            newval |= WS_EX_WINDOWEDGE;
        else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2377
            newval |= WS_EX_WINDOWEDGE;
2378
        else
2379
            newval &= ~WS_EX_WINDOWEDGE;
2380
        break;
2381
    case GWLP_HWNDPARENT:
2382 2383 2384
        if (wndPtr->parent == GetDesktopWindow())
        {
            WIN_ReleasePtr( wndPtr );
2385
            return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2386 2387 2388 2389
        }
        else
        {
            WIN_ReleasePtr( wndPtr );
2390
            return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2391
        }
2392
    case GWLP_WNDPROC:
2393
    {
2394
        WNDPROC proc;
2395
        UINT old_flags = wndPtr->flags;
2396
        retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2397
        proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2398 2399
        if (proc) wndPtr->winproc = proc;
        if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2400 2401
        else wndPtr->flags &= ~WIN_ISUNICODE;
        if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2402 2403 2404 2405 2406 2407 2408
        {
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* update is_unicode flag on the server side */
        break;
    }
2409 2410 2411
    case GWLP_ID:
    case GWLP_HINSTANCE:
    case GWLP_USERDATA:
2412
        break;
2413
    case DWLP_DLGPROC:
2414
        if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2415
            (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2416
        {
2417
            WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2418
            retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2419
            *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2420 2421 2422 2423 2424
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* fall through */
    default:
2425
        if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
Alexandre Julliard's avatar
Alexandre Julliard committed
2426
        {
2427
            WARN("Invalid offset %d\n", offset );
2428 2429 2430
            WIN_ReleasePtr( wndPtr );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2431
        }
2432
        else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
Alexandre Julliard's avatar
Alexandre Julliard committed
2433
        {
2434 2435 2436
            /* already set to the same value */
            WIN_ReleasePtr( wndPtr );
            return newval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2437
        }
2438
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2439
    }
2440

2441 2442
    SERVER_START_REQ( set_window_info )
    {
2443
        req->handle = wine_server_user_handle( hwnd );
2444 2445
        req->extra_offset = -1;
        switch(offset)
2446 2447
        {
        case GWL_STYLE:
2448 2449 2450
            req->flags = SET_WIN_STYLE;
            req->style = newval;
            break;
2451
        case GWL_EXSTYLE:
2452 2453
            req->flags = SET_WIN_EXSTYLE;
            req->ex_style = newval;
2454
            break;
2455
        case GWLP_ID:
2456 2457 2458
            req->flags = SET_WIN_ID;
            req->id = newval;
            break;
2459
        case GWLP_HINSTANCE:
2460
            req->flags = SET_WIN_INSTANCE;
2461
            req->instance = wine_server_client_ptr( (void *)newval );
2462
            break;
2463 2464
        case GWLP_WNDPROC:
            req->flags = SET_WIN_UNICODE;
2465
            req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2466
            break;
2467
        case GWLP_USERDATA:
2468
            req->flags = SET_WIN_USERDATA;
2469
            req->user_data = newval;
2470 2471
            break;
        default:
2472
            req->flags = SET_WIN_EXTRA;
2473
            req->extra_offset = offset;
2474 2475
            req->extra_size = size;
            set_win_data( &req->extra_value, newval, size );
2476
        }
2477
        if ((ok = !wine_server_call_err( req )))
2478 2479 2480 2481
        {
            switch(offset)
            {
            case GWL_STYLE:
2482 2483
                wndPtr->dwStyle = newval;
                retval = reply->old_style;
2484 2485
                break;
            case GWL_EXSTYLE:
2486 2487
                wndPtr->dwExStyle = newval;
                retval = reply->old_ex_style;
2488
                break;
2489
            case GWLP_ID:
2490 2491
                wndPtr->wIDmenu = newval;
                retval = reply->old_id;
2492
                break;
2493
            case GWLP_HINSTANCE:
2494
                wndPtr->hInstance = (HINSTANCE)newval;
2495
                retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2496
                break;
2497 2498
            case GWLP_WNDPROC:
                break;
2499
            case GWLP_USERDATA:
2500
                wndPtr->userdata = newval;
2501
                retval = reply->old_user_data;
2502
                break;
2503
            default:
2504 2505
                retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
                set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2506
                break;
2507 2508
            }
        }
2509 2510
    }
    SERVER_END_REQ;
2511

2512 2513
    if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
        (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2514
    {
2515
        made_visible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
2516 2517
        invalidate_dce( wndPtr, NULL );
    }
2518
    WIN_ReleasePtr( wndPtr );
2519

2520
    if (!ok) return 0;
2521

2522
    if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2523
    {
2524 2525
        style.styleOld = retval;
        style.styleNew = newval;
2526
        USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2527
        if (made_visible) update_window_state( hwnd );
2528
        SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2529
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2530

Alexandre Julliard's avatar
Alexandre Julliard committed
2531 2532 2533 2534
    return retval;
}


2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558
/**********************************************************************
 *		GetWindowWord (USER32.@)
 */
WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
{
    switch(offset)
    {
    case GWLP_ID:
    case GWLP_HINSTANCE:
    case GWLP_HWNDPARENT:
        break;
    default:
        if (offset < 0)
        {
            WARN("Invalid offset %d\n", offset );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
        }
        break;
    }
    return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2559
/**********************************************************************
2560
 *		GetWindowLongA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2561
 */
2562
LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2563
{
2564
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2565 2566 2567 2568
}


/**********************************************************************
2569
 *		GetWindowLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2570
 */
2571
LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2572
{
2573
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2574 2575 2576
}


2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600
/**********************************************************************
 *		SetWindowWord (USER32.@)
 */
WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
{
    switch(offset)
    {
    case GWLP_ID:
    case GWLP_HINSTANCE:
    case GWLP_HWNDPARENT:
        break;
    default:
        if (offset < 0)
        {
            WARN("Invalid offset %d\n", offset );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
        }
        break;
    }
    return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2601
/**********************************************************************
2602
 *		SetWindowLongA (USER32.@)
2603 2604
 *
 * See SetWindowLongW.
Alexandre Julliard's avatar
Alexandre Julliard committed
2605
 */
2606
LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
2607
{
2608
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2609 2610 2611
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2612
/**********************************************************************
2613
 *		SetWindowLongW (USER32.@) Set window attribute
Alexandre Julliard's avatar
Alexandre Julliard committed
2614 2615
 *
 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2616
 * value in a window's extra memory.
Alexandre Julliard's avatar
Alexandre Julliard committed
2617
 *
2618 2619 2620
 * The _hwnd_ parameter specifies the handle to a window that
 * has extra memory. The _newval_ parameter contains the new
 * attribute or extra memory value.  If positive, the _offset_
Alexandre Julliard's avatar
Alexandre Julliard committed
2621 2622 2623 2624 2625 2626
 * parameter is the byte-addressed location in the window's extra
 * memory to set.  If negative, _offset_ specifies the window
 * attribute to set, and should be one of the following values:
 *
 * GWL_EXSTYLE      The window's extended window style
 *
2627
 * GWL_STYLE        The window's window style.
Alexandre Julliard's avatar
Alexandre Julliard committed
2628
 *
2629
 * GWLP_WNDPROC     Pointer to the window's window procedure.
Alexandre Julliard's avatar
Alexandre Julliard committed
2630
 *
2631
 * GWLP_HINSTANCE   The window's application instance handle.
Alexandre Julliard's avatar
Alexandre Julliard committed
2632
 *
2633
 * GWLP_ID          The window's identifier.
Alexandre Julliard's avatar
Alexandre Julliard committed
2634
 *
2635
 * GWLP_USERDATA    The window's user-specified data.
Alexandre Julliard's avatar
Alexandre Julliard committed
2636
 *
2637
 * If the window is a dialog box, the _offset_ parameter can be one of
Alexandre Julliard's avatar
Alexandre Julliard committed
2638 2639
 * the following values:
 *
2640
 * DWLP_DLGPROC     The address of the window's dialog box procedure.
Alexandre Julliard's avatar
Alexandre Julliard committed
2641
 *
2642
 * DWLP_MSGRESULT   The return value of a message
Alexandre Julliard's avatar
Alexandre Julliard committed
2643 2644
 *                  that the dialog box procedure processed.
 *
2645
 * DWLP_USER        Application specific information.
Alexandre Julliard's avatar
Alexandre Julliard committed
2646 2647 2648 2649 2650 2651 2652 2653
 *
 * RETURNS
 *
 * If successful, returns the previous value located at _offset_. Otherwise,
 * returns 0.
 *
 * NOTES
 *
2654
 * Extra memory for a window class is specified by a nonzero cbWndExtra
Alexandre Julliard's avatar
Alexandre Julliard committed
2655 2656
 * parameter of the WNDCLASS structure passed to RegisterClass() at the
 * time of class creation.
2657
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2658 2659 2660 2661 2662 2663 2664
 * Using GWL_WNDPROC to set a new window procedure effectively creates
 * a window subclass. Use CallWindowProc() in the new windows procedure
 * to pass messages to the superclass's window procedure.
 *
 * The user data is reserved for use by the application which created
 * the window.
 *
2665
 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
Alexandre Julliard's avatar
Alexandre Julliard committed
2666 2667 2668 2669 2670 2671
 * instead, call the EnableWindow() function to change the window's
 * disabled state.
 *
 * Do not use GWL_HWNDPARENT to reset the window's parent, use
 * SetParent() instead.
 *
2672 2673 2674 2675 2676
 * Win95:
 * When offset is GWL_STYLE and the calling app's ver is 4.0,
 * it sends WM_STYLECHANGING before changing the settings
 * and WM_STYLECHANGED afterwards.
 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
Alexandre Julliard's avatar
Alexandre Julliard committed
2677
 */
2678
LONG WINAPI SetWindowLongW(
2679 2680 2681
    HWND hwnd,  /* [in] window to alter */
    INT offset, /* [in] offset, in bytes, of location to alter */
    LONG newval /* [in] new value of location */
Alexandre Julliard's avatar
Alexandre Julliard committed
2682
) {
2683
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2684 2685 2686 2687
}


/*******************************************************************
2688
 *		GetWindowTextA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2689
 */
2690
INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2691
{
2692 2693
    WCHAR *buffer;

2694
    if (!lpString || nMaxCount <= 0) return 0;
2695

2696
    if (WIN_IsCurrentProcess( hwnd ))
2697
    {
2698
        lpString[0] = 0;
2699
        return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2700
    }
2701 2702 2703 2704 2705 2706 2707 2708

    /* when window belongs to other process, don't send a message */
    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
    get_server_window_text( hwnd, buffer, nMaxCount );
    if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
        lpString[nMaxCount-1] = 0;
    HeapFree( GetProcessHeap(), 0, buffer );
    return strlen(lpString);
Alexandre Julliard's avatar
Alexandre Julliard committed
2709
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2710

2711

Alexandre Julliard's avatar
Alexandre Julliard committed
2712
/*******************************************************************
2713
 *		InternalGetWindowText (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2714
 */
2715
INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2716
{
2717 2718 2719 2720
    WND *win;

    if (nMaxCount <= 0) return 0;
    if (!(win = WIN_GetPtr( hwnd ))) return 0;
2721 2722
    if (win == WND_DESKTOP) lpString[0] = 0;
    else if (win != WND_OTHER_PROCESS)
2723 2724 2725 2726 2727 2728 2729 2730 2731
    {
        if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
        else lpString[0] = 0;
        WIN_ReleasePtr( win );
    }
    else
    {
        get_server_window_text( hwnd, lpString, nMaxCount );
    }
2732
    return strlenW(lpString);
Alexandre Julliard's avatar
Alexandre Julliard committed
2733 2734
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2735 2736

/*******************************************************************
2737
 *		GetWindowTextW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2738
 */
2739
INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2740
{
2741
    if (!lpString || nMaxCount <= 0) return 0;
2742

2743
    if (WIN_IsCurrentProcess( hwnd ))
2744
    {
2745
        lpString[0] = 0;
2746
        return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2747
    }
2748 2749 2750 2751

    /* when window belongs to other process, don't send a message */
    get_server_window_text( hwnd, lpString, nMaxCount );
    return strlenW(lpString);
Alexandre Julliard's avatar
Alexandre Julliard committed
2752 2753 2754
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2755
/*******************************************************************
2756
 *		SetWindowTextA (USER32.@)
2757
 *		SetWindowText  (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2758
 */
2759
BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextA( HWND hwnd, LPCSTR lpString )
Alexandre Julliard's avatar
Alexandre Julliard committed
2760
{
2761 2762 2763 2764 2765
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2766
    if (!WIN_IsCurrentProcess( hwnd ))
2767
        WARN( "setting text %s of other process window %p should not use SendMessage\n",
2768
               debugstr_a(lpString), hwnd );
2769
    return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
Alexandre Julliard's avatar
Alexandre Julliard committed
2770 2771
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2772

Alexandre Julliard's avatar
Alexandre Julliard committed
2773
/*******************************************************************
2774
 *		SetWindowTextW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2775
 */
2776
BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextW( HWND hwnd, LPCWSTR lpString )
Alexandre Julliard's avatar
Alexandre Julliard committed
2777
{
2778 2779 2780 2781 2782
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2783
    if (!WIN_IsCurrentProcess( hwnd ))
2784
        WARN( "setting text %s of other process window %p should not use SendMessage\n",
2785
               debugstr_w(lpString), hwnd );
2786
    return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
Alexandre Julliard's avatar
Alexandre Julliard committed
2787 2788 2789
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2790
/*******************************************************************
2791
 *		GetWindowTextLengthA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2792
 */
2793
INT WINAPI GetWindowTextLengthA( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2794
{
2795
    return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2796 2797 2798
}

/*******************************************************************
2799
 *		GetWindowTextLengthW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2800
 */
2801
INT WINAPI GetWindowTextLengthW( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2802
{
2803
    return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2804 2805
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2806

Alexandre Julliard's avatar
Alexandre Julliard committed
2807
/*******************************************************************
2808
 *		IsWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2809
 */
2810
BOOL WINAPI IsWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2811
{
2812
    WND *ptr;
2813
    BOOL ret;
2814

2815
    if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2816
    if (ptr == WND_DESKTOP) return TRUE;
2817 2818

    if (ptr != WND_OTHER_PROCESS)
2819
    {
2820
        WIN_ReleasePtr( ptr );
2821
        return TRUE;
2822 2823
    }

2824 2825
    /* check other processes */
    SERVER_START_REQ( get_window_info )
2826
    {
2827
        req->handle = wine_server_user_handle( hwnd );
2828
        ret = !wine_server_call_err( req );
2829
    }
2830
    SERVER_END_REQ;
2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842
    return ret;
}


/***********************************************************************
 *		GetWindowThreadProcessId (USER32.@)
 */
DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
{
    WND *ptr;
    DWORD tid = 0;

2843
    if (!(ptr = WIN_GetPtr( hwnd )))
2844
    {
2845 2846 2847 2848
        SetLastError( ERROR_INVALID_WINDOW_HANDLE);
        return 0;
    }

2849
    if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2850 2851 2852 2853 2854
    {
        /* got a valid window */
        tid = ptr->tid;
        if (process) *process = GetCurrentProcessId();
        WIN_ReleasePtr( ptr );
2855 2856 2857 2858 2859 2860
        return tid;
    }

    /* check other processes */
    SERVER_START_REQ( get_window_info )
    {
2861
        req->handle = wine_server_user_handle( hwnd );
2862
        if (!wine_server_call_err( req ))
2863
        {
2864 2865
            tid = (DWORD)reply->tid;
            if (process) *process = (DWORD)reply->pid;
2866 2867 2868 2869
        }
    }
    SERVER_END_REQ;
    return tid;
Alexandre Julliard's avatar
Alexandre Julliard committed
2870 2871 2872
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2873
/*****************************************************************
2874
 *		GetParent (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2875
 */
2876
HWND WINAPI GetParent( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2877
{
2878
    WND *wndPtr;
2879 2880
    HWND retvalue = 0;

2881 2882 2883 2884 2885
    if (!(wndPtr = WIN_GetPtr( hwnd )))
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }
2886
    if (wndPtr == WND_DESKTOP) return 0;
2887 2888 2889 2890 2891 2892 2893
    if (wndPtr == WND_OTHER_PROCESS)
    {
        LONG style = GetWindowLongW( hwnd, GWL_STYLE );
        if (style & (WS_POPUP | WS_CHILD))
        {
            SERVER_START_REQ( get_window_tree )
            {
2894
                req->handle = wine_server_user_handle( hwnd );
2895
                if (!wine_server_call_err( req ))
2896
                {
2897 2898
                    if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
                    else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2899 2900 2901 2902 2903 2904
                }
            }
            SERVER_END_REQ;
        }
    }
    else
2905
    {
2906 2907
        if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
        else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2908
        WIN_ReleasePtr( wndPtr );
2909
    }
2910
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2911 2912 2913 2914
}


/*****************************************************************
2915
 *		GetAncestor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2916
 */
2917
HWND WINAPI GetAncestor( HWND hwnd, UINT type )
Alexandre Julliard's avatar
Alexandre Julliard committed
2918
{
2919
    WND *win;
2920
    HWND *list, ret = 0;
2921

2922
    switch(type)
2923
    {
2924
    case GA_PARENT:
2925 2926 2927 2928 2929
        if (!(win = WIN_GetPtr( hwnd )))
        {
            SetLastError( ERROR_INVALID_WINDOW_HANDLE );
            return 0;
        }
2930
        if (win == WND_DESKTOP) return 0;
2931
        if (win != WND_OTHER_PROCESS)
2932
        {
2933 2934
            ret = win->parent;
            WIN_ReleasePtr( win );
2935
        }
2936
        else /* need to query the server */
2937
        {
2938
            SERVER_START_REQ( get_window_tree )
2939
            {
2940 2941
                req->handle = wine_server_user_handle( hwnd );
                if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2942
            }
2943
            SERVER_END_REQ;
2944
        }
2945
        break;
2946

2947
    case GA_ROOT:
2948
        if (!(list = list_window_parents( hwnd ))) return 0;
2949

2950 2951 2952 2953 2954 2955 2956 2957 2958
        if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
        else
        {
            int count = 2;
            while (list[count]) count++;
            ret = list[count - 2];  /* get the one before the desktop */
        }
        HeapFree( GetProcessHeap(), 0, list );
        break;
2959

2960
    case GA_ROOTOWNER:
2961 2962
        if (is_desktop_window( hwnd )) return 0;
        ret = WIN_GetFullHandle( hwnd );
2963 2964
        for (;;)
        {
2965 2966 2967
            HWND parent = GetParent( ret );
            if (!parent) break;
            ret = parent;
2968
        }
2969
        break;
2970 2971
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2972 2973
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2974

Alexandre Julliard's avatar
Alexandre Julliard committed
2975
/*****************************************************************
2976
 *		SetParent (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2977
 */
2978
HWND WINAPI SetParent( HWND hwnd, HWND parent )
Alexandre Julliard's avatar
Alexandre Julliard committed
2979
{
2980
    HWND full_handle;
2981 2982 2983
    HWND old_parent = 0;
    BOOL was_visible;
    WND *wndPtr;
2984
    POINT pt;
2985
    BOOL ret;
2986

2987 2988 2989 2990 2991 2992
    if (is_broadcast(hwnd) || is_broadcast(parent))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

2993
    if (!parent) parent = GetDesktopWindow();
2994
    else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2995 2996 2997 2998 2999 3000 3001 3002
    else parent = WIN_GetFullHandle( parent );

    if (!IsWindow( parent ))
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }

3003 3004 3005 3006 3007 3008 3009
    /* Some applications try to set a child as a parent */
    if (IsChild(hwnd, parent))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }

3010
    if (!(full_handle = WIN_IsCurrentThread( hwnd )))
3011
        return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
3012

3013 3014 3015 3016 3017 3018
    if (full_handle == parent)
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }

3019 3020 3021 3022 3023 3024 3025
    /* Windows hides the window first, then shows it again
     * including the WM_SHOWWINDOW messages and all */
    was_visible = ShowWindow( hwnd, SW_HIDE );

    wndPtr = WIN_GetPtr( hwnd );
    if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;

3026 3027 3028
    pt.x = wndPtr->rectWindow.left;
    pt.y = wndPtr->rectWindow.top;

3029 3030
    SERVER_START_REQ( set_parent )
    {
3031 3032
        req->handle = wine_server_user_handle( hwnd );
        req->parent = wine_server_user_handle( parent );
3033 3034
        if ((ret = !wine_server_call( req )))
        {
3035 3036
            old_parent = wine_server_ptr_handle( reply->old_parent );
            wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
        }

    }
    SERVER_END_REQ;
    WIN_ReleasePtr( wndPtr );
    if (!ret) return 0;

    USER_Driver->pSetParent( full_handle, parent, old_parent );

    /* SetParent additionally needs to make hwnd the topmost window
       in the x-order and send the expected WM_WINDOWPOSCHANGING and
       WM_WINDOWPOSCHANGED notification messages.
    */
3050 3051 3052
    SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );

    if (was_visible) ShowWindow( hwnd, SW_SHOW );
3053 3054

    return old_parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
3055 3056
}

3057

Alexandre Julliard's avatar
Alexandre Julliard committed
3058
/*******************************************************************
3059
 *		IsChild (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3060
 */
3061
BOOL WINAPI IsChild( HWND parent, HWND child )
Alexandre Julliard's avatar
Alexandre Julliard committed
3062
{
3063
    HWND *list;
3064
    int i;
3065
    BOOL ret = FALSE;
3066

3067 3068
    if (!(GetWindowLongW( child, GWL_STYLE ) & WS_CHILD)) return FALSE;
    if (!(list = list_window_parents( child ))) return FALSE;
3069
    parent = WIN_GetFullHandle( parent );
3070 3071 3072 3073 3074 3075 3076 3077 3078
    for (i = 0; list[i]; i++)
    {
        if (list[i] == parent)
        {
            ret = list[i] && list[i+1];
            break;
        }
        if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_CHILD)) break;
    }
3079 3080
    HeapFree( GetProcessHeap(), 0, list );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3081 3082 3083
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3084
/***********************************************************************
3085
 *		IsWindowVisible (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3086
 */
3087
BOOL WINAPI IsWindowVisible( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3088
{
3089
    HWND *list;
3090
    BOOL retval = TRUE;
3091 3092 3093
    int i;

    if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3094
    if (!(list = list_window_parents( hwnd ))) return TRUE;
3095
    if (list[0])
3096 3097 3098
    {
        for (i = 0; list[i+1]; i++)
            if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3099
        retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3100
    }
3101
    HeapFree( GetProcessHeap(), 0, list );
3102
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3103 3104
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3105

Alexandre Julliard's avatar
Alexandre Julliard committed
3106 3107
/***********************************************************************
 *           WIN_IsWindowDrawable
Alexandre Julliard's avatar
Alexandre Julliard committed
3108 3109 3110
 *
 * hwnd is drawable when it is visible, all parents are not
 * minimized, and it is itself not minimized unless we are
Alexandre Julliard's avatar
Alexandre Julliard committed
3111
 * trying to draw its default class icon.
Alexandre Julliard's avatar
Alexandre Julliard committed
3112
 */
3113
BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
Alexandre Julliard's avatar
Alexandre Julliard committed
3114
{
3115
    HWND *list;
3116
    BOOL retval = TRUE;
3117
    int i;
3118
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3119

3120
    if (!(style & WS_VISIBLE)) return FALSE;
3121
    if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
3122

3123
    if (!(list = list_window_parents( hwnd ))) return TRUE;
3124
    if (list[0])
3125 3126 3127 3128
    {
        for (i = 0; list[i+1]; i++)
            if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
                break;
3129
        retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3130
    }
3131 3132
    HeapFree( GetProcessHeap(), 0, list );
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3133 3134
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3135

Alexandre Julliard's avatar
Alexandre Julliard committed
3136
/*******************************************************************
3137
 *		GetTopWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3138
 */
3139
HWND WINAPI GetTopWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3140
{
3141 3142
    if (!hwnd) hwnd = GetDesktopWindow();
    return GetWindow( hwnd, GW_CHILD );
Alexandre Julliard's avatar
Alexandre Julliard committed
3143 3144 3145
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3146
/*******************************************************************
3147
 *		GetWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3148
 */
3149
HWND WINAPI GetWindow( HWND hwnd, UINT rel )
Alexandre Julliard's avatar
Alexandre Julliard committed
3150
{
3151
    HWND retval = 0;
3152

3153
    if (rel == GW_OWNER)  /* this one may be available locally */
Alexandre Julliard's avatar
Alexandre Julliard committed
3154
    {
3155 3156 3157 3158 3159 3160
        WND *wndPtr = WIN_GetPtr( hwnd );
        if (!wndPtr)
        {
            SetLastError( ERROR_INVALID_HANDLE );
            return 0;
        }
3161
        if (wndPtr == WND_DESKTOP) return 0;
3162 3163 3164 3165 3166 3167 3168
        if (wndPtr != WND_OTHER_PROCESS)
        {
            retval = wndPtr->owner;
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* else fall through to server call */
3169
    }
3170

3171 3172
    SERVER_START_REQ( get_window_tree )
    {
3173
        req->handle = wine_server_user_handle( hwnd );
3174
        if (!wine_server_call_err( req ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3175
        {
3176
            switch(rel)
3177
            {
3178
            case GW_HWNDFIRST:
3179
                retval = wine_server_ptr_handle( reply->first_sibling );
3180 3181
                break;
            case GW_HWNDLAST:
3182
                retval = wine_server_ptr_handle( reply->last_sibling );
3183 3184
                break;
            case GW_HWNDNEXT:
3185
                retval = wine_server_ptr_handle( reply->next_sibling );
3186 3187
                break;
            case GW_HWNDPREV:
3188
                retval = wine_server_ptr_handle( reply->prev_sibling );
3189
                break;
3190
            case GW_OWNER:
3191
                retval = wine_server_ptr_handle( reply->owner );
3192
                break;
3193
            case GW_CHILD:
3194
                retval = wine_server_ptr_handle( reply->first_child );
3195
                break;
3196
            }
3197
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3198
    }
3199
    SERVER_END_REQ;
3200
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3201 3202 3203
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3204
/*******************************************************************
3205
 *		ShowOwnedPopups (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3206
 */
3207
BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
Alexandre Julliard's avatar
Alexandre Julliard committed
3208
{
3209
    int count = 0;
3210
    WND *pWnd;
3211
    HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3212

3213
    if (!win_array) return TRUE;
3214

3215 3216
    while (win_array[count]) count++;
    while (--count >= 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
3217
    {
3218
        if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3219 3220
        if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
        if (pWnd == WND_OTHER_PROCESS) continue;
3221
        if (fShow)
3222
        {
3223
            if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3224
            {
3225 3226 3227 3228 3229 3230 3231
                WIN_ReleasePtr( pWnd );
                /* In Windows, ShowOwnedPopups(TRUE) generates
                 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
                 * regardless of the state of the owner
                 */
                SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
                continue;
3232
            }
3233 3234 3235 3236
        }
        else
        {
            if (pWnd->dwStyle & WS_VISIBLE)
3237
            {
3238 3239 3240 3241 3242 3243 3244
                WIN_ReleasePtr( pWnd );
                /* In Windows, ShowOwnedPopups(FALSE) generates
                 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
                 * regardless of the state of the owner
                 */
                SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
                continue;
3245 3246
            }
        }
3247
        WIN_ReleasePtr( pWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
3248
    }
3249
    HeapFree( GetProcessHeap(), 0, win_array );
Alexandre Julliard's avatar
Alexandre Julliard committed
3250
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3251
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3252 3253


Alexandre Julliard's avatar
Alexandre Julliard committed
3254
/*******************************************************************
3255
 *		GetLastActivePopup (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3256
 */
3257
HWND WINAPI GetLastActivePopup( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3258
{
3259 3260 3261 3262
    HWND retval = hwnd;

    SERVER_START_REQ( get_window_info )
    {
3263 3264
        req->handle = wine_server_user_handle( hwnd );
        if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3265 3266
    }
    SERVER_END_REQ;
3267
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3268 3269
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3270

3271 3272 3273 3274 3275 3276 3277
/*******************************************************************
 *           WIN_ListChildren
 *
 * Build an array of the children of a given window. The array must be
 * freed with HeapFree. Returns NULL when no windows are found.
 */
HWND *WIN_ListChildren( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3278
{
3279 3280 3281 3282 3283
    if (!hwnd)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return NULL;
    }
3284
    return list_window_children( 0, hwnd, NULL, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3285
}
3286

Alexandre Julliard's avatar
Alexandre Julliard committed
3287 3288

/*******************************************************************
3289
 *		EnumWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3290
 */
3291
BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3292
{
3293 3294
    HWND *list;
    BOOL ret = TRUE;
3295 3296 3297
    int i;

    USER_CheckNotLock();
Alexandre Julliard's avatar
Alexandre Julliard committed
3298

Alexandre Julliard's avatar
Alexandre Julliard committed
3299
    /* We have to build a list of all windows first, to avoid */
3300 3301
    /* unpleasant side-effects, for instance if the callback */
    /* function changes the Z-order of the windows.          */
Alexandre Julliard's avatar
Alexandre Julliard committed
3302

3303
    if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3304

Alexandre Julliard's avatar
Alexandre Julliard committed
3305
    /* Now call the callback function for every window */
Alexandre Julliard's avatar
Alexandre Julliard committed
3306

3307
    for (i = 0; list[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
3308 3309
    {
        /* Make sure that the window still exists */
3310 3311
        if (!IsWindow( list[i] )) continue;
        if (!(ret = lpEnumFunc( list[i], lParam ))) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
3312
    }
3313
    HeapFree( GetProcessHeap(), 0, list );
3314
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3315
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3316 3317


Alexandre Julliard's avatar
Alexandre Julliard committed
3318
/**********************************************************************
3319
 *		EnumThreadWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3320
 */
3321
BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3322
{
3323
    HWND *list;
3324
    int i;
3325
    BOOL ret = TRUE;
3326 3327

    USER_CheckNotLock();
3328

3329
    if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3330 3331 3332 3333

    /* Now call the callback function for every window */

    for (i = 0; list[i]; i++)
3334
        if (!(ret = func( list[i], lParam ))) break;
3335
    HeapFree( GetProcessHeap(), 0, list );
3336
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3337 3338 3339
}


3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
/***********************************************************************
 *              EnumDesktopWindows   (USER32.@)
 */
BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
{
    HWND *list;
    int i;

    USER_CheckNotLock();

    if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;

    for (i = 0; list[i]; i++)
        if (!func( list[i], lparam )) break;
    HeapFree( GetProcessHeap(), 0, list );
    return TRUE;
}


3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383
#ifdef __i386__
/* Some apps pass a non-stdcall proc to EnumChildWindows,
 * so we need a small assembly wrapper to call the proc.
 */
extern LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam );
__ASM_GLOBAL_FUNC( enum_callback_wrapper,
    "pushl %ebp\n\t"
    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
    "movl %esp,%ebp\n\t"
    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
    "pushl 16(%ebp)\n\t"
    "pushl 12(%ebp)\n\t"
    "call *8(%ebp)\n\t"
    "leave\n\t"
    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
    __ASM_CFI(".cfi_same_value %ebp\n\t")
    "ret" )
#else
static inline LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam )
{
    return proc( hwnd, lparam );
}
#endif /* __i386__ */

Alexandre Julliard's avatar
Alexandre Julliard committed
3384
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
3385
 *           WIN_EnumChildWindows
Alexandre Julliard's avatar
Alexandre Julliard committed
3386
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
3387
 * Helper function for EnumChildWindows().
Alexandre Julliard's avatar
Alexandre Julliard committed
3388
 */
3389
static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3390
{
3391 3392
    HWND *childList;
    BOOL ret = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3393

3394
    for ( ; *list; list++)
Alexandre Julliard's avatar
Alexandre Julliard committed
3395
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3396
        /* Make sure that the window still exists */
3397
        if (!IsWindow( *list )) continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3398
        /* Build children list first */
3399
        childList = WIN_ListChildren( *list );
3400

3401
        ret = enum_callback_wrapper( func, *list, lParam );
3402

Alexandre Julliard's avatar
Alexandre Julliard committed
3403 3404 3405
        if (childList)
        {
            if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3406
            HeapFree( GetProcessHeap(), 0, childList );
Alexandre Julliard's avatar
Alexandre Julliard committed
3407
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3408 3409 3410 3411 3412 3413 3414
        if (!ret) return FALSE;
    }
    return TRUE;
}


/**********************************************************************
3415
 *		EnumChildWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3416
 */
3417
BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3418
{
3419
    HWND *list;
3420
    BOOL ret;
3421 3422

    USER_CheckNotLock();
Alexandre Julliard's avatar
Alexandre Julliard committed
3423

3424
    if (!(list = WIN_ListChildren( parent ))) return FALSE;
3425
    ret = WIN_EnumChildWindows( list, func, lParam );
3426
    HeapFree( GetProcessHeap(), 0, list );
3427
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3428
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3429 3430


Alexandre Julliard's avatar
Alexandre Julliard committed
3431
/*******************************************************************
3432
 *		AnyPopup (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3433
 */
3434
BOOL WINAPI AnyPopup(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3435
{
3436
    int i;
3437
    BOOL retvalue;
3438
    HWND *list = WIN_ListChildren( GetDesktopWindow() );
3439 3440 3441

    if (!list) return FALSE;
    for (i = 0; list[i]; i++)
3442
    {
3443
        if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3444
    }
3445
    retvalue = (list[i] != 0);
3446
    HeapFree( GetProcessHeap(), 0, list );
3447
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3448 3449
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3450 3451

/*******************************************************************
3452
 *		FlashWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3453
 */
3454
BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
{
    FLASHWINFO finfo;

    finfo.cbSize = sizeof(FLASHWINFO);
    finfo.dwFlags = bInvert ? FLASHW_ALL : FLASHW_STOP;
    finfo.uCount = 1;
    finfo.dwTimeout = 0;
    finfo.hwnd = hWnd;
    return FlashWindowEx( &finfo );
}

/*******************************************************************
 *		FlashWindowEx (USER32.@)
 */
BOOL WINAPI FlashWindowEx( PFLASHWINFO pfinfo )
Alexandre Julliard's avatar
Alexandre Julliard committed
3470
{
3471
    WND *wndPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
3472

3473
    TRACE( "%p\n", pfinfo->hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
3474

3475
    if (!pfinfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
3476
    {
3477 3478 3479
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }
3480

3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492
    if (!pfinfo->hwnd || pfinfo->cbSize != sizeof(FLASHWINFO) || !IsWindow( pfinfo->hwnd ))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
    FIXME( "%p - semi-stub\n", pfinfo );

    if (IsIconic( pfinfo->hwnd ))
    {
        RedrawWindow( pfinfo->hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );

        wndPtr = WIN_GetPtr( pfinfo->hwnd );
3493
        if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3494
        if (pfinfo->dwFlags && !(wndPtr->flags & WIN_NCACTIVATED))
Alexandre Julliard's avatar
Alexandre Julliard committed
3495 3496 3497 3498 3499 3500 3501
        {
            wndPtr->flags |= WIN_NCACTIVATED;
        }
        else
        {
            wndPtr->flags &= ~WIN_NCACTIVATED;
        }
3502
        WIN_ReleasePtr( wndPtr );
3503
        USER_Driver->pFlashWindowEx( pfinfo );
Alexandre Julliard's avatar
Alexandre Julliard committed
3504 3505 3506 3507
        return TRUE;
    }
    else
    {
3508
        WPARAM wparam;
3509
        HWND hwnd = pfinfo->hwnd;
3510

3511
        wndPtr = WIN_GetPtr( hwnd );
3512
        if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3513
        hwnd = wndPtr->obj.handle;  /* make it a full handle */
3514

3515 3516
        if (pfinfo->dwFlags) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
        else wparam = (hwnd == GetForegroundWindow());
Alexandre Julliard's avatar
Alexandre Julliard committed
3517

3518
        WIN_ReleasePtr( wndPtr );
3519
        SendMessageW( hwnd, WM_NCACTIVATE, wparam, 0 );
3520
        USER_Driver->pFlashWindowEx( pfinfo );
Alexandre Julliard's avatar
Alexandre Julliard committed
3521 3522
        return wparam;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3523 3524
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3525
/*******************************************************************
3526
 *		GetWindowContextHelpId (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3527
 */
3528
DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3529
{
3530
    DWORD retval;
3531
    WND *wnd = WIN_GetPtr( hwnd );
3532
    if (!wnd || wnd == WND_DESKTOP) return 0;
3533 3534 3535 3536 3537
    if (wnd == WND_OTHER_PROCESS)
    {
        if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
        return 0;
    }
3538
    retval = wnd->helpContext;
3539
    WIN_ReleasePtr( wnd );
3540
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3541 3542 3543 3544
}


/*******************************************************************
3545
 *		SetWindowContextHelpId (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3546
 */
3547
BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
Alexandre Julliard's avatar
Alexandre Julliard committed
3548
{
3549
    WND *wnd = WIN_GetPtr( hwnd );
3550
    if (!wnd || wnd == WND_DESKTOP) return FALSE;
3551 3552 3553
    if (wnd == WND_OTHER_PROCESS)
    {
        if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3554
        return FALSE;
3555
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3556
    wnd->helpContext = id;
3557
    WIN_ReleasePtr( wnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
3558 3559 3560 3561
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3562
/*******************************************************************
3563
 *		DragDetect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3564
 */
3565
BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
3566
{
3567 3568
    MSG msg;
    RECT rect;
3569 3570
    WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
    WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
Alexandre Julliard's avatar
Alexandre Julliard committed
3571

Alexandre Julliard's avatar
Alexandre Julliard committed
3572 3573
    rect.left = pt.x - wDragWidth;
    rect.right = pt.x + wDragWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
3574

Alexandre Julliard's avatar
Alexandre Julliard committed
3575 3576
    rect.top = pt.y - wDragHeight;
    rect.bottom = pt.y + wDragHeight;
Alexandre Julliard's avatar
Alexandre Julliard committed
3577

3578
    SetCapture(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
3579

Alexandre Julliard's avatar
Alexandre Julliard committed
3580 3581
    while(1)
    {
3582
        while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3583 3584
        {
            if( msg.message == WM_LBUTTONUP )
3585 3586
            {
                ReleaseCapture();
3587
                return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3588 3589
            }
            if( msg.message == WM_MOUSEMOVE )
3590
            {
3591
                POINT tmp;
3592 3593
                tmp.x = (short)LOWORD(msg.lParam);
                tmp.y = (short)HIWORD(msg.lParam);
3594
                if( !PtInRect( &rect, tmp ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3595
                {
3596
                    ReleaseCapture();
3597
                    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3598
                }
3599
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
3600
        }
3601
        WaitMessage();
Alexandre Julliard's avatar
Alexandre Julliard committed
3602
    }
3603
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3604 3605
}

3606 3607 3608
/******************************************************************************
 *		GetWindowModuleFileNameA (USER32.@)
 */
3609
UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3610
{
3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625
    WND *win;
    HINSTANCE hinst;

    TRACE( "%p, %p, %u\n", hwnd, module, size );

    win = WIN_GetPtr( hwnd );
    if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }
    hinst = win->hInstance;
    WIN_ReleasePtr( win );

    return GetModuleFileNameA( hinst, module, size );
3626 3627 3628 3629 3630
}

/******************************************************************************
 *		GetWindowModuleFileNameW (USER32.@)
 */
3631
UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3632
{
3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647
    WND *win;
    HINSTANCE hinst;

    TRACE( "%p, %p, %u\n", hwnd, module, size );

    win = WIN_GetPtr( hwnd );
    if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }
    hinst = win->hInstance;
    WIN_ReleasePtr( win );

    return GetModuleFileNameW( hinst, module, size );
3648
}
3649 3650 3651

/******************************************************************************
 *              GetWindowInfo (USER32.@)
3652 3653
 *
 * Note: tests show that Windows doesn't check cbSize of the structure.
3654
 */
3655
BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3656 3657
{
    if (!pwi) return FALSE;
3658
    if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3659

3660 3661
    pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3662
    pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3663 3664 3665 3666 3667 3668 3669

    pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
    pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;

    pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
    pwi->wCreatorVersion = 0x0400;

3670 3671
    return TRUE;
}
3672 3673 3674 3675 3676 3677 3678 3679

/******************************************************************************
 *              SwitchDesktop (USER32.@)
 *
 * NOTES: Sets the current input or interactive desktop.
 */
BOOL WINAPI SwitchDesktop( HDESK hDesktop)
{
3680
    FIXME("(hwnd %p) stub!\n", hDesktop);
3681 3682
    return TRUE;
}
3683

3684 3685 3686 3687 3688 3689

/***********************************************************************
 *           __wine_set_pixel_format
 */
BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
{
3690 3691 3692 3693 3694 3695 3696 3697 3698 3699
    WND *win = WIN_GetPtr( hwnd );

    if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
    {
        WARN( "setting format %d on win %p not supported\n", format, hwnd );
        return FALSE;
    }
    win->pixel_format = format;
    WIN_ReleasePtr( win );

3700 3701
    update_window_state( hwnd );
    return TRUE;
3702 3703 3704
}


3705 3706 3707
/*****************************************************************************
 *              SetLayeredWindowAttributes (USER32.@)
 */
3708
BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3709
{
3710 3711
    BOOL ret;

3712
    TRACE("(%p,%08x,%d,%x)\n", hwnd, key, alpha, flags);
3713 3714 3715

    SERVER_START_REQ( set_window_layered_info )
    {
3716
        req->handle = wine_server_user_handle( hwnd );
3717 3718 3719 3720 3721 3722 3723
        req->color_key = key;
        req->alpha = alpha;
        req->flags = flags;
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;

3724 3725
    if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );

3726
    return ret;
3727
}
3728

3729

3730 3731 3732
/*****************************************************************************
 *              GetLayeredWindowAttributes (USER32.@)
 */
3733
BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3734
{
3735 3736 3737 3738
    BOOL ret;

    SERVER_START_REQ( get_window_layered_info )
    {
3739
        req->handle = wine_server_user_handle( hwnd );
3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
        if ((ret = !wine_server_call_err( req )))
        {
            if (key) *key = reply->color_key;
            if (alpha) *alpha = reply->alpha;
            if (flags) *flags = reply->flags;
        }
    }
    SERVER_END_REQ;

    return ret;
3750 3751
}

3752 3753 3754 3755 3756 3757

/*****************************************************************************
 *              UpdateLayeredWindowIndirect  (USER32.@)
 */
BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
{
3758 3759 3760
    DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
    RECT window_rect, client_rect;
    SIZE offset;
3761

3762 3763 3764 3765
    if (!info ||
        info->cbSize != sizeof(*info) ||
        info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
        !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3766 3767 3768 3769 3770 3771
        GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }

3772
    WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3773

3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786
    if (info->pptDst)
    {
        offset.cx = info->pptDst->x - window_rect.left;
        offset.cy = info->pptDst->y - window_rect.top;
        OffsetRect( &client_rect, offset.cx, offset.cy );
        OffsetRect( &window_rect, offset.cx, offset.cy );
        flags &= ~SWP_NOMOVE;
    }
    if (info->psize)
    {
        offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
        offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
        if (info->psize->cx <= 0 || info->psize->cy <= 0)
3787
        {
3788 3789
            SetLastError( ERROR_INVALID_PARAMETER );
            return FALSE;
3790
        }
3791
        if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3792
        {
3793 3794
            SetLastError( ERROR_INCORRECT_SIZE );
            return FALSE;
3795
        }
3796 3797 3798 3799 3800
        client_rect.right  += offset.cx;
        client_rect.bottom += offset.cy;
        window_rect.right  += offset.cx;
        window_rect.bottom += offset.cy;
        flags &= ~SWP_NOSIZE;
3801 3802
    }

3803 3804
    TRACE( "window %p win %s client %s\n", hwnd,
           wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3805

3806
    if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3807

3808
    set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3809 3810 3811 3812
    return TRUE;
}


3813 3814 3815 3816 3817
/*****************************************************************************
 *              UpdateLayeredWindow (USER32.@)
 */
BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
                                 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3818
                                 DWORD flags)
3819
{
3820 3821
    UPDATELAYEREDWINDOWINFO info;

3822 3823 3824 3825 3826
    if (flags & ULW_EX_NORESIZE)  /* only valid for UpdateLayeredWindowIndirect */
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
3827 3828 3829 3830 3831 3832 3833 3834
    info.cbSize   = sizeof(info);
    info.hdcDst   = hdcDst;
    info.pptDst   = pptDst;
    info.psize    = psize;
    info.hdcSrc   = hdcSrc;
    info.pptSrc   = pptSrc;
    info.crKey    = crKey;
    info.pblend   = pblend;
3835
    info.dwFlags  = flags;
3836 3837
    info.prcDirty = NULL;
    return UpdateLayeredWindowIndirect( hwnd, &info );
3838
}
3839

3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852

/******************************************************************************
 *                    GetProcessDefaultLayout [USER32.@]
 *
 * Gets the default layout for parentless windows.
 */
BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
{
    if (!layout)
    {
        SetLastError( ERROR_NOACCESS );
        return FALSE;
    }
3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887
    if (process_layout == ~0u)
    {
        static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
                                              '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
        static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
                                           '\\','%','0','4','x','%','0','4','x',
                                           '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
        WCHAR *str, buffer[MAX_PATH];
        DWORD i, len, version_layout = 0;
        DWORD user_lang = GetUserDefaultLangID();
        DWORD *languages;
        void *data = NULL;

        GetModuleFileNameW( 0, buffer, MAX_PATH );
        if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
        if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
        if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
        if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;

        len /= sizeof(DWORD);
        for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
        if (i == len)  /* try neutral language */
            for (i = 0; i < len; i++)
                if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
        if (i == len) i = 0;  /* default to the first one */

        sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
        if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
        TRACE( "found description %s\n", debugstr_w( str ));
        if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;

    done:
        HeapFree( GetProcessHeap(), 0, data );
        process_layout = version_layout;
    }
3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
    *layout = process_layout;
    return TRUE;
}


/******************************************************************************
 *                    SetProcessDefaultLayout [USER32.@]
 *
 * Sets the default layout for parentless windows.
 */
BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
{
    process_layout = layout;
    return TRUE;
}


3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927
/* 64bit versions */

#ifdef GetWindowLongPtrW
#undef GetWindowLongPtrW
#endif

#ifdef GetWindowLongPtrA
#undef GetWindowLongPtrA
#endif

#ifdef SetWindowLongPtrW
#undef SetWindowLongPtrW
#endif

#ifdef SetWindowLongPtrA
#undef SetWindowLongPtrA
#endif

/*****************************************************************************
 *              GetWindowLongPtrW (USER32.@)
 */
LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
{
3928
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3929 3930 3931 3932 3933 3934 3935
}

/*****************************************************************************
 *              GetWindowLongPtrA (USER32.@)
 */
LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
{
3936
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3937 3938 3939 3940 3941 3942 3943
}

/*****************************************************************************
 *              SetWindowLongPtrW (USER32.@)
 */
LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
{
3944
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3945 3946 3947 3948 3949 3950 3951
}

/*****************************************************************************
 *              SetWindowLongPtrA (USER32.@)
 */
LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
{
3952
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3953
}
3954 3955 3956 3957 3958 3959 3960 3961 3962 3963

/*****************************************************************************
 *              RegisterTouchWindow (USER32.@)
 */
BOOL WINAPI RegisterTouchWindow(HWND hwnd, ULONG flags)
{
    FIXME("(%p %08x): stub\n", hwnd, flags);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
}