win.c 101 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
#include "windef.h"
29
#include "winbase.h"
30
#include "wine/server.h"
31
#include "wine/unicode.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
32
#include "win.h"
33
#include "user_private.h"
34
#include "controls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#include "winerror.h"
36
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
37

38
WINE_DEFAULT_DEBUG_CHANNEL(win);
39

40 41
#define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
#define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
42

43 44
/**********************************************************************/

45 46 47 48 49 50 51 52 53 54 55 56 57 58 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
/* 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
87

88
static void *user_handles[NB_USER_HANDLES];
89

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/***********************************************************************
 *           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;
        user_handles[index] = ptr;
    }
    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 )
{
146
    assert( ptr && ptr != OBJ_OTHER_PROCESS );
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    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 );
            if (!wine_server_call( req )) user_handles[index] = NULL;
            else ptr = NULL;
        }
        SERVER_END_REQ;
        release_user_handle_ptr( ptr );
    }
    return ptr;
}


174 175 176 177 178
/***********************************************************************
 *           create_window_handle
 *
 * Create a window handle with the server.
 */
179
static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
180
                                  HINSTANCE instance, BOOL unicode )
181
{
182
    WORD index;
183
    WND *win;
184
    HWND handle = 0, full_parent = 0, full_owner = 0;
185 186
    struct tagCLASS *class = NULL;
    int extra_bytes = 0;
187

188
    SERVER_START_REQ( create_window )
189
    {
190 191
        req->parent   = wine_server_user_handle( parent );
        req->owner    = wine_server_user_handle( owner );
192
        req->instance = wine_server_client_ptr( instance );
193 194
        if (!(req->atom = get_int_atom_value( name )) && name)
            wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
195 196
        if (!wine_server_call_err( req ))
        {
197
            handle      = wine_server_ptr_handle( reply->handle );
198 199
            full_parent = wine_server_ptr_handle( reply->parent );
            full_owner  = wine_server_ptr_handle( reply->owner );
200
            extra_bytes = reply->extra;
201
            class       = wine_server_get_ptr( reply->class_ptr );
202
        }
203
    }
204
    SERVER_END_REQ;
205

206 207
    if (!handle)
    {
208
        WARN( "error %d creating window\n", GetLastError() );
209 210 211
        return NULL;
    }

212 213
    if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                           sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
214
    {
215 216
        SERVER_START_REQ( destroy_window )
        {
217
            req->handle = wine_server_user_handle( handle );
218 219 220 221
            wine_server_call( req );
        }
        SERVER_END_REQ;
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
222 223
        return NULL;
    }
224

225 226 227 228
    if (!parent)  /* if parent is 0 we don't have a desktop window yet */
    {
        struct user_thread_info *thread_info = get_user_thread_info();

229 230 231 232 233 234 235 236 237 238 239
        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;
        }
240 241
    }

242 243
    USER_Lock();

244
    index = USER_HANDLE_TO_INDEX(handle);
245 246
    assert( index < NB_USER_HANDLES );
    user_handles[index] = win;
247 248
    win->obj.handle = handle;
    win->obj.type   = USER_WINDOW;
249 250
    win->parent     = full_parent;
    win->owner      = full_owner;
251 252
    win->class      = class;
    win->winproc    = get_class_winproc( class );
253
    win->cbWndExtra = extra_bytes;
254
    if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
255 256 257 258 259 260 261 262 263
    return win;
}


/***********************************************************************
 *           free_window_handle
 *
 * Free a window handle.
 */
264
static void free_window_handle( HWND hwnd )
265
{
266
    struct user_object *ptr;
267
    WORD index = USER_HANDLE_TO_INDEX(hwnd);
268

269
    if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
270 271 272
    {
        SERVER_START_REQ( destroy_window )
        {
273
            req->handle = wine_server_user_handle( hwnd );
274 275
            if (!wine_server_call_err( req )) user_handles[index] = NULL;
            else ptr = NULL;
276 277
        }
        SERVER_END_REQ;
278 279
        release_user_handle_ptr( ptr );
        HeapFree( GetProcessHeap(), 0, ptr );
280 281 282 283
    }
}


284 285 286 287 288 289
/*******************************************************************
 *           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.
 */
290
static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
291
{
292
    HWND *list;
293
    int i, size = 128;
294 295 296 297
    ATOM atom = get_int_atom_value( class );

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

299
    for (;;)
300
    {
301 302 303 304 305
        int count = 0;

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

        SERVER_START_REQ( get_window_children )
306
        {
307
            req->desktop = wine_server_obj_handle( desktop );
308
            req->parent = wine_server_user_handle( hwnd );
309
            req->tid = tid;
310 311
            req->atom = atom;
            if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
312
            wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
313
            if (!wine_server_call( req )) count = reply->count;
314
        }
315 316 317
        SERVER_END_REQ;
        if (count && count < size)
        {
318 319 320
            /* 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] );
321 322 323 324 325 326
            list[count] = 0;
            return list;
        }
        HeapFree( GetProcessHeap(), 0, list );
        if (!count) break;
        size = count + 1;  /* restart with a large enough buffer */
327
    }
328
    return NULL;
329 330 331
}


332 333 334 335 336 337 338 339 340 341
/*******************************************************************
 *           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;
342
    int i, pos = 0, size = 16, count = 0;
343 344 345 346 347 348 349 350

    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 */
351
        if (win == WND_DESKTOP)
352 353
        {
            if (!pos) goto empty;
354
            list[pos] = 0;
355 356
            return list;
        }
357 358
        list[pos] = current = win->parent;
        WIN_ReleasePtr( win );
359
        if (!current) return list;
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
        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 )
        {
377 378
            req->handle = wine_server_user_handle( hwnd );
            wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
379 380 381 382 383 384
            if (!wine_server_call( req )) count = reply->count;
        }
        SERVER_END_REQ;
        if (!count) goto empty;
        if (size > count)
        {
385 386 387
            /* 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] );
388 389 390 391 392 393 394 395 396 397 398 399 400 401
            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;
}


402 403 404 405 406
/*******************************************************************
 *           send_parent_notify
 */
static void send_parent_notify( HWND hwnd, UINT msg )
{
407 408
    if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
        !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
409 410 411 412 413 414
    {
        HWND parent = GetParent(hwnd);
        if (parent && parent != GetDesktopWindow())
            SendMessageW( parent, WM_PARENTNOTIFY,
                          MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
    }
415 416 417
}


418 419 420 421 422 423 424
/*******************************************************************
 *		get_server_window_text
 *
 * Retrieve the window text from the server.
 */
static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
{
425 426 427
    size_t len = 0;

    SERVER_START_REQ( get_window_text )
428
    {
429
        req->handle = wine_server_user_handle( hwnd );
430 431
        wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
        if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
432
    }
433
    SERVER_END_REQ;
434 435 436 437
    text[len / sizeof(WCHAR)] = 0;
}


438 439 440 441 442
/*******************************************************************
 *           get_hwnd_message_parent
 *
 * Return the parent for HWND_MESSAGE windows.
 */
443
HWND get_hwnd_message_parent(void)
444 445 446 447 448 449 450 451
{
    struct user_thread_info *thread_info = get_user_thread_info();

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


452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
/*******************************************************************
 *           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;
}


474
/***********************************************************************
475
 *           WIN_GetPtr
476
 *
477
 * Return a pointer to the WND structure if local to the process,
Andreas Mohr's avatar
Andreas Mohr committed
478
 * or WND_OTHER_PROCESS if handle may be valid in other process.
479
 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
480
 */
481
WND *WIN_GetPtr( HWND hwnd )
482
{
483
    WND *ptr;
484

485
    if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
486
    {
487
        if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
488
    }
489 490 491 492 493 494 495
    return ptr;
}


/***********************************************************************
 *           WIN_IsCurrentProcess
 *
496
 * Check whether a given window belongs to the current process (and return the full handle).
497
 */
498
HWND WIN_IsCurrentProcess( HWND hwnd )
499 500
{
    WND *ptr;
501
    HWND ret;
502

503
    if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
504
    ret = ptr->obj.handle;
505 506
    WIN_ReleasePtr( ptr );
    return ret;
507 508 509 510 511 512
}


/***********************************************************************
 *           WIN_IsCurrentThread
 *
513
 * Check whether a given window belongs to the current thread (and return the full handle).
514
 */
515
HWND WIN_IsCurrentThread( HWND hwnd )
516 517
{
    WND *ptr;
518
    HWND ret = 0;
519

520
    if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
521
    if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
522
    WIN_ReleasePtr( ptr );
523
    return ret;
524 525 526 527
}


/***********************************************************************
528
 *           WIN_GetFullHandle
529
 *
530
 * Convert a possibly truncated window handle to a full 32-bit handle.
531
 */
532
HWND WIN_GetFullHandle( HWND hwnd )
533 534 535
{
    WND *ptr;

536 537
    if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
    if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
538
    /* do sign extension for -2 and -3 */
539
    if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
540

541 542
    if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;

543 544 545 546 547
    if (ptr == WND_DESKTOP)
    {
        if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
        else return get_hwnd_message_parent();
    }
548

549
    if (ptr != WND_OTHER_PROCESS)
550
    {
551
        hwnd = ptr->obj.handle;
552
        WIN_ReleasePtr( ptr );
553 554
    }
    else  /* may belong to another process */
555 556 557
    {
        SERVER_START_REQ( get_window_info )
        {
558 559
            req->handle = wine_server_user_handle( hwnd );
            if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
560 561 562 563 564 565 566
        }
        SERVER_END_REQ;
    }
    return hwnd;
}


567 568 569 570 571
/***********************************************************************
 *           WIN_SetOwner
 *
 * Change the owner of a window.
 */
572
HWND WIN_SetOwner( HWND hwnd, HWND owner )
573
{
574
    WND *win = WIN_GetPtr( hwnd );
575
    HWND ret = 0;
576

577
    if (!win || win == WND_DESKTOP) return 0;
578
    if (win == WND_OTHER_PROCESS)
Alexandre Julliard's avatar
Alexandre Julliard committed
579
    {
580
        if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
581
        return 0;
582
    }
583 584
    SERVER_START_REQ( set_window_owner )
    {
585 586
        req->handle = wine_server_user_handle( hwnd );
        req->owner  = wine_server_user_handle( owner );
587 588
        if (!wine_server_call( req ))
        {
589 590
            win->owner = wine_server_ptr_handle( reply->full_owner );
            ret = wine_server_ptr_handle( reply->prev_owner );
591
        }
592 593 594
    }
    SERVER_END_REQ;
    WIN_ReleasePtr( win );
595
    return ret;
596 597 598 599 600 601 602 603
}


/***********************************************************************
 *           WIN_SetStyle
 *
 * Change the style of a window.
 */
604
ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
605 606
{
    BOOL ok;
607
    STYLESTRUCT style;
608 609
    WND *win = WIN_GetPtr( hwnd );

610
    if (!win || win == WND_DESKTOP) return 0;
611 612 613
    if (win == WND_OTHER_PROCESS)
    {
        if (IsWindow(hwnd))
614
            ERR( "cannot set style %x/%x on other process window %p\n",
615
                 set_bits, clear_bits, hwnd );
616 617
        return 0;
    }
618 619 620
    style.styleOld = win->dwStyle;
    style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
    if (style.styleNew == style.styleOld)
621 622
    {
        WIN_ReleasePtr( win );
623
        return style.styleNew;
624 625 626
    }
    SERVER_START_REQ( set_window_info )
    {
627
        req->handle = wine_server_user_handle( hwnd );
628
        req->flags  = SET_WIN_STYLE;
629
        req->style  = style.styleNew;
630
        req->extra_offset = -1;
631
        if ((ok = !wine_server_call( req )))
632
        {
633 634
            style.styleOld = reply->old_style;
            win->dwStyle = style.styleNew;
635 636 637 638
        }
    }
    SERVER_END_REQ;
    WIN_ReleasePtr( win );
639 640
    if (ok)
    {
641 642
        USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
        if ((style.styleOld ^ style.styleNew) & WS_VISIBLE) invalidate_dce( hwnd, NULL );
643
    }
644
    return style.styleOld;
645 646 647
}


648 649 650 651 652 653 654 655 656 657
/***********************************************************************
 *           WIN_GetRectangles
 *
 * Get the window and client rectangles.
 */
BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
{
    WND *win = WIN_GetPtr( hwnd );
    BOOL ret = TRUE;

658 659 660 661 662
    if (!win)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return FALSE;
    }
663 664 665 666
    if (win == WND_DESKTOP)
    {
        RECT rect;
        rect.left = rect.top = 0;
667 668 669 670 671 672 673 674 675 676
        if (hwnd == get_hwnd_message_parent())
        {
            rect.right  = 100;
            rect.bottom = 100;
        }
        else
        {
            rect.right  = GetSystemMetrics(SM_CXSCREEN);
            rect.bottom = GetSystemMetrics(SM_CYSCREEN);
        }
677 678 679 680
        if (rectWindow) *rectWindow = rect;
        if (rectClient) *rectClient = rect;
    }
    else if (win == WND_OTHER_PROCESS)
681 682 683
    {
        SERVER_START_REQ( get_window_rectangles )
        {
684
            req->handle = wine_server_user_handle( hwnd );
685
            if ((ret = !wine_server_call_err( req )))
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
            {
                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;
                }
            }
        }
        SERVER_END_REQ;
    }
    else
    {
        if (rectWindow) *rectWindow = win->rectWindow;
        if (rectClient) *rectClient = win->rectClient;
        WIN_ReleasePtr( win );
    }
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
715 716 717
/***********************************************************************
 *           WIN_DestroyWindow
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
718
 * Destroy storage associated to a window. "Internals" p.358
Alexandre Julliard's avatar
Alexandre Julliard committed
719
 */
720
LRESULT WIN_DestroyWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
721
{
722 723
    WND *wndPtr;
    HWND *list;
724
    HMENU menu = 0, sys_menu;
725
    HWND icon_title;
Alexandre Julliard's avatar
Alexandre Julliard committed
726

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

Alexandre Julliard's avatar
Alexandre Julliard committed
729
    /* free child windows */
730
    if ((list = WIN_ListChildren( hwnd )))
731
    {
732
        int i;
733 734 735 736 737
        for (i = 0; list[i]; i++)
        {
            if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
            else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
        }
738
        HeapFree( GetProcessHeap(), 0, list );
739
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
740

741
    /* Unlink now so we won't bother with the children later on */
742 743
    SERVER_START_REQ( set_parent )
    {
744
        req->handle = wine_server_user_handle( hwnd );
745 746 747 748
        req->parent = 0;
        wine_server_call( req );
    }
    SERVER_END_REQ;
749

750 751 752
    /*
     * Send the WM_NCDESTROY to the window being destroyed.
     */
753
    SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
754 755 756 757 758

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

    /* free resources associated with the window */

759
    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
760 761
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
        menu = (HMENU)wndPtr->wIDmenu;
762
    sys_menu = wndPtr->hSysMenu;
763 764
    free_dce( wndPtr->dce, hwnd );
    wndPtr->dce = NULL;
765
    icon_title = wndPtr->icon_title;
766 767 768
    HeapFree( GetProcessHeap(), 0, wndPtr->text );
    wndPtr->text = NULL;
    HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
769
    wndPtr->pScroll = NULL;
770 771
    WIN_ReleasePtr( wndPtr );

772
    if (icon_title) DestroyWindow( icon_title );
773 774
    if (menu) DestroyMenu( menu );
    if (sys_menu) DestroyMenu( sys_menu );
Alexandre Julliard's avatar
Alexandre Julliard committed
775

776
    USER_Driver->pDestroyWindow( hwnd );
777 778

    free_window_handle( hwnd );
779
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
780 781
}

782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849

/***********************************************************************
 *		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;
    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 );
        user_handles[index] = NULL;
    }
    USER_Unlock();

    HeapFree( GetProcessHeap(), 0, wndPtr );
    if (menu) DestroyMenu( menu );
    if (sys_menu) DestroyMenu( sys_menu );
}


/***********************************************************************
 *		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
850
/***********************************************************************
851
 *           WIN_DestroyThreadWindows
Alexandre Julliard's avatar
Alexandre Julliard committed
852
 *
853
 * Destroy all children of 'wnd' owned by the current thread.
Alexandre Julliard's avatar
Alexandre Julliard committed
854
 */
855
void WIN_DestroyThreadWindows( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
856
{
857 858
    HWND *list;
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
859

860
    if (!(list = WIN_ListChildren( hwnd ))) return;
861 862

    /* reset owners of top-level windows */
863
    for (i = 0; list[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
864
    {
865 866 867 868 869
        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
870
    }
871 872

    for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
873
    HeapFree( GetProcessHeap(), 0, list );
Alexandre Julliard's avatar
Alexandre Julliard committed
874 875
}

Alexandre Julliard's avatar
Alexandre Julliard committed
876

877
/***********************************************************************
878
 *           WIN_FixCoordinates
879 880 881 882
 *
 * Fix the coordinates - Helper for WIN_CreateWindowEx.
 * returns default show mode in sw.
 */
883
static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
884
{
885
#define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
886 887 888 889 890 891 892
    POINT pos[2];

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

        MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
893
        if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
894 895 896 897

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

898
    if (cs->style & (WS_CHILD | WS_POPUP))
899
    {
900
        if (cs->dwExStyle & WS_EX_MDICHILD)
901
        {
902
            if (IS_DEFAULT(cs->x))
903
            {
904 905
                cs->x = pos[0].x;
                cs->y = pos[0].y;
906
            }
907 908
            if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
            if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
909
        }
910
        else
911
        {
912 913 914 915 916 917 918 919 920
            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;
921

922
        if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
923

924
        monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
925 926 927 928 929 930 931 932 933 934
        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;
        }
935

936 937 938
        if (IS_DEFAULT(cs->cx))
        {
            if (info.dwFlags & STARTF_USESIZE)
939
            {
940 941
                cs->cx = info.dwXSize;
                cs->cy = info.dwYSize;
942
            }
943
            else
944
            {
945 946
                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;
947
            }
948
        }
949 950 951 952
        /* 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.
         */
953 954
        else if (IS_DEFAULT(cs->cy))
        {
955
            FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
956
            cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
957
        }
958
    }
959
#undef IS_DEFAULT
960 961
}

962 963 964 965 966 967
/***********************************************************************
 *           dump_window_styles
 */
static void dump_window_styles( DWORD style, DWORD exstyle )
{
    TRACE( "style:" );
968 969 970 971 972 973 974 975 976
    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");
977 978
    else
    {
979 980
        if(style & WS_BORDER) TRACE(" WS_BORDER");
        if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
981
    }
982 983 984 985
    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");
986 987 988 989 990 991 992 993 994 995
    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");
    }
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017

    /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
#define DUMPED_STYLES \
    (WS_POPUP | \
     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 | \
     WS_MAXIMIZEBOX)

1018 1019
    if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
    TRACE("\n");
1020 1021 1022
#undef DUMPED_STYLES

    TRACE( "exstyle:" );
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
    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");
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061

#define DUMPED_EX_STYLES \
    (WS_EX_DLGMODALFRAME | \
     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 | \
     WS_EX_LAYERED)

1062 1063
    if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
    TRACE("\n");
1064 1065 1066 1067
#undef DUMPED_EX_STYLES
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1068
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070 1071
 *           WIN_CreateWindowEx
 *
 * Implementation of CreateWindowEx().
Alexandre Julliard's avatar
Alexandre Julliard committed
1072
 */
1073
HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
{
1075
    INT cx, cy, style, sw = SW_SHOW;
1076 1077
    LRESULT result;
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1078
    WND *wndPtr;
1079
    HWND hwnd, parent, owner, top_child = 0;
1080 1081 1082
    MDICREATESTRUCTW mdi_cs;
    CBT_CREATEWNDW cbtc;
    CREATESTRUCTW cbcs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1083

1084
    TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1085
          unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1086
          debugstr_w(className),
Alexandre Julliard's avatar
Alexandre Julliard committed
1087 1088
          cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
          cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1089 1090
    if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );

1091 1092 1093 1094 1095 1096
    /* Fix the styles for MDI children */
    if (cs->dwExStyle & WS_EX_MDICHILD)
    {
        UINT flags = 0;

        wndPtr = WIN_GetPtr(cs->hwndParent);
1097
        if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
        {
            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;

1125
        cs->lpCreateParams = &mdi_cs;
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143

        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);
1144 1145 1146 1147 1148 1149 1150 1151

        if (top_child)
        {
            /* Restore current maximized child */
            if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
            {
                TRACE("Restoring current maximized child %p\n", top_child);
                SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1152
                ShowWindow( top_child, SW_SHOWNORMAL );
1153 1154 1155
                SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
            }
        }
1156 1157
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1158
    /* Find the parent window */
Alexandre Julliard's avatar
Alexandre Julliard committed
1159

1160
    parent = cs->hwndParent;
1161
    owner = 0;
1162 1163 1164

    if (cs->hwndParent == HWND_MESSAGE)
    {
1165
        cs->hwndParent = parent = get_hwnd_message_parent();
1166 1167
    }
    else if (cs->hwndParent)
Alexandre Julliard's avatar
Alexandre Julliard committed
1168
    {
1169
        if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
Alexandre Julliard's avatar
Alexandre Julliard committed
1170
        {
1171 1172 1173
            parent = GetDesktopWindow();
            owner = cs->hwndParent;
        }
1174
    }
1175
    else
1176
    {
1177 1178
        static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};

1179 1180 1181
        if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
        {
            WARN("No parent for child window\n" );
1182
            SetLastError(ERROR_TLW_WITH_WSCHILD);
1183 1184
            return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
        }
1185 1186 1187
        /* are we creating the desktop or HWND_MESSAGE parent itself? */
        if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
            (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1188
            parent = GetDesktopWindow();
Alexandre Julliard's avatar
Alexandre Julliard committed
1189
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1190

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

1193 1194 1195 1196 1197 1198 1199
    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
1200
    /* Create the window structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
1201

1202
    if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1203
        return 0;
1204
    hwnd = wndPtr->obj.handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1205

Alexandre Julliard's avatar
Alexandre Julliard committed
1206
    /* Fill the window structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
1207

1208
    wndPtr->tid            = GetCurrentThreadId();
Alexandre Julliard's avatar
Alexandre Julliard committed
1209
    wndPtr->hInstance      = cs->hInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
1210
    wndPtr->text           = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1211 1212
    wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
    wndPtr->dwExStyle      = cs->dwExStyle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1213
    wndPtr->wIDmenu        = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1214
    wndPtr->helpContext    = 0;
1215
    wndPtr->pScroll        = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1216
    wndPtr->userdata       = 0;
1217 1218
    wndPtr->hIcon          = 0;
    wndPtr->hIconSmall     = 0;
1219 1220
    wndPtr->hSysMenu       = 0;

1221 1222 1223
    wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
    wndPtr->max_pos.x = wndPtr->max_pos.y = -1;

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

1226 1227 1228 1229 1230 1231
    /*
     * Correct the window styles.
     *
     * It affects only the style loaded into the WIN structure.
     */

1232
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
    {
        wndPtr->dwStyle |= WS_CLIPSIBLINGS;
        if (!(wndPtr->dwStyle & WS_POPUP))
            wndPtr->dwStyle |= WS_CAPTION;
    }

    /*
     * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
     * why does the user get to set it?
     */

    if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
          (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
        wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
    else
        wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;

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

1253 1254
    SERVER_START_REQ( set_window_info )
    {
1255
        req->handle    = wine_server_user_handle( hwnd );
1256
        req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1257 1258
        req->style     = wndPtr->dwStyle;
        req->ex_style  = wndPtr->dwExStyle;
1259
        req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1260
        req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1261
        req->extra_offset = -1;
1262
        wine_server_call( req );
1263 1264
    }
    SERVER_END_REQ;
Alexandre Julliard's avatar
Alexandre Julliard committed
1265

Alexandre Julliard's avatar
Alexandre Julliard committed
1266 1267
    /* Set the window menu */

1268
    if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
Alexandre Julliard's avatar
Alexandre Julliard committed
1269
    {
1270 1271 1272 1273 1274 1275 1276 1277 1278
        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
1279 1280
        else
        {
1281
            LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
Alexandre Julliard's avatar
Alexandre Julliard committed
1282 1283
            if (menuName)
            {
1284
                cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1285
                if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
Alexandre Julliard's avatar
Alexandre Julliard committed
1286
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1287
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1288
    }
1289
    else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

    /* 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;
1301
    WIN_ReleasePtr( wndPtr );
1302
    if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
Alexandre Julliard's avatar
Alexandre Julliard committed
1303

1304 1305 1306 1307 1308
    /* 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
1309
    {
1310 1311 1312 1313
        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;
1314 1315
        if (minTrack.x > cx) cx = minTrack.x;
        if (minTrack.y > cy) cy = minTrack.y;
1316 1317 1318 1319 1320
    }

    if (cx < 0) cx = 0;
    if (cy < 0) cy = 0;
    SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1321 1322 1323
    /* check for wraparound */
    if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
    if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
    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 */

    if ((wndPtr = WIN_GetPtr(hwnd)))
    {
        /* yes, even if the CBT hook was called with HWND_TOP */
1344
        POINT pt;
1345 1346 1347 1348
        HWND insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
        RECT window_rect = wndPtr->rectWindow;
        RECT client_rect = window_rect;
        WIN_ReleasePtr( wndPtr );
1349 1350 1351 1352 1353

        /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
        pt.x = pt.y = 0;
        MapWindowPoints( parent, 0, &pt, 1 );
        OffsetRect( &client_rect, pt.x, pt.y );
1354
        SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1355
        OffsetRect( &client_rect, -pt.x, -pt.y );
1356
        set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &window_rect, &client_rect, NULL );
1357
    }
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
    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;

1368 1369 1370 1371
    /* call the driver */

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

1372 1373 1374 1375
    NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);

    /* send the size messages */

1376 1377
    if (!(wndPtr = WIN_GetPtr( hwnd )) ||
          wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
    if (!(wndPtr->flags & WIN_NEED_SIZE))
    {
        rect = wndPtr->rectClient;
        WIN_ReleasePtr( wndPtr );
        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 );

1388
    /* Show the window, maximizing or minimizing if needed */
1389

1390 1391 1392 1393 1394 1395 1396 1397 1398
    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;
1399 1400
        SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
                      newPos.bottom - newPos.top, swFlag );
1401
    }
1402

1403
    /* Notify the parent window only */
1404

1405
    send_parent_notify( hwnd, WM_CREATE );
1406
    if (!IsWindow( hwnd )) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1407

1408
    if (cs->style & WS_VISIBLE)
1409
    {
1410
        if (cs->style & WS_MAXIMIZE)
1411
            sw = SW_SHOW;
1412 1413 1414 1415 1416
        else if (cs->style & WS_MINIMIZE)
            sw = SW_SHOWMINIMIZED;

        ShowWindow( hwnd, sw );
        if (cs->dwExStyle & WS_EX_MDICHILD)
1417
        {
1418 1419 1420
            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 );
1421 1422 1423
        }
    }

1424
    /* Call WH_SHELL hook */
1425

1426
    if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1427
        HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1428

1429
    TRACE("created window %p\n", hwnd);
1430
    return hwnd;
1431 1432 1433 1434

failed:
    WIN_DestroyWindow( hwnd );
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436 1437
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1438
/***********************************************************************
1439
 *		CreateWindowExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1440
 */
1441 1442 1443 1444 1445
HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
                                 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
1446
{
1447
    CREATESTRUCTA cs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1448 1449

    cs.lpCreateParams = data;
Alexandre Julliard's avatar
Alexandre Julliard committed
1450 1451
    cs.hInstance      = instance;
    cs.hMenu          = menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1452
    cs.hwndParent     = parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1453 1454 1455 1456 1457
    cs.x              = x;
    cs.y              = y;
    cs.cx             = width;
    cs.cy             = height;
    cs.style          = style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1458 1459
    cs.lpszName       = windowName;
    cs.lpszClass      = className;
Alexandre Julliard's avatar
Alexandre Julliard committed
1460
    cs.dwExStyle      = exStyle;
1461

1462 1463 1464 1465 1466
    if (!IS_INTRESOURCE(className))
    {
        WCHAR bufferW[256];
        if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
            return 0;
1467
        return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1468
    }
1469 1470
    /* Note: we rely on the fact that CREATESTRUCTA and */
    /* CREATESTRUCTW have the same layout. */
1471
    return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1472
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474


Alexandre Julliard's avatar
Alexandre Julliard committed
1475
/***********************************************************************
1476
 *		CreateWindowExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1477
 */
1478 1479 1480 1481 1482
HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
                                 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
1483
{
1484
    CREATESTRUCTW cs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486

    cs.lpCreateParams = data;
Alexandre Julliard's avatar
Alexandre Julliard committed
1487 1488
    cs.hInstance      = instance;
    cs.hMenu          = menu;
Alexandre Julliard's avatar
Alexandre Julliard committed
1489
    cs.hwndParent     = parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1490 1491 1492 1493 1494
    cs.x              = x;
    cs.y              = y;
    cs.cx             = width;
    cs.cy             = height;
    cs.style          = style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1495 1496
    cs.lpszName       = windowName;
    cs.lpszClass      = className;
Alexandre Julliard's avatar
Alexandre Julliard committed
1497
    cs.dwExStyle      = exStyle;
1498

1499
    return wow_handlers.create_window( &cs, className, instance, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1500 1501
}

1502

Alexandre Julliard's avatar
Alexandre Julliard committed
1503 1504 1505
/***********************************************************************
 *           WIN_SendDestroyMsg
 */
1506
static void WIN_SendDestroyMsg( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1507
{
1508 1509 1510 1511 1512
    GUITHREADINFO info;

    if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
    {
        if (hwnd == info.hwndCaret) DestroyCaret();
1513
        if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1514
    }
1515 1516 1517 1518

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

1521 1522 1523 1524
    /*
     * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
     * make sure that the window still exists when we come back.
     */
1525 1526 1527 1528
    if (IsWindow(hwnd))
    {
        HWND* pWndArray;
        int i;
1529

1530
        if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1531

1532
        for (i = 0; pWndArray[i]; i++)
1533 1534 1535
        {
            if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
        }
1536
        HeapFree( GetProcessHeap(), 0, pWndArray );
Alexandre Julliard's avatar
Alexandre Julliard committed
1537 1538
    }
    else
1539
      WARN("\tdestroyed itself while in WM_DESTROY!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1540 1541 1542
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1543
/***********************************************************************
1544
 *		DestroyWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1545
 */
1546
BOOL WINAPI DestroyWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1547
{
1548
    BOOL is_child;
Alexandre Julliard's avatar
Alexandre Julliard committed
1549

1550
    if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1551 1552 1553 1554
    {
        SetLastError( ERROR_ACCESS_DENIED );
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1555

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1558 1559
      /* Call hooks */

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

1562 1563 1564
    if (MENU_IsMenuActive() == hwnd)
        EndMenu();

1565 1566 1567 1568 1569 1570 1571 1572
    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
1573
    {
1574
        HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1575 1576 1577
        /* FIXME: clean up palette - see "Internals" p.352 */
    }

1578
    if (!IsWindow(hwnd)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1579

Alexandre Julliard's avatar
Alexandre Julliard committed
1580
      /* Hide the window */
1581 1582 1583 1584 1585 1586 1587 1588 1589
    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 );
    }
1590

1591
    if (!IsWindow(hwnd)) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1592

Alexandre Julliard's avatar
Alexandre Julliard committed
1593 1594
      /* Recursively destroy owned windows */

1595
    if (!is_child)
Alexandre Julliard's avatar
Alexandre Julliard committed
1596
    {
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617
        for (;;)
        {
            int i, got_one = 0;
            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] );
                        got_one = 1;
                        continue;
                    }
                    WIN_SetOwner( list[i], 0 );
                }
                HeapFree( GetProcessHeap(), 0, list );
            }
            if (!got_one) break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1618 1619
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1620
      /* Send destroy messages */
Alexandre Julliard's avatar
Alexandre Julliard committed
1621

1622
    WIN_SendDestroyMsg( hwnd );
1623
    if (!IsWindow( hwnd )) return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1624

1625 1626 1627
    if (GetClipboardOwner() == hwnd)
        CLIPBOARD_ReleaseOwner();

Alexandre Julliard's avatar
Alexandre Julliard committed
1628 1629
      /* Destroy the window storage */

1630
    WIN_DestroyWindow( hwnd );
1631
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1632 1633 1634
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1635
/***********************************************************************
1636
 *		CloseWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1637
 */
1638
BOOL WINAPI CloseWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1639
{
1640
    if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1641
    ShowWindow( hwnd, SW_MINIMIZE );
1642
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1643 1644
}

1645

Alexandre Julliard's avatar
Alexandre Julliard committed
1646
/***********************************************************************
1647
 *		OpenIcon (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1648
 */
1649
BOOL WINAPI OpenIcon( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1650
{
1651 1652
    if (!IsIconic( hwnd )) return FALSE;
    ShowWindow( hwnd, SW_SHOWNORMAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1653
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1654 1655
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1656

Alexandre Julliard's avatar
Alexandre Julliard committed
1657
/***********************************************************************
1658
 *		FindWindowExW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1659
 */
1660
HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1661
{
1662 1663
    HWND *list = NULL;
    HWND retvalue = 0;
1664 1665
    int i = 0, len = 0;
    WCHAR *buffer = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1666

1667 1668 1669
    if (!parent && child) parent = GetDesktopWindow();
    else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();

1670
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1671
    {
1672 1673
        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
1674
    }
1675

1676
    if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1677 1678

    if (child)
1679
    {
1680
        child = WIN_GetFullHandle( child );
1681
        while (list[i] && list[i] != child) i++;
1682
        if (!list[i]) goto done;
1683
        i++;  /* start from next window */
Alexandre Julliard's avatar
Alexandre Julliard committed
1684 1685
    }

1686
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1687
    {
1688 1689
        while (list[i])
        {
1690
            if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1691 1692
            i++;
        }
1693
    }
1694 1695
    retvalue = list[i];

1696
 done:
1697 1698
    HeapFree( GetProcessHeap(), 0, list );
    HeapFree( GetProcessHeap(), 0, buffer );
1699
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1700
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1701 1702 1703 1704



/***********************************************************************
1705
 *		FindWindowA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1706
 */
1707
HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1708
{
1709
    HWND ret = FindWindowExA( 0, 0, className, title );
Alexandre Julliard's avatar
Alexandre Julliard committed
1710 1711
    if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1712 1713 1714 1715
}


/***********************************************************************
1716
 *		FindWindowExA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1717
 */
1718
HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1719
{
1720 1721
    LPWSTR titleW = NULL;
    HWND hwnd = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1722

1723
    if (title)
Alexandre Julliard's avatar
Alexandre Julliard committed
1724
    {
1725 1726 1727
        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
1728
    }
1729

1730
    if (!IS_INTRESOURCE(className))
Alexandre Julliard's avatar
Alexandre Julliard committed
1731
    {
1732 1733 1734 1735 1736 1737 1738
        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
1739
    }
1740 1741 1742

    HeapFree( GetProcessHeap(), 0, titleW );
    return hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1743 1744 1745 1746
}


/***********************************************************************
1747
 *		FindWindowW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1748
 */
1749
HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
Alexandre Julliard's avatar
Alexandre Julliard committed
1750
{
1751
    return FindWindowExW( 0, 0, className, title );
Alexandre Julliard's avatar
Alexandre Julliard committed
1752 1753 1754
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1755
/**********************************************************************
1756
 *		GetDesktopWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1757
 */
1758
HWND WINAPI GetDesktopWindow(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1759
{
1760 1761
    struct user_thread_info *thread_info = get_user_thread_info();

1762
    if (thread_info->top_window) return thread_info->top_window;
1763 1764 1765 1766

    SERVER_START_REQ( get_desktop_window )
    {
        req->force = 0;
1767 1768
        if (!wine_server_call( req ))
        {
1769 1770
            thread_info->top_window = wine_server_ptr_handle( reply->top_window );
            thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1771
        }
1772 1773 1774
    }
    SERVER_END_REQ;

1775
    if (!thread_info->top_window)
1776
    {
1777 1778 1779
        USEROBJECTFLAGS flags;
        if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
                                        sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1780
        {
1781 1782
            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};
1783 1784
            STARTUPINFOW si;
            PROCESS_INFORMATION pi;
1785 1786 1787
            WCHAR windir[MAX_PATH];
            WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
            WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1788
            void *redir;
1789 1790 1791 1792 1793 1794 1795 1796

            memset( &si, 0, sizeof(si) );
            si.cb = sizeof(si);
            si.dwFlags = STARTF_USESTDHANDLES;
            si.hStdInput  = 0;
            si.hStdOutput = 0;
            si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );

1797
            GetSystemDirectoryW( windir, MAX_PATH );
1798 1799 1800 1801
            strcpyW( app, windir );
            strcatW( app, explorer );
            strcpyW( cmdline, app );
            strcatW( cmdline, args );
1802 1803

            Wow64DisableWow64FsRedirection( &redir );
1804 1805
            if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
                                NULL, windir, &si, &pi ))
1806 1807 1808 1809 1810 1811 1812
            {
                TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
                WaitForInputIdle( pi.hProcess, 10000 );
                CloseHandle( pi.hThread );
                CloseHandle( pi.hProcess );
            }
            else WARN( "failed to start explorer, err %d\n", GetLastError() );
1813
            Wow64RevertWow64FsRedirection( redir );
1814
        }
1815
        else TRACE( "not starting explorer since winstation is not visible\n" );
1816

1817 1818
        SERVER_START_REQ( get_desktop_window )
        {
1819
            req->force = 1;
1820 1821
            if (!wine_server_call( req ))
            {
1822 1823
                thread_info->top_window = wine_server_ptr_handle( reply->top_window );
                thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1824
            }
1825 1826 1827
        }
        SERVER_END_REQ;
    }
1828

1829
    if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1830 1831
        ERR( "failed to create desktop window\n" );

1832
    return thread_info->top_window;
Alexandre Julliard's avatar
Alexandre Julliard committed
1833 1834 1835
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1836
/*******************************************************************
1837
 *		EnableWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1838
 */
1839
BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
Alexandre Julliard's avatar
Alexandre Julliard committed
1840
{
1841
    BOOL retvalue;
1842
    HWND full_handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1843

1844 1845 1846 1847 1848 1849
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }

1850 1851
    if (!(full_handle = WIN_IsCurrentThread( hwnd )))
        return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1852

1853
    hwnd = full_handle;
1854

1855
    TRACE("( %p, %d )\n", hwnd, enable);
1856

1857
    retvalue = !IsWindowEnabled( hwnd );
1858

1859
    if (enable && retvalue)
1860
    {
1861
        WIN_SetStyle( hwnd, 0, WS_DISABLED );
1862
        SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1863
    }
1864
    else if (!enable && !retvalue)
Alexandre Julliard's avatar
Alexandre Julliard committed
1865
    {
1866
        HWND capture_wnd;
1867

1868
        SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1869

1870
        WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1871

1872
        if (hwnd == GetFocus())
1873
            SetFocus( 0 );  /* A disabled window can't have the focus */
1874

1875 1876
        capture_wnd = GetCapture();
        if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1877 1878
            ReleaseCapture();  /* A disabled window can't capture the mouse */

1879
        SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1880
    }
1881
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1882 1883 1884
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1885
/***********************************************************************
1886
 *		IsWindowEnabled (USER32.@)
1887
 */
1888
BOOL WINAPI IsWindowEnabled(HWND hWnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1889
{
1890
    return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
Alexandre Julliard's avatar
Alexandre Julliard committed
1891 1892
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1893

Alexandre Julliard's avatar
Alexandre Julliard committed
1894
/***********************************************************************
1895
 *		IsWindowUnicode (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1896
 */
1897
BOOL WINAPI IsWindowUnicode( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1898
{
1899
    WND * wndPtr;
1900 1901 1902
    BOOL retvalue = FALSE;

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

1904
    if (wndPtr == WND_DESKTOP) return TRUE;
1905 1906 1907

    if (wndPtr != WND_OTHER_PROCESS)
    {
1908
        retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1909 1910 1911 1912 1913 1914
        WIN_ReleasePtr( wndPtr );
    }
    else
    {
        SERVER_START_REQ( get_window_info )
        {
1915
            req->handle = wine_server_user_handle( hwnd );
1916 1917 1918 1919
            if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
        }
        SERVER_END_REQ;
    }
1920
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1921 1922 1923
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1924
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1925 1926 1927
 *	     WIN_GetWindowLong
 *
 * Helper function for GetWindowLong().
Alexandre Julliard's avatar
Alexandre Julliard committed
1928
 */
1929
static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1930
{
1931
    LONG_PTR retvalue = 0;
1932 1933
    WND *wndPtr;

1934
    if (offset == GWLP_HWNDPARENT)
1935 1936 1937
    {
        HWND parent = GetAncestor( hwnd, GA_PARENT );
        if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1938
        return (ULONG_PTR)parent;
1939
    }
1940 1941 1942 1943 1944 1945 1946

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

1947
    if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1948
    {
1949
        if (offset == GWLP_WNDPROC)
1950 1951 1952 1953 1954 1955
        {
            SetLastError( ERROR_ACCESS_DENIED );
            return 0;
        }
        SERVER_START_REQ( set_window_info )
        {
1956
            req->handle = wine_server_user_handle( hwnd );
1957
            req->flags  = 0;  /* don't set anything, just retrieve */
1958
            req->extra_offset = (offset >= 0) ? offset : -1;
1959
            req->extra_size = (offset >= 0) ? size : 0;
1960
            if (!wine_server_call_err( req ))
1961 1962 1963
            {
                switch(offset)
                {
1964 1965 1966
                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;
1967
                case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
1968
                case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1969
                default:
1970
                    if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1971
                    else SetLastError( ERROR_INVALID_INDEX );
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981
                    break;
                }
            }
        }
        SERVER_END_REQ;
        return retvalue;
    }

    /* now we have a valid wndPtr */

Alexandre Julliard's avatar
Alexandre Julliard committed
1982 1983
    if (offset >= 0)
    {
1984
        if (offset > (int)(wndPtr->cbWndExtra - size))
Alexandre Julliard's avatar
Alexandre Julliard committed
1985
        {
1986
            WARN("Invalid offset %d\n", offset );
1987 1988 1989
            WIN_ReleasePtr( wndPtr );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1990
        }
1991 1992
        retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );

Alexandre Julliard's avatar
Alexandre Julliard committed
1993
        /* Special case for dialog window procedure */
1994
        if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
1995
            retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1996 1997
        WIN_ReleasePtr( wndPtr );
        return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1998
    }
1999

Alexandre Julliard's avatar
Alexandre Julliard committed
2000 2001
    switch(offset)
    {
2002
    case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2003 2004
    case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
    case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2005
    case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2006
    case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2007 2008 2009 2010 2011
    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.
         */
2012
        if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2013 2014 2015 2016
            retvalue = (ULONG_PTR)wndPtr->winproc;
        else
            retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
        break;
2017 2018 2019 2020
    default:
        WARN("Unknown offset %d\n", offset );
        SetLastError( ERROR_INVALID_INDEX );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2021
    }
2022
    WIN_ReleasePtr(wndPtr);
2023
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2024 2025 2026
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2027
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
2028 2029 2030
 *	     WIN_SetWindowLong
 *
 * Helper function for SetWindowLong().
Alexandre Julliard's avatar
Alexandre Julliard committed
2031 2032 2033
 *
 * 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
2034
 */
2035
LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
2036
{
2037 2038
    STYLESTRUCT style;
    BOOL ok;
2039
    LONG_PTR retval = 0;
2040
    WND *wndPtr;
2041

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

2044 2045 2046 2047 2048
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061

    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
2062
    {
2063
        if (offset == GWLP_WNDPROC)
2064 2065 2066 2067
        {
            SetLastError( ERROR_ACCESS_DENIED );
            return 0;
        }
2068 2069 2070 2071 2072 2073
        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
2074 2075
    }

2076 2077
    /* first some special cases */
    switch( offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2078
    {
2079 2080 2081 2082 2083 2084 2085 2086 2087 2088
    case GWL_STYLE:
    case GWL_EXSTYLE:
        style.styleOld =
            offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
        style.styleNew = newval;
        WIN_ReleasePtr( wndPtr );
        SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
        if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
        newval = style.styleNew;
        break;
2089
    case GWLP_HWNDPARENT:
2090 2091 2092
        if (wndPtr->parent == GetDesktopWindow())
        {
            WIN_ReleasePtr( wndPtr );
2093
            return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2094 2095 2096 2097
        }
        else
        {
            WIN_ReleasePtr( wndPtr );
2098
            return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2099
        }
2100
    case GWLP_WNDPROC:
2101
    {
2102
        WNDPROC proc;
2103
        UINT old_flags = wndPtr->flags;
2104
        retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2105
        proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2106 2107
        if (proc) wndPtr->winproc = proc;
        if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2108 2109
        else wndPtr->flags &= ~WIN_ISUNICODE;
        if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2110 2111 2112 2113 2114 2115 2116
        {
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* update is_unicode flag on the server side */
        break;
    }
2117 2118 2119
    case GWLP_ID:
    case GWLP_HINSTANCE:
    case GWLP_USERDATA:
2120
        break;
2121
    case DWLP_DLGPROC:
2122
        if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2123
            (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2124
        {
2125
            WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2126
            retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2127
            *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2128 2129 2130 2131 2132
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* fall through */
    default:
2133
        if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
Alexandre Julliard's avatar
Alexandre Julliard committed
2134
        {
2135
            WARN("Invalid offset %d\n", offset );
2136 2137 2138
            WIN_ReleasePtr( wndPtr );
            SetLastError( ERROR_INVALID_INDEX );
            return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2139
        }
2140
        else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
Alexandre Julliard's avatar
Alexandre Julliard committed
2141
        {
2142 2143 2144
            /* already set to the same value */
            WIN_ReleasePtr( wndPtr );
            return newval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2145
        }
2146
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2147
    }
2148

2149 2150
    SERVER_START_REQ( set_window_info )
    {
2151
        req->handle = wine_server_user_handle( hwnd );
2152 2153
        req->extra_offset = -1;
        switch(offset)
2154 2155
        {
        case GWL_STYLE:
2156 2157 2158
            req->flags = SET_WIN_STYLE;
            req->style = newval;
            break;
2159
        case GWL_EXSTYLE:
2160
            req->flags = SET_WIN_EXSTYLE;
2161 2162
            /* WS_EX_TOPMOST can only be changed through SetWindowPos */
            newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2163
            req->ex_style = newval;
2164
            break;
2165
        case GWLP_ID:
2166 2167 2168
            req->flags = SET_WIN_ID;
            req->id = newval;
            break;
2169
        case GWLP_HINSTANCE:
2170
            req->flags = SET_WIN_INSTANCE;
2171
            req->instance = wine_server_client_ptr( (void *)newval );
2172
            break;
2173 2174
        case GWLP_WNDPROC:
            req->flags = SET_WIN_UNICODE;
2175
            req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2176
            break;
2177
        case GWLP_USERDATA:
2178
            req->flags = SET_WIN_USERDATA;
2179
            req->user_data = newval;
2180 2181
            break;
        default:
2182
            req->flags = SET_WIN_EXTRA;
2183
            req->extra_offset = offset;
2184 2185
            req->extra_size = size;
            set_win_data( &req->extra_value, newval, size );
2186
        }
2187
        if ((ok = !wine_server_call_err( req )))
2188 2189 2190 2191
        {
            switch(offset)
            {
            case GWL_STYLE:
2192 2193
                wndPtr->dwStyle = newval;
                retval = reply->old_style;
2194 2195
                break;
            case GWL_EXSTYLE:
2196 2197
                wndPtr->dwExStyle = newval;
                retval = reply->old_ex_style;
2198
                break;
2199
            case GWLP_ID:
2200 2201
                wndPtr->wIDmenu = newval;
                retval = reply->old_id;
2202
                break;
2203
            case GWLP_HINSTANCE:
2204
                wndPtr->hInstance = (HINSTANCE)newval;
2205
                retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2206
                break;
2207 2208
            case GWLP_WNDPROC:
                break;
2209
            case GWLP_USERDATA:
2210
                wndPtr->userdata = newval;
2211
                retval = reply->old_user_data;
2212
                break;
2213
            default:
2214 2215
                retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
                set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2216
                break;
2217 2218
            }
        }
2219 2220 2221
    }
    SERVER_END_REQ;
    WIN_ReleasePtr( wndPtr );
2222

2223
    if (!ok) return 0;
2224

2225
    if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2226 2227
    {
        USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2228
        SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2229
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2230

Alexandre Julliard's avatar
Alexandre Julliard committed
2231 2232 2233 2234
    return retval;
}


2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258
/**********************************************************************
 *		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
2259
/**********************************************************************
2260
 *		GetWindowLongA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2261
 */
2262
LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2263
{
2264
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2265 2266 2267 2268
}


/**********************************************************************
2269
 *		GetWindowLongW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2270
 */
2271
LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
Alexandre Julliard's avatar
Alexandre Julliard committed
2272
{
2273
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2274 2275 2276
}


2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
/**********************************************************************
 *		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
2301
/**********************************************************************
2302
 *		SetWindowLongA (USER32.@)
2303 2304
 *
 * See SetWindowLongW.
Alexandre Julliard's avatar
Alexandre Julliard committed
2305
 */
2306
LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
Alexandre Julliard's avatar
Alexandre Julliard committed
2307
{
2308
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2309 2310 2311
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2312
/**********************************************************************
2313
 *		SetWindowLongW (USER32.@) Set window attribute
Alexandre Julliard's avatar
Alexandre Julliard committed
2314 2315
 *
 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2316
 * value in a window's extra memory.
Alexandre Julliard's avatar
Alexandre Julliard committed
2317 2318 2319 2320 2321 2322 2323 2324 2325 2326
 *
 * The _hwnd_ parameter specifies the window.  is the handle to a
 * window that has extra memory. The _newval_ parameter contains the
 * new attribute or extra memory value.  If positive, the _offset_
 * 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
 *
2327
 * GWL_STYLE        The window's window style.
Alexandre Julliard's avatar
Alexandre Julliard committed
2328
 *
2329
 * GWLP_WNDPROC     Pointer to the window's window procedure.
Alexandre Julliard's avatar
Alexandre Julliard committed
2330
 *
2331
 * GWLP_HINSTANCE   The window's pplication instance handle.
Alexandre Julliard's avatar
Alexandre Julliard committed
2332
 *
2333
 * GWLP_ID          The window's identifier.
Alexandre Julliard's avatar
Alexandre Julliard committed
2334
 *
2335
 * GWLP_USERDATA    The window's user-specified data.
Alexandre Julliard's avatar
Alexandre Julliard committed
2336
 *
2337
 * If the window is a dialog box, the _offset_ parameter can be one of
Alexandre Julliard's avatar
Alexandre Julliard committed
2338 2339
 * the following values:
 *
2340
 * DWLP_DLGPROC     The address of the window's dialog box procedure.
Alexandre Julliard's avatar
Alexandre Julliard committed
2341
 *
2342
 * DWLP_MSGRESULT   The return value of a message
Alexandre Julliard's avatar
Alexandre Julliard committed
2343 2344
 *                  that the dialog box procedure processed.
 *
2345
 * DWLP_USER        Application specific information.
Alexandre Julliard's avatar
Alexandre Julliard committed
2346 2347 2348 2349 2350 2351 2352 2353
 *
 * RETURNS
 *
 * If successful, returns the previous value located at _offset_. Otherwise,
 * returns 0.
 *
 * NOTES
 *
2354
 * Extra memory for a window class is specified by a nonzero cbWndExtra
Alexandre Julliard's avatar
Alexandre Julliard committed
2355 2356
 * parameter of the WNDCLASS structure passed to RegisterClass() at the
 * time of class creation.
2357
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2358 2359 2360 2361 2362 2363 2364
 * 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.
 *
2365
 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
Alexandre Julliard's avatar
Alexandre Julliard committed
2366 2367 2368 2369 2370 2371
 * 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.
 *
2372 2373 2374 2375 2376
 * 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
2377
 */
2378
LONG WINAPI SetWindowLongW(
2379 2380 2381
    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
2382
) {
2383
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
2384 2385 2386 2387
}


/*******************************************************************
2388
 *		GetWindowTextA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2389
 */
2390
INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2391
{
2392 2393
    WCHAR *buffer;

2394 2395
    if (!lpString) return 0;

2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406
    if (WIN_IsCurrentProcess( hwnd ))
        return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );

    /* when window belongs to other process, don't send a message */
    if (nMaxCount <= 0) return 0;
    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
2407
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2408

2409

Alexandre Julliard's avatar
Alexandre Julliard committed
2410
/*******************************************************************
2411
 *		InternalGetWindowText (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2412
 */
2413
INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2414
{
2415 2416 2417 2418
    WND *win;

    if (nMaxCount <= 0) return 0;
    if (!(win = WIN_GetPtr( hwnd ))) return 0;
2419 2420
    if (win == WND_DESKTOP) lpString[0] = 0;
    else if (win != WND_OTHER_PROCESS)
2421 2422 2423 2424 2425 2426 2427 2428 2429
    {
        if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
        else lpString[0] = 0;
        WIN_ReleasePtr( win );
    }
    else
    {
        get_server_window_text( hwnd, lpString, nMaxCount );
    }
2430
    return strlenW(lpString);
Alexandre Julliard's avatar
Alexandre Julliard committed
2431 2432
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2433 2434

/*******************************************************************
2435
 *		GetWindowTextW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2436
 */
2437
INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
Alexandre Julliard's avatar
Alexandre Julliard committed
2438
{
2439 2440
    if (!lpString) return 0;

2441 2442 2443 2444 2445 2446 2447
    if (WIN_IsCurrentProcess( hwnd ))
        return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );

    /* when window belongs to other process, don't send a message */
    if (nMaxCount <= 0) return 0;
    get_server_window_text( hwnd, lpString, nMaxCount );
    return strlenW(lpString);
Alexandre Julliard's avatar
Alexandre Julliard committed
2448 2449 2450
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2451
/*******************************************************************
2452
 *		SetWindowTextA (USER32.@)
2453
 *		SetWindowText  (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2454
 */
2455
BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
Alexandre Julliard's avatar
Alexandre Julliard committed
2456
{
2457 2458 2459 2460 2461
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2462
    if (!WIN_IsCurrentProcess( hwnd ))
2463
        WARN( "setting text %s of other process window %p should not use SendMessage\n",
2464
               debugstr_a(lpString), hwnd );
2465
    return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
Alexandre Julliard's avatar
Alexandre Julliard committed
2466 2467
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2468

Alexandre Julliard's avatar
Alexandre Julliard committed
2469
/*******************************************************************
2470
 *		SetWindowTextW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2471
 */
2472
BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
Alexandre Julliard's avatar
Alexandre Julliard committed
2473
{
2474 2475 2476 2477 2478
    if (is_broadcast(hwnd))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
    }
2479
    if (!WIN_IsCurrentProcess( hwnd ))
2480
        WARN( "setting text %s of other process window %p should not use SendMessage\n",
2481
               debugstr_w(lpString), hwnd );
2482
    return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
Alexandre Julliard's avatar
Alexandre Julliard committed
2483 2484 2485
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2486
/*******************************************************************
2487
 *		GetWindowTextLengthA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2488
 */
2489
INT WINAPI GetWindowTextLengthA( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2490
{
2491
    return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2492 2493 2494
}

/*******************************************************************
2495
 *		GetWindowTextLengthW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2496
 */
2497
INT WINAPI GetWindowTextLengthW( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2498
{
2499
    return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2500 2501
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2502

Alexandre Julliard's avatar
Alexandre Julliard committed
2503
/*******************************************************************
2504
 *		IsWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2505
 */
2506
BOOL WINAPI IsWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2507
{
2508
    WND *ptr;
2509
    BOOL ret;
2510

2511
    if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2512
    if (ptr == WND_DESKTOP) return TRUE;
2513 2514

    if (ptr != WND_OTHER_PROCESS)
2515
    {
2516
        WIN_ReleasePtr( ptr );
2517
        return TRUE;
2518 2519
    }

2520 2521
    /* check other processes */
    SERVER_START_REQ( get_window_info )
2522
    {
2523
        req->handle = wine_server_user_handle( hwnd );
2524
        ret = !wine_server_call_err( req );
2525
    }
2526
    SERVER_END_REQ;
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538
    return ret;
}


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

2539
    if (!(ptr = WIN_GetPtr( hwnd )))
2540
    {
2541 2542 2543 2544
        SetLastError( ERROR_INVALID_WINDOW_HANDLE);
        return 0;
    }

2545
    if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2546 2547 2548 2549 2550
    {
        /* got a valid window */
        tid = ptr->tid;
        if (process) *process = GetCurrentProcessId();
        WIN_ReleasePtr( ptr );
2551 2552 2553 2554 2555 2556
        return tid;
    }

    /* check other processes */
    SERVER_START_REQ( get_window_info )
    {
2557
        req->handle = wine_server_user_handle( hwnd );
2558
        if (!wine_server_call_err( req ))
2559
        {
2560 2561
            tid = (DWORD)reply->tid;
            if (process) *process = (DWORD)reply->pid;
2562 2563 2564 2565
        }
    }
    SERVER_END_REQ;
    return tid;
Alexandre Julliard's avatar
Alexandre Julliard committed
2566 2567 2568
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2569
/*****************************************************************
2570
 *		GetParent (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2571
 */
2572
HWND WINAPI GetParent( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2573
{
2574
    WND *wndPtr;
2575 2576
    HWND retvalue = 0;

2577 2578 2579 2580 2581
    if (!(wndPtr = WIN_GetPtr( hwnd )))
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return 0;
    }
2582
    if (wndPtr == WND_DESKTOP) return 0;
2583 2584 2585 2586 2587 2588 2589
    if (wndPtr == WND_OTHER_PROCESS)
    {
        LONG style = GetWindowLongW( hwnd, GWL_STYLE );
        if (style & (WS_POPUP | WS_CHILD))
        {
            SERVER_START_REQ( get_window_tree )
            {
2590
                req->handle = wine_server_user_handle( hwnd );
2591
                if (!wine_server_call_err( req ))
2592
                {
2593 2594
                    if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
                    else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2595 2596 2597 2598 2599 2600
                }
            }
            SERVER_END_REQ;
        }
    }
    else
2601
    {
2602 2603
        if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
        else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2604
        WIN_ReleasePtr( wndPtr );
2605
    }
2606
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
2607 2608 2609 2610
}


/*****************************************************************
2611
 *		GetAncestor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2612
 */
2613
HWND WINAPI GetAncestor( HWND hwnd, UINT type )
Alexandre Julliard's avatar
Alexandre Julliard committed
2614
{
2615
    WND *win;
2616
    HWND *list, ret = 0;
2617

2618
    switch(type)
2619
    {
2620
    case GA_PARENT:
2621 2622 2623 2624 2625
        if (!(win = WIN_GetPtr( hwnd )))
        {
            SetLastError( ERROR_INVALID_WINDOW_HANDLE );
            return 0;
        }
2626
        if (win == WND_DESKTOP) return 0;
2627
        if (win != WND_OTHER_PROCESS)
2628
        {
2629 2630
            ret = win->parent;
            WIN_ReleasePtr( win );
2631
        }
2632
        else /* need to query the server */
2633
        {
2634
            SERVER_START_REQ( get_window_tree )
2635
            {
2636 2637
                req->handle = wine_server_user_handle( hwnd );
                if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2638
            }
2639
            SERVER_END_REQ;
2640
        }
2641
        break;
2642

2643
    case GA_ROOT:
2644
        if (!(list = list_window_parents( hwnd ))) return 0;
2645

2646 2647 2648 2649 2650 2651 2652 2653 2654
        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;
2655

2656
    case GA_ROOTOWNER:
2657 2658
        if (is_desktop_window( hwnd )) return 0;
        ret = WIN_GetFullHandle( hwnd );
2659 2660
        for (;;)
        {
2661 2662 2663
            HWND parent = GetParent( ret );
            if (!parent) break;
            ret = parent;
2664
        }
2665
        break;
2666 2667
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2668 2669
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2670

Alexandre Julliard's avatar
Alexandre Julliard committed
2671
/*****************************************************************
2672
 *		SetParent (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2673
 */
2674
HWND WINAPI SetParent( HWND hwnd, HWND parent )
Alexandre Julliard's avatar
Alexandre Julliard committed
2675
{
2676
    HWND full_handle;
2677 2678 2679 2680
    HWND old_parent = 0;
    BOOL was_visible;
    WND *wndPtr;
    BOOL ret;
2681

2682 2683 2684 2685 2686 2687
    if (is_broadcast(hwnd) || is_broadcast(parent))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

2688
    if (!parent) parent = GetDesktopWindow();
2689
    else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2690 2691 2692 2693 2694 2695 2696 2697
    else parent = WIN_GetFullHandle( parent );

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

2698 2699 2700 2701 2702 2703 2704
    /* Some applications try to set a child as a parent */
    if (IsChild(hwnd, parent))
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }

2705
    if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2706
        return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2707

2708 2709 2710 2711 2712 2713
    if (full_handle == parent)
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
    }

2714 2715 2716 2717 2718 2719 2720 2721 2722
    /* 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;

    SERVER_START_REQ( set_parent )
    {
2723 2724
        req->handle = wine_server_user_handle( hwnd );
        req->parent = wine_server_user_handle( parent );
2725 2726
        if ((ret = !wine_server_call( req )))
        {
2727 2728
            old_parent = wine_server_ptr_handle( reply->old_parent );
            wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741
        }

    }
    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.
    */
2742
    SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2743 2744 2745 2746 2747
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
    /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
     * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */

    return old_parent;
Alexandre Julliard's avatar
Alexandre Julliard committed
2748 2749
}

2750

Alexandre Julliard's avatar
Alexandre Julliard committed
2751
/*******************************************************************
2752
 *		IsChild (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2753
 */
2754
BOOL WINAPI IsChild( HWND parent, HWND child )
Alexandre Julliard's avatar
Alexandre Julliard committed
2755
{
2756
    HWND *list = list_window_parents( child );
2757 2758 2759 2760
    int i;
    BOOL ret;

    if (!list) return FALSE;
2761
    parent = WIN_GetFullHandle( parent );
2762
    for (i = 0; list[i]; i++) if (list[i] == parent) break;
2763
    ret = list[i] && list[i+1];
2764 2765
    HeapFree( GetProcessHeap(), 0, list );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2766 2767 2768
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2769
/***********************************************************************
2770
 *		IsWindowVisible (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2771
 */
2772
BOOL WINAPI IsWindowVisible( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2773
{
2774
    HWND *list;
2775
    BOOL retval = TRUE;
2776 2777 2778
    int i;

    if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2779
    if (!(list = list_window_parents( hwnd ))) return TRUE;
2780
    if (list[0])
2781 2782 2783
    {
        for (i = 0; list[i+1]; i++)
            if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2784
        retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2785
    }
2786
    HeapFree( GetProcessHeap(), 0, list );
2787
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2788 2789
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2790

Alexandre Julliard's avatar
Alexandre Julliard committed
2791 2792
/***********************************************************************
 *           WIN_IsWindowDrawable
Alexandre Julliard's avatar
Alexandre Julliard committed
2793 2794 2795
 *
 * 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
2796
 * trying to draw its default class icon.
Alexandre Julliard's avatar
Alexandre Julliard committed
2797
 */
2798
BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
Alexandre Julliard's avatar
Alexandre Julliard committed
2799
{
2800
    HWND *list;
2801
    BOOL retval = TRUE;
2802
    int i;
2803
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2804

2805
    if (!(style & WS_VISIBLE)) return FALSE;
2806
    if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2807

2808
    if (!(list = list_window_parents( hwnd ))) return TRUE;
2809
    if (list[0])
2810 2811 2812 2813
    {
        for (i = 0; list[i+1]; i++)
            if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
                break;
2814
        retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2815
    }
2816 2817
    HeapFree( GetProcessHeap(), 0, list );
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2818 2819
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2820

Alexandre Julliard's avatar
Alexandre Julliard committed
2821
/*******************************************************************
2822
 *		GetTopWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2823
 */
2824
HWND WINAPI GetTopWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2825
{
2826 2827
    if (!hwnd) hwnd = GetDesktopWindow();
    return GetWindow( hwnd, GW_CHILD );
Alexandre Julliard's avatar
Alexandre Julliard committed
2828 2829 2830
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2831
/*******************************************************************
2832
 *		GetWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2833
 */
2834
HWND WINAPI GetWindow( HWND hwnd, UINT rel )
Alexandre Julliard's avatar
Alexandre Julliard committed
2835
{
2836
    HWND retval = 0;
2837

2838
    if (rel == GW_OWNER)  /* this one may be available locally */
Alexandre Julliard's avatar
Alexandre Julliard committed
2839
    {
2840 2841 2842 2843 2844 2845
        WND *wndPtr = WIN_GetPtr( hwnd );
        if (!wndPtr)
        {
            SetLastError( ERROR_INVALID_HANDLE );
            return 0;
        }
2846
        if (wndPtr == WND_DESKTOP) return 0;
2847 2848 2849 2850 2851 2852 2853
        if (wndPtr != WND_OTHER_PROCESS)
        {
            retval = wndPtr->owner;
            WIN_ReleasePtr( wndPtr );
            return retval;
        }
        /* else fall through to server call */
2854
    }
2855

2856 2857
    SERVER_START_REQ( get_window_tree )
    {
2858
        req->handle = wine_server_user_handle( hwnd );
2859
        if (!wine_server_call_err( req ))
Alexandre Julliard's avatar
Alexandre Julliard committed
2860
        {
2861
            switch(rel)
2862
            {
2863
            case GW_HWNDFIRST:
2864
                retval = wine_server_ptr_handle( reply->first_sibling );
2865 2866
                break;
            case GW_HWNDLAST:
2867
                retval = wine_server_ptr_handle( reply->last_sibling );
2868 2869
                break;
            case GW_HWNDNEXT:
2870
                retval = wine_server_ptr_handle( reply->next_sibling );
2871 2872
                break;
            case GW_HWNDPREV:
2873
                retval = wine_server_ptr_handle( reply->prev_sibling );
2874
                break;
2875
            case GW_OWNER:
2876
                retval = wine_server_ptr_handle( reply->owner );
2877
                break;
2878
            case GW_CHILD:
2879
                retval = wine_server_ptr_handle( reply->first_child );
2880
                break;
2881
            }
2882
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2883
    }
2884
    SERVER_END_REQ;
2885
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2886 2887 2888
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2889
/*******************************************************************
2890
 *		ShowOwnedPopups (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2891
 */
2892
BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
Alexandre Julliard's avatar
Alexandre Julliard committed
2893
{
2894
    int count = 0;
2895
    WND *pWnd;
2896
    HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2897

2898
    if (!win_array) return TRUE;
2899

2900 2901
    while (win_array[count]) count++;
    while (--count >= 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
2902
    {
2903
        if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2904 2905
        if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
        if (pWnd == WND_OTHER_PROCESS) continue;
2906
        if (fShow)
2907
        {
2908
            if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2909
            {
2910 2911 2912 2913 2914 2915 2916
                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;
2917
            }
2918 2919 2920 2921
        }
        else
        {
            if (pWnd->dwStyle & WS_VISIBLE)
2922
            {
2923 2924 2925 2926 2927 2928 2929
                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;
2930 2931
            }
        }
2932
        WIN_ReleasePtr( pWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
2933
    }
2934
    HeapFree( GetProcessHeap(), 0, win_array );
Alexandre Julliard's avatar
Alexandre Julliard committed
2935
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2936
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2937 2938


Alexandre Julliard's avatar
Alexandre Julliard committed
2939
/*******************************************************************
2940
 *		GetLastActivePopup (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2941
 */
2942
HWND WINAPI GetLastActivePopup( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
2943
{
2944 2945 2946 2947
    HWND retval = hwnd;

    SERVER_START_REQ( get_window_info )
    {
2948 2949
        req->handle = wine_server_user_handle( hwnd );
        if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
2950 2951
    }
    SERVER_END_REQ;
2952
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2953 2954
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2955

2956 2957 2958 2959 2960 2961 2962
/*******************************************************************
 *           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
2963
{
2964 2965 2966 2967 2968
    if (!hwnd)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return NULL;
    }
2969
    return list_window_children( 0, hwnd, NULL, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2970
}
2971

Alexandre Julliard's avatar
Alexandre Julliard committed
2972 2973

/*******************************************************************
2974
 *		EnumWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2975
 */
2976
BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
2977
{
2978 2979
    HWND *list;
    BOOL ret = TRUE;
2980 2981 2982
    int i;

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

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

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

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

2992
    for (i = 0; list[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
2993 2994
    {
        /* Make sure that the window still exists */
2995 2996
        if (!IsWindow( list[i] )) continue;
        if (!(ret = lpEnumFunc( list[i], lParam ))) break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2997
    }
2998
    HeapFree( GetProcessHeap(), 0, list );
2999
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3000
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3001 3002


Alexandre Julliard's avatar
Alexandre Julliard committed
3003
/**********************************************************************
3004
 *		EnumThreadWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3005
 */
3006
BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3007
{
3008
    HWND *list;
3009
    int i;
3010
    BOOL ret = TRUE;
3011 3012

    USER_CheckNotLock();
3013

3014
    if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3015 3016 3017 3018

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

    for (i = 0; list[i]; i++)
3019
        if (!(ret = func( list[i], lParam ))) break;
3020
    HeapFree( GetProcessHeap(), 0, list );
3021
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3022 3023 3024
}


3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
/***********************************************************************
 *              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;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3044
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
3045
 *           WIN_EnumChildWindows
Alexandre Julliard's avatar
Alexandre Julliard committed
3046
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
3047
 * Helper function for EnumChildWindows().
Alexandre Julliard's avatar
Alexandre Julliard committed
3048
 */
3049
static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3050
{
3051 3052
    HWND *childList;
    BOOL ret = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3053

3054
    for ( ; *list; list++)
Alexandre Julliard's avatar
Alexandre Julliard committed
3055
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
3056
        /* Make sure that the window still exists */
3057
        if (!IsWindow( *list )) continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3058
        /* Build children list first */
3059
        childList = WIN_ListChildren( *list );
3060 3061

        ret = func( *list, lParam );
3062

Alexandre Julliard's avatar
Alexandre Julliard committed
3063 3064 3065
        if (childList)
        {
            if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3066
            HeapFree( GetProcessHeap(), 0, childList );
Alexandre Julliard's avatar
Alexandre Julliard committed
3067
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
3068 3069 3070 3071 3072 3073 3074
        if (!ret) return FALSE;
    }
    return TRUE;
}


/**********************************************************************
3075
 *		EnumChildWindows (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3076
 */
3077
BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
3078
{
3079
    HWND *list;
3080
    BOOL ret;
3081 3082

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

3084
    if (!(list = WIN_ListChildren( parent ))) return FALSE;
3085
    ret = WIN_EnumChildWindows( list, func, lParam );
3086
    HeapFree( GetProcessHeap(), 0, list );
3087
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
3088
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3089 3090


Alexandre Julliard's avatar
Alexandre Julliard committed
3091
/*******************************************************************
3092
 *		AnyPopup (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3093
 */
3094
BOOL WINAPI AnyPopup(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3095
{
3096
    int i;
3097
    BOOL retvalue;
3098
    HWND *list = WIN_ListChildren( GetDesktopWindow() );
3099 3100 3101

    if (!list) return FALSE;
    for (i = 0; list[i]; i++)
3102
    {
3103
        if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3104
    }
3105
    retvalue = (list[i] != 0);
3106
    HeapFree( GetProcessHeap(), 0, list );
3107
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
3108 3109
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3110 3111

/*******************************************************************
3112
 *		FlashWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3113
 */
3114
BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
Alexandre Julliard's avatar
Alexandre Julliard committed
3115
{
3116
    WND *wndPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
3117

3118
    TRACE("%p\n", hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
3119

3120
    if (IsIconic( hWnd ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3121
    {
3122
        RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3123 3124

        wndPtr = WIN_GetPtr(hWnd);
3125
        if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3126 3127 3128 3129 3130 3131 3132 3133
        if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
        {
            wndPtr->flags |= WIN_NCACTIVATED;
        }
        else
        {
            wndPtr->flags &= ~WIN_NCACTIVATED;
        }
3134
        WIN_ReleasePtr( wndPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
3135 3136 3137 3138
        return TRUE;
    }
    else
    {
3139 3140 3141
        WPARAM wparam;

        wndPtr = WIN_GetPtr(hWnd);
3142
        if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3143
        hWnd = wndPtr->obj.handle;  /* make it a full handle */
3144

Alexandre Julliard's avatar
Alexandre Julliard committed
3145
        if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3146
        else wparam = (hWnd == GetForegroundWindow());
Alexandre Julliard's avatar
Alexandre Julliard committed
3147

3148
        WIN_ReleasePtr( wndPtr );
3149
        SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
3150 3151
        return wparam;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3152 3153
}

3154 3155 3156 3157 3158 3159 3160 3161
/*******************************************************************
 *		FlashWindowEx (USER32.@)
 */
BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
{
    FIXME("%p\n", pfwi);
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
3162

Alexandre Julliard's avatar
Alexandre Julliard committed
3163
/*******************************************************************
3164
 *		GetWindowContextHelpId (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3165
 */
3166
DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
3167
{
3168
    DWORD retval;
3169
    WND *wnd = WIN_GetPtr( hwnd );
3170
    if (!wnd || wnd == WND_DESKTOP) return 0;
3171 3172 3173 3174 3175
    if (wnd == WND_OTHER_PROCESS)
    {
        if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
        return 0;
    }
3176
    retval = wnd->helpContext;
3177
    WIN_ReleasePtr( wnd );
3178
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
3179 3180 3181 3182
}


/*******************************************************************
3183
 *		SetWindowContextHelpId (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3184
 */
3185
BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
Alexandre Julliard's avatar
Alexandre Julliard committed
3186
{
3187
    WND *wnd = WIN_GetPtr( hwnd );
3188
    if (!wnd || wnd == WND_DESKTOP) return FALSE;
3189 3190 3191 3192 3193
    if (wnd == WND_OTHER_PROCESS)
    {
        if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3194
    wnd->helpContext = id;
3195
    WIN_ReleasePtr( wnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
3196 3197 3198 3199
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3200
/*******************************************************************
3201
 *		DragDetect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
3202
 */
3203
BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
3204
{
3205 3206
    MSG msg;
    RECT rect;
3207 3208
    WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
    WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
Alexandre Julliard's avatar
Alexandre Julliard committed
3209

Alexandre Julliard's avatar
Alexandre Julliard committed
3210 3211
    rect.left = pt.x - wDragWidth;
    rect.right = pt.x + wDragWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
3212

Alexandre Julliard's avatar
Alexandre Julliard committed
3213 3214
    rect.top = pt.y - wDragHeight;
    rect.bottom = pt.y + wDragHeight;
Alexandre Julliard's avatar
Alexandre Julliard committed
3215

3216
    SetCapture(hWnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
3217

Alexandre Julliard's avatar
Alexandre Julliard committed
3218 3219
    while(1)
    {
3220
        while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3221 3222
        {
            if( msg.message == WM_LBUTTONUP )
3223 3224 3225
            {
                ReleaseCapture();
                return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3226 3227
            }
            if( msg.message == WM_MOUSEMOVE )
3228
            {
3229
                POINT tmp;
3230 3231
                tmp.x = (short)LOWORD(msg.lParam);
                tmp.y = (short)HIWORD(msg.lParam);
3232
                if( !PtInRect( &rect, tmp ))
Alexandre Julliard's avatar
Alexandre Julliard committed
3233
                {
3234 3235
                    ReleaseCapture();
                    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
3236
                }
3237
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
3238
        }
3239
        WaitMessage();
Alexandre Julliard's avatar
Alexandre Julliard committed
3240 3241
    }
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
3242 3243
}

3244 3245 3246
/******************************************************************************
 *		GetWindowModuleFileNameA (USER32.@)
 */
3247
UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3248
{
3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
    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 );
3264 3265 3266 3267 3268
}

/******************************************************************************
 *		GetWindowModuleFileNameW (USER32.@)
 */
3269
UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3270
{
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285
    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 );
3286
}
3287 3288 3289

/******************************************************************************
 *              GetWindowInfo (USER32.@)
3290 3291
 *
 * Note: tests show that Windows doesn't check cbSize of the structure.
3292 3293 3294 3295
 */
BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
{
    if (!pwi) return FALSE;
3296 3297 3298 3299 3300 3301
    if (!IsWindow(hwnd)) return FALSE;

    GetWindowRect(hwnd, &pwi->rcWindow);
    GetClientRect(hwnd, &pwi->rcClient);
    /* translate to screen coordinates */
    MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3302

3303 3304
    pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3305
    pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3306 3307 3308 3309 3310 3311 3312

    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;

3313 3314
    return TRUE;
}
3315 3316 3317 3318 3319 3320 3321 3322

/******************************************************************************
 *              SwitchDesktop (USER32.@)
 *
 * NOTES: Sets the current input or interactive desktop.
 */
BOOL WINAPI SwitchDesktop( HDESK hDesktop)
{
3323
    FIXME("(hwnd %p) stub!\n", hDesktop);
3324 3325
    return TRUE;
}
3326 3327 3328 3329

/*****************************************************************************
 *              SetLayeredWindowAttributes (USER32.@)
 */
3330
BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3331
{
3332 3333
    BOOL ret;

3334
    TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3335 3336 3337

    SERVER_START_REQ( set_window_layered_info )
    {
3338
        req->handle = wine_server_user_handle( hwnd );
3339 3340 3341 3342 3343 3344 3345
        req->color_key = key;
        req->alpha = alpha;
        req->flags = flags;
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;

3346 3347
    if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );

3348
    return ret;
3349
}
3350

3351

3352 3353 3354
/*****************************************************************************
 *              GetLayeredWindowAttributes (USER32.@)
 */
3355
BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3356
{
3357 3358 3359 3360
    BOOL ret;

    SERVER_START_REQ( get_window_layered_info )
    {
3361
        req->handle = wine_server_user_handle( hwnd );
3362 3363 3364 3365 3366 3367 3368 3369 3370 3371
        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;
3372 3373
}

3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398

/*****************************************************************************
 *              UpdateLayeredWindowIndirect  (USER32.@)
 */
BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
{
    BYTE alpha = 0xff;

    if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
    {
        int x = 0, y = 0, cx = 0, cy = 0;
        DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;

        if (info->pptDst)
        {
            x = info->pptDst->x;
            y = info->pptDst->y;
            flags &= ~SWP_NOMOVE;
        }
        if (info->psize)
        {
            cx = info->psize->cx;
            cy = info->psize->cy;
            flags &= ~SWP_NOSIZE;
        }
3399
        TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3400 3401 3402 3403 3404
        SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
    }

    if (info->hdcSrc)
    {
3405
        HDC hdc = GetWindowDC( hwnd );
3406 3407 3408 3409

        if (hdc)
        {
            int x = 0, y = 0;
3410
            RECT rect;
3411

3412 3413
            GetWindowRect( hwnd, &rect );
            OffsetRect( &rect, -rect.left, -rect.top);
3414 3415 3416 3417 3418
            if (info->pptSrc)
            {
                x = info->pptSrc->x;
                y = info->pptSrc->y;
            }
3419 3420 3421 3422 3423 3424 3425

            if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
            {
                TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
                BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
                        info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
            }
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437
            ReleaseDC( hwnd, hdc );
        }
    }

    if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
    TRACE( "setting window %p alpha %u\n", hwnd, alpha );
    USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
                                              info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
    return TRUE;
}


3438 3439 3440 3441 3442 3443 3444
/*****************************************************************************
 *              UpdateLayeredWindow (USER32.@)
 */
BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
                                 HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
                                 DWORD dwFlags)
{
3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457
    UPDATELAYEREDWINDOWINFO info;

    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;
    info.dwFlags  = dwFlags;
    info.prcDirty = NULL;
    return UpdateLayeredWindowIndirect( hwnd, &info );
3458
}
3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482

/* 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 )
{
3483
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3484 3485 3486 3487 3488 3489 3490
}

/*****************************************************************************
 *              GetWindowLongPtrA (USER32.@)
 */
LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
{
3491
    return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3492 3493 3494 3495 3496 3497 3498
}

/*****************************************************************************
 *              SetWindowLongPtrW (USER32.@)
 */
LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
{
3499
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3500 3501 3502 3503 3504 3505 3506
}

/*****************************************************************************
 *              SetWindowLongPtrA (USER32.@)
 */
LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
{
3507
    return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3508
}