user32: Don't flush window surfaces while waiting for a sent message reply.
[wine] / dlls / user32 / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * 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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winver.h"
31 #include "wine/server.h"
32 #include "wine/unicode.h"
33 #include "win.h"
34 #include "user_private.h"
35 #include "controls.h"
36 #include "winerror.h"
37 #include "wine/gdi_driver.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
41
42 #define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
43 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
44
45 static DWORD process_layout = ~0u;
46
47 static struct list window_surfaces = LIST_INIT( window_surfaces );
48
49 static CRITICAL_SECTION surfaces_section;
50 static CRITICAL_SECTION_DEBUG critsect_debug =
51 {
52     0, 0, &surfaces_section,
53     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
54       0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") }
55 };
56 static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 };
57
58 /**********************************************************************/
59
60 /* helper for Get/SetWindowLong */
61 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
62 {
63     if (size == sizeof(WORD))
64     {
65         WORD ret;
66         memcpy( &ret, ptr, sizeof(ret) );
67         return ret;
68     }
69     else if (size == sizeof(DWORD))
70     {
71         DWORD ret;
72         memcpy( &ret, ptr, sizeof(ret) );
73         return ret;
74     }
75     else
76     {
77         LONG_PTR ret;
78         memcpy( &ret, ptr, sizeof(ret) );
79         return ret;
80     }
81 }
82
83 /* helper for Get/SetWindowLong */
84 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
85 {
86     if (size == sizeof(WORD))
87     {
88         WORD newval = val;
89         memcpy( ptr, &newval, sizeof(newval) );
90     }
91     else if (size == sizeof(DWORD))
92     {
93         DWORD newval = val;
94         memcpy( ptr, &newval, sizeof(newval) );
95     }
96     else
97     {
98         memcpy( ptr, &val, sizeof(val) );
99     }
100 }
101
102
103 static void *user_handles[NB_USER_HANDLES];
104
105 /***********************************************************************
106  *           alloc_user_handle
107  */
108 HANDLE alloc_user_handle( struct user_object *ptr, enum user_obj_type type )
109 {
110     HANDLE handle = 0;
111
112     SERVER_START_REQ( alloc_user_handle )
113     {
114         if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle );
115     }
116     SERVER_END_REQ;
117
118     if (handle)
119     {
120         UINT index = USER_HANDLE_TO_INDEX( handle );
121
122         assert( index < NB_USER_HANDLES );
123         ptr->handle = handle;
124         ptr->type = type;
125         InterlockedExchangePointer( &user_handles[index], ptr );
126     }
127     return handle;
128 }
129
130
131 /***********************************************************************
132  *           get_user_handle_ptr
133  */
134 void *get_user_handle_ptr( HANDLE handle, enum user_obj_type type )
135 {
136     struct user_object *ptr;
137     WORD index = USER_HANDLE_TO_INDEX( handle );
138
139     if (index >= NB_USER_HANDLES) return NULL;
140
141     USER_Lock();
142     if ((ptr = user_handles[index]))
143     {
144         if (ptr->type == type &&
145             ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle ||
146              !HIWORD(handle) || HIWORD(handle) == 0xffff))
147             return ptr;
148         ptr = NULL;
149     }
150     else ptr = OBJ_OTHER_PROCESS;
151     USER_Unlock();
152     return ptr;
153 }
154
155
156 /***********************************************************************
157  *           release_user_handle_ptr
158  */
159 void release_user_handle_ptr( void *ptr )
160 {
161     assert( ptr && ptr != OBJ_OTHER_PROCESS );
162     USER_Unlock();
163 }
164
165
166 /***********************************************************************
167  *           free_user_handle
168  */
169 void *free_user_handle( HANDLE handle, enum user_obj_type type )
170 {
171     struct user_object *ptr;
172     WORD index = USER_HANDLE_TO_INDEX( handle );
173
174     if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS)
175     {
176         SERVER_START_REQ( free_user_handle )
177         {
178             req->handle = wine_server_user_handle( handle );
179             if (wine_server_call( req )) ptr = NULL;
180             else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
181         }
182         SERVER_END_REQ;
183         release_user_handle_ptr( ptr );
184     }
185     return ptr;
186 }
187
188
189 /***********************************************************************
190  *           create_window_handle
191  *
192  * Create a window handle with the server.
193  */
194 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
195                                   HINSTANCE instance, BOOL unicode )
196 {
197     WORD index;
198     WND *win;
199     HWND handle = 0, full_parent = 0, full_owner = 0;
200     struct tagCLASS *class = NULL;
201     int extra_bytes = 0;
202
203     SERVER_START_REQ( create_window )
204     {
205         req->parent   = wine_server_user_handle( parent );
206         req->owner    = wine_server_user_handle( owner );
207         req->instance = wine_server_client_ptr( instance );
208         if (!(req->atom = get_int_atom_value( name )) && name)
209             wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
210         if (!wine_server_call_err( req ))
211         {
212             handle      = wine_server_ptr_handle( reply->handle );
213             full_parent = wine_server_ptr_handle( reply->parent );
214             full_owner  = wine_server_ptr_handle( reply->owner );
215             extra_bytes = reply->extra;
216             class       = wine_server_get_ptr( reply->class_ptr );
217         }
218     }
219     SERVER_END_REQ;
220
221     if (!handle)
222     {
223         WARN( "error %d creating window\n", GetLastError() );
224         return NULL;
225     }
226
227     if (!(win = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
228                            sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
229     {
230         SERVER_START_REQ( destroy_window )
231         {
232             req->handle = wine_server_user_handle( handle );
233             wine_server_call( req );
234         }
235         SERVER_END_REQ;
236         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
237         return NULL;
238     }
239
240     if (!parent)  /* if parent is 0 we don't have a desktop window yet */
241     {
242         struct user_thread_info *thread_info = get_user_thread_info();
243
244         if (name == (LPCWSTR)DESKTOP_CLASS_ATOM)
245         {
246             if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
247             else assert( full_parent == thread_info->top_window );
248             if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
249                 ERR( "failed to create desktop window\n" );
250         }
251         else  /* HWND_MESSAGE parent */
252         {
253             if (!thread_info->msg_window && !full_parent) thread_info->msg_window = handle;
254         }
255     }
256
257     USER_Lock();
258
259     index = USER_HANDLE_TO_INDEX(handle);
260     assert( index < NB_USER_HANDLES );
261     win->obj.handle = handle;
262     win->obj.type   = USER_WINDOW;
263     win->parent     = full_parent;
264     win->owner      = full_owner;
265     win->class      = class;
266     win->winproc    = get_class_winproc( class );
267     win->cbWndExtra = extra_bytes;
268     InterlockedExchangePointer( &user_handles[index], win );
269     if (WINPROC_IsUnicode( win->winproc, unicode )) win->flags |= WIN_ISUNICODE;
270     return win;
271 }
272
273
274 /***********************************************************************
275  *           free_window_handle
276  *
277  * Free a window handle.
278  */
279 static void free_window_handle( HWND hwnd )
280 {
281     struct user_object *ptr;
282     WORD index = USER_HANDLE_TO_INDEX(hwnd);
283
284     if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) && ptr != OBJ_OTHER_PROCESS)
285     {
286         SERVER_START_REQ( destroy_window )
287         {
288             req->handle = wine_server_user_handle( hwnd );
289             if (wine_server_call_err( req )) ptr = NULL;
290             else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr );
291         }
292         SERVER_END_REQ;
293         release_user_handle_ptr( ptr );
294         HeapFree( GetProcessHeap(), 0, ptr );
295     }
296 }
297
298
299 /*******************************************************************
300  *           list_window_children
301  *
302  * Build an array of the children of a given window. The array must be
303  * freed with HeapFree. Returns NULL when no windows are found.
304  */
305 static HWND *list_window_children( HDESK desktop, HWND hwnd, LPCWSTR class, DWORD tid )
306 {
307     HWND *list;
308     int i, size = 128;
309     ATOM atom = get_int_atom_value( class );
310
311     /* empty class is not the same as NULL class */
312     if (!atom && class && !class[0]) return NULL;
313
314     for (;;)
315     {
316         int count = 0;
317
318         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
319
320         SERVER_START_REQ( get_window_children )
321         {
322             req->desktop = wine_server_obj_handle( desktop );
323             req->parent = wine_server_user_handle( hwnd );
324             req->tid = tid;
325             req->atom = atom;
326             if (!atom && class) wine_server_add_data( req, class, strlenW(class)*sizeof(WCHAR) );
327             wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
328             if (!wine_server_call( req )) count = reply->count;
329         }
330         SERVER_END_REQ;
331         if (count && count < size)
332         {
333             /* start from the end since HWND is potentially larger than user_handle_t */
334             for (i = count - 1; i >= 0; i--)
335                 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
336             list[count] = 0;
337             return list;
338         }
339         HeapFree( GetProcessHeap(), 0, list );
340         if (!count) break;
341         size = count + 1;  /* restart with a large enough buffer */
342     }
343     return NULL;
344 }
345
346
347 /*******************************************************************
348  *           list_window_parents
349  *
350  * Build an array of all parents of a given window, starting with
351  * the immediate parent. The array must be freed with HeapFree.
352  */
353 static HWND *list_window_parents( HWND hwnd )
354 {
355     WND *win;
356     HWND current, *list;
357     int i, pos = 0, size = 16, count = 0;
358
359     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
360
361     current = hwnd;
362     for (;;)
363     {
364         if (!(win = WIN_GetPtr( current ))) goto empty;
365         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
366         if (win == WND_DESKTOP)
367         {
368             if (!pos) goto empty;
369             list[pos] = 0;
370             return list;
371         }
372         list[pos] = current = win->parent;
373         WIN_ReleasePtr( win );
374         if (!current) return list;
375         if (++pos == size - 1)
376         {
377             /* need to grow the list */
378             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
379             if (!new_list) goto empty;
380             list = new_list;
381             size += 16;
382         }
383     }
384
385     /* at least one parent belongs to another process, have to query the server */
386
387     for (;;)
388     {
389         count = 0;
390         SERVER_START_REQ( get_window_parents )
391         {
392             req->handle = wine_server_user_handle( hwnd );
393             wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
394             if (!wine_server_call( req )) count = reply->count;
395         }
396         SERVER_END_REQ;
397         if (!count) goto empty;
398         if (size > count)
399         {
400             /* start from the end since HWND is potentially larger than user_handle_t */
401             for (i = count - 1; i >= 0; i--)
402                 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
403             list[count] = 0;
404             return list;
405         }
406         HeapFree( GetProcessHeap(), 0, list );
407         size = count + 1;
408         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
409     }
410
411  empty:
412     HeapFree( GetProcessHeap(), 0, list );
413     return NULL;
414 }
415
416
417 /*******************************************************************
418  *           send_parent_notify
419  */
420 static void send_parent_notify( HWND hwnd, UINT msg )
421 {
422     if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
423         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
424     {
425         HWND parent = GetParent(hwnd);
426         if (parent && parent != GetDesktopWindow())
427             SendMessageW( parent, WM_PARENTNOTIFY,
428                           MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
429     }
430 }
431
432
433 /*******************************************************************
434  *              update_window_state
435  *
436  * Trigger an update of the window's driver state and surface.
437  */
438 static void update_window_state( HWND hwnd )
439 {
440     RECT window_rect, client_rect;
441
442     WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
443     set_window_pos( hwnd, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE |
444                     SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW, &window_rect, &client_rect, NULL );
445 }
446
447
448 /*******************************************************************
449  *              get_server_window_text
450  *
451  * Retrieve the window text from the server.
452  */
453 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
454 {
455     size_t len = 0;
456
457     SERVER_START_REQ( get_window_text )
458     {
459         req->handle = wine_server_user_handle( hwnd );
460         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
461         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
462     }
463     SERVER_END_REQ;
464     text[len / sizeof(WCHAR)] = 0;
465 }
466
467
468 /*******************************************************************
469  *           get_hwnd_message_parent
470  *
471  * Return the parent for HWND_MESSAGE windows.
472  */
473 HWND get_hwnd_message_parent(void)
474 {
475     struct user_thread_info *thread_info = get_user_thread_info();
476
477     if (!thread_info->msg_window) GetDesktopWindow();  /* trigger creation */
478     return thread_info->msg_window;
479 }
480
481
482 /*******************************************************************
483  *           is_desktop_window
484  *
485  * Check if window is the desktop or the HWND_MESSAGE top parent.
486  */
487 BOOL is_desktop_window( HWND hwnd )
488 {
489     struct user_thread_info *thread_info = get_user_thread_info();
490
491     if (!hwnd) return FALSE;
492     if (hwnd == thread_info->top_window) return TRUE;
493     if (hwnd == thread_info->msg_window) return TRUE;
494
495     if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff)
496     {
497         if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE;
498         if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE;
499     }
500     return FALSE;
501 }
502
503
504 /*******************************************************************
505  * Dummy window surface for windows that shouldn't get painted.
506  */
507
508 static void dummy_surface_lock( struct window_surface *window_surface )
509 {
510     /* nothing to do */
511 }
512
513 static void dummy_surface_unlock( struct window_surface *window_surface )
514 {
515     /* nothing to do */
516 }
517
518 static void *dummy_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
519 {
520     static DWORD dummy_data;
521
522     info->bmiHeader.biSize          = sizeof( info->bmiHeader );
523     info->bmiHeader.biWidth         = dummy_surface.rect.right;
524     info->bmiHeader.biHeight        = dummy_surface.rect.bottom;
525     info->bmiHeader.biPlanes        = 1;
526     info->bmiHeader.biBitCount      = 32;
527     info->bmiHeader.biCompression   = BI_RGB;
528     info->bmiHeader.biSizeImage     = 0;
529     info->bmiHeader.biXPelsPerMeter = 0;
530     info->bmiHeader.biYPelsPerMeter = 0;
531     info->bmiHeader.biClrUsed       = 0;
532     info->bmiHeader.biClrImportant  = 0;
533     return &dummy_data;
534 }
535
536 static RECT *dummy_surface_get_bounds( struct window_surface *window_surface )
537 {
538     static RECT dummy_bounds;
539     return &dummy_bounds;
540 }
541
542 static void dummy_surface_set_region( struct window_surface *window_surface, HRGN region )
543 {
544     /* nothing to do */
545 }
546
547 static void dummy_surface_flush( struct window_surface *window_surface )
548 {
549     /* nothing to do */
550 }
551
552 static void dummy_surface_destroy( struct window_surface *window_surface )
553 {
554     /* nothing to do */
555 }
556
557 static const struct window_surface_funcs dummy_surface_funcs =
558 {
559     dummy_surface_lock,
560     dummy_surface_unlock,
561     dummy_surface_get_bitmap_info,
562     dummy_surface_get_bounds,
563     dummy_surface_set_region,
564     dummy_surface_flush,
565     dummy_surface_destroy
566 };
567
568 struct window_surface dummy_surface = { &dummy_surface_funcs, { NULL, NULL }, 1, { 0, 0, 1, 1 } };
569
570
571 /*******************************************************************
572  *           register_window_surface
573  *
574  * Register a window surface in the global list, possibly replacing another one.
575  */
576 void register_window_surface( struct window_surface *old, struct window_surface *new )
577 {
578     if (old == new) return;
579     EnterCriticalSection( &surfaces_section );
580     if (old && old != &dummy_surface) list_remove( &old->entry );
581     if (new && new != &dummy_surface) list_add_tail( &window_surfaces, &new->entry );
582     LeaveCriticalSection( &surfaces_section );
583 }
584
585
586 /*******************************************************************
587  *           flush_window_surfaces
588  *
589  * Flush pending output from all window surfaces.
590  */
591 void flush_window_surfaces( BOOL idle )
592 {
593     static DWORD last_idle;
594     DWORD now;
595     struct window_surface *surface;
596
597     EnterCriticalSection( &surfaces_section );
598     now = GetTickCount();
599     if (idle) last_idle = now;
600     /* if not idle, we only flush if there's evidence that the app never goes idle */
601     else if ((int)(now - last_idle) < 1000) goto done;
602
603     LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry )
604         surface->funcs->flush( surface );
605 done:
606     LeaveCriticalSection( &surfaces_section );
607 }
608
609
610 /***********************************************************************
611  *           WIN_GetPtr
612  *
613  * Return a pointer to the WND structure if local to the process,
614  * or WND_OTHER_PROCESS if handle may be valid in other process.
615  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
616  */
617 WND *WIN_GetPtr( HWND hwnd )
618 {
619     WND *ptr;
620
621     if ((ptr = get_user_handle_ptr( hwnd, USER_WINDOW )) == WND_OTHER_PROCESS)
622     {
623         if (is_desktop_window( hwnd )) ptr = WND_DESKTOP;
624     }
625     return ptr;
626 }
627
628
629 /***********************************************************************
630  *           WIN_IsCurrentProcess
631  *
632  * Check whether a given window belongs to the current process (and return the full handle).
633  */
634 HWND WIN_IsCurrentProcess( HWND hwnd )
635 {
636     WND *ptr;
637     HWND ret;
638
639     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
640     ret = ptr->obj.handle;
641     WIN_ReleasePtr( ptr );
642     return ret;
643 }
644
645
646 /***********************************************************************
647  *           WIN_IsCurrentThread
648  *
649  * Check whether a given window belongs to the current thread (and return the full handle).
650  */
651 HWND WIN_IsCurrentThread( HWND hwnd )
652 {
653     WND *ptr;
654     HWND ret = 0;
655
656     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
657     if (ptr->tid == GetCurrentThreadId()) ret = ptr->obj.handle;
658     WIN_ReleasePtr( ptr );
659     return ret;
660 }
661
662
663 /***********************************************************************
664  *           WIN_GetFullHandle
665  *
666  * Convert a possibly truncated window handle to a full 32-bit handle.
667  */
668 HWND WIN_GetFullHandle( HWND hwnd )
669 {
670     WND *ptr;
671
672     if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
673     if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
674     /* do sign extension for -2 and -3 */
675     if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
676
677     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
678
679     if (ptr == WND_DESKTOP)
680     {
681         if (LOWORD(hwnd) == LOWORD(GetDesktopWindow())) return GetDesktopWindow();
682         else return get_hwnd_message_parent();
683     }
684
685     if (ptr != WND_OTHER_PROCESS)
686     {
687         hwnd = ptr->obj.handle;
688         WIN_ReleasePtr( ptr );
689     }
690     else  /* may belong to another process */
691     {
692         SERVER_START_REQ( get_window_info )
693         {
694             req->handle = wine_server_user_handle( hwnd );
695             if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
696         }
697         SERVER_END_REQ;
698     }
699     return hwnd;
700 }
701
702
703 /***********************************************************************
704  *           WIN_SetOwner
705  *
706  * Change the owner of a window.
707  */
708 HWND WIN_SetOwner( HWND hwnd, HWND owner )
709 {
710     WND *win = WIN_GetPtr( hwnd );
711     HWND ret = 0;
712
713     if (!win || win == WND_DESKTOP) return 0;
714     if (win == WND_OTHER_PROCESS)
715     {
716         if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
717         return 0;
718     }
719     SERVER_START_REQ( set_window_owner )
720     {
721         req->handle = wine_server_user_handle( hwnd );
722         req->owner  = wine_server_user_handle( owner );
723         if (!wine_server_call( req ))
724         {
725             win->owner = wine_server_ptr_handle( reply->full_owner );
726             ret = wine_server_ptr_handle( reply->prev_owner );
727         }
728     }
729     SERVER_END_REQ;
730     WIN_ReleasePtr( win );
731     return ret;
732 }
733
734
735 /***********************************************************************
736  *           WIN_SetStyle
737  *
738  * Change the style of a window.
739  */
740 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
741 {
742     BOOL ok, made_visible = FALSE;
743     STYLESTRUCT style;
744     WND *win = WIN_GetPtr( hwnd );
745
746     if (!win || win == WND_DESKTOP) return 0;
747     if (win == WND_OTHER_PROCESS)
748     {
749         if (IsWindow(hwnd))
750             ERR( "cannot set style %x/%x on other process window %p\n",
751                  set_bits, clear_bits, hwnd );
752         return 0;
753     }
754     style.styleOld = win->dwStyle;
755     style.styleNew = (win->dwStyle | set_bits) & ~clear_bits;
756     if (style.styleNew == style.styleOld)
757     {
758         WIN_ReleasePtr( win );
759         return style.styleNew;
760     }
761     SERVER_START_REQ( set_window_info )
762     {
763         req->handle = wine_server_user_handle( hwnd );
764         req->flags  = SET_WIN_STYLE;
765         req->style  = style.styleNew;
766         req->extra_offset = -1;
767         if ((ok = !wine_server_call( req )))
768         {
769             style.styleOld = reply->old_style;
770             win->dwStyle = style.styleNew;
771         }
772     }
773     SERVER_END_REQ;
774
775     if (ok && ((style.styleOld ^ style.styleNew) & WS_VISIBLE))
776     {
777         /* Some apps try to make their window visible through WM_SETREDRAW.
778          * Only do that if the window was never explicitly hidden,
779          * because Steam messes with WM_SETREDRAW after hiding its windows. */
780         made_visible = !(win->flags & WIN_HIDDEN) && (style.styleNew & WS_VISIBLE);
781         invalidate_dce( win, NULL );
782     }
783     WIN_ReleasePtr( win );
784
785     if (!ok) return 0;
786
787     USER_Driver->pSetWindowStyle( hwnd, GWL_STYLE, &style );
788     if (made_visible) update_window_state( hwnd );
789
790     return style.styleOld;
791 }
792
793
794 /***********************************************************************
795  *           WIN_GetRectangles
796  *
797  * Get the window and client rectangles.
798  */
799 BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient )
800 {
801     WND *win = WIN_GetPtr( hwnd );
802     BOOL ret = TRUE;
803
804     if (!win)
805     {
806         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
807         return FALSE;
808     }
809     if (win == WND_DESKTOP)
810     {
811         RECT rect;
812         rect.left = rect.top = 0;
813         if (hwnd == get_hwnd_message_parent())
814         {
815             rect.right  = 100;
816             rect.bottom = 100;
817         }
818         else
819         {
820             rect.right  = GetSystemMetrics(SM_CXSCREEN);
821             rect.bottom = GetSystemMetrics(SM_CYSCREEN);
822         }
823         if (rectWindow) *rectWindow = rect;
824         if (rectClient) *rectClient = rect;
825         return TRUE;
826     }
827     if (win != WND_OTHER_PROCESS)
828     {
829         RECT window_rect = win->rectWindow, client_rect = win->rectClient;
830
831         switch (relative)
832         {
833         case COORDS_CLIENT:
834             OffsetRect( &window_rect, -win->rectClient.left, -win->rectClient.top );
835             OffsetRect( &client_rect, -win->rectClient.left, -win->rectClient.top );
836             if (win->dwExStyle & WS_EX_LAYOUTRTL)
837                 mirror_rect( &win->rectClient, &window_rect );
838             break;
839         case COORDS_WINDOW:
840             OffsetRect( &window_rect, -win->rectWindow.left, -win->rectWindow.top );
841             OffsetRect( &client_rect, -win->rectWindow.left, -win->rectWindow.top );
842             if (win->dwExStyle & WS_EX_LAYOUTRTL)
843                 mirror_rect( &win->rectWindow, &client_rect );
844             break;
845         case COORDS_PARENT:
846             if (win->parent)
847             {
848                 WND *parent = WIN_GetPtr( win->parent );
849                 if (parent == WND_DESKTOP) break;
850                 if (!parent || parent == WND_OTHER_PROCESS)
851                 {
852                     WIN_ReleasePtr( win );
853                     goto other_process;
854                 }
855                 if (parent->flags & WIN_CHILDREN_MOVED)
856                 {
857                     WIN_ReleasePtr( parent );
858                     WIN_ReleasePtr( win );
859                     goto other_process;
860                 }
861                 if (parent->dwExStyle & WS_EX_LAYOUTRTL)
862                 {
863                     mirror_rect( &parent->rectClient, &window_rect );
864                     mirror_rect( &parent->rectClient, &client_rect );
865                 }
866                 WIN_ReleasePtr( parent );
867             }
868             break;
869         case COORDS_SCREEN:
870             while (win->parent)
871             {
872                 WND *parent = WIN_GetPtr( win->parent );
873                 if (parent == WND_DESKTOP) break;
874                 if (!parent || parent == WND_OTHER_PROCESS)
875                 {
876                     WIN_ReleasePtr( win );
877                     goto other_process;
878                 }
879                 WIN_ReleasePtr( win );
880                 if (parent->flags & WIN_CHILDREN_MOVED)
881                 {
882                     WIN_ReleasePtr( parent );
883                     goto other_process;
884                 }
885                 win = parent;
886                 if (win->parent)
887                 {
888                     OffsetRect( &window_rect, win->rectClient.left, win->rectClient.top );
889                     OffsetRect( &client_rect, win->rectClient.left, win->rectClient.top );
890                 }
891             }
892             break;
893         }
894         if (rectWindow) *rectWindow = window_rect;
895         if (rectClient) *rectClient = client_rect;
896         WIN_ReleasePtr( win );
897         return TRUE;
898     }
899
900 other_process:
901     SERVER_START_REQ( get_window_rectangles )
902     {
903         req->handle = wine_server_user_handle( hwnd );
904         req->relative = relative;
905         if ((ret = !wine_server_call_err( req )))
906         {
907             if (rectWindow)
908             {
909                 rectWindow->left   = reply->window.left;
910                 rectWindow->top    = reply->window.top;
911                 rectWindow->right  = reply->window.right;
912                 rectWindow->bottom = reply->window.bottom;
913             }
914             if (rectClient)
915             {
916                 rectClient->left   = reply->client.left;
917                 rectClient->top    = reply->client.top;
918                 rectClient->right  = reply->client.right;
919                 rectClient->bottom = reply->client.bottom;
920             }
921         }
922     }
923     SERVER_END_REQ;
924     return ret;
925 }
926
927
928 /***********************************************************************
929  *           WIN_DestroyWindow
930  *
931  * Destroy storage associated to a window. "Internals" p.358
932  */
933 LRESULT WIN_DestroyWindow( HWND hwnd )
934 {
935     WND *wndPtr;
936     HWND *list;
937     HMENU menu = 0, sys_menu;
938     HWND icon_title;
939     struct window_surface *surface;
940
941     TRACE("%p\n", hwnd );
942
943     /* free child windows */
944     if ((list = WIN_ListChildren( hwnd )))
945     {
946         int i;
947         for (i = 0; list[i]; i++)
948         {
949             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
950             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
951         }
952         HeapFree( GetProcessHeap(), 0, list );
953     }
954
955     /* Unlink now so we won't bother with the children later on */
956     SERVER_START_REQ( set_parent )
957     {
958         req->handle = wine_server_user_handle( hwnd );
959         req->parent = 0;
960         wine_server_call( req );
961     }
962     SERVER_END_REQ;
963
964     /*
965      * Send the WM_NCDESTROY to the window being destroyed.
966      */
967     SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
968
969     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
970
971     /* free resources associated with the window */
972
973     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
974     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
975         menu = (HMENU)wndPtr->wIDmenu;
976     sys_menu = wndPtr->hSysMenu;
977     free_dce( wndPtr->dce, hwnd );
978     wndPtr->dce = NULL;
979     icon_title = wndPtr->icon_title;
980     HeapFree( GetProcessHeap(), 0, wndPtr->text );
981     wndPtr->text = NULL;
982     HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
983     wndPtr->pScroll = NULL;
984     surface = wndPtr->surface;
985     wndPtr->surface = NULL;
986     WIN_ReleasePtr( wndPtr );
987
988     if (icon_title) DestroyWindow( icon_title );
989     if (menu) DestroyMenu( menu );
990     if (sys_menu) DestroyMenu( sys_menu );
991     if (surface)
992     {
993         register_window_surface( surface, NULL );
994         window_surface_release( surface );
995     }
996
997     USER_Driver->pDestroyWindow( hwnd );
998
999     free_window_handle( hwnd );
1000     return 0;
1001 }
1002
1003
1004 /***********************************************************************
1005  *              destroy_thread_window
1006  *
1007  * Destroy a window upon exit of its thread.
1008  */
1009 static void destroy_thread_window( HWND hwnd )
1010 {
1011     WND *wndPtr;
1012     HWND *list;
1013     HMENU menu = 0, sys_menu = 0;
1014     struct window_surface *surface = NULL;
1015     WORD index;
1016
1017     /* free child windows */
1018
1019     if ((list = WIN_ListChildren( hwnd )))
1020     {
1021         int i;
1022         for (i = 0; list[i]; i++)
1023         {
1024             if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
1025             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
1026         }
1027         HeapFree( GetProcessHeap(), 0, list );
1028     }
1029
1030     /* destroy the client-side storage */
1031
1032     index = USER_HANDLE_TO_INDEX(hwnd);
1033     if (index >= NB_USER_HANDLES) return;
1034     USER_Lock();
1035     if ((wndPtr = user_handles[index]))
1036     {
1037         if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
1038         sys_menu = wndPtr->hSysMenu;
1039         free_dce( wndPtr->dce, hwnd );
1040         surface = wndPtr->surface;
1041         wndPtr->surface = NULL;
1042         InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
1043     }
1044     USER_Unlock();
1045
1046     HeapFree( GetProcessHeap(), 0, wndPtr );
1047     if (menu) DestroyMenu( menu );
1048     if (sys_menu) DestroyMenu( sys_menu );
1049     if (surface)
1050     {
1051         register_window_surface( surface, NULL );
1052         window_surface_release( surface );
1053     }
1054 }
1055
1056
1057 /***********************************************************************
1058  *              destroy_thread_child_windows
1059  *
1060  * Destroy child windows upon exit of its thread.
1061  */
1062 static void destroy_thread_child_windows( HWND hwnd )
1063 {
1064     HWND *list;
1065     int i;
1066
1067     if (WIN_IsCurrentThread( hwnd ))
1068     {
1069         destroy_thread_window( hwnd );
1070     }
1071     else if ((list = WIN_ListChildren( hwnd )))
1072     {
1073         for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1074         HeapFree( GetProcessHeap(), 0, list );
1075     }
1076 }
1077
1078
1079 /***********************************************************************
1080  *           WIN_DestroyThreadWindows
1081  *
1082  * Destroy all children of 'wnd' owned by the current thread.
1083  */
1084 void WIN_DestroyThreadWindows( HWND hwnd )
1085 {
1086     HWND *list;
1087     int i;
1088
1089     if (!(list = WIN_ListChildren( hwnd ))) return;
1090
1091     /* reset owners of top-level windows */
1092     for (i = 0; list[i]; i++)
1093     {
1094         if (!WIN_IsCurrentThread( list[i] ))
1095         {
1096             HWND owner = GetWindow( list[i], GW_OWNER );
1097             if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
1098         }
1099     }
1100
1101     for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
1102     HeapFree( GetProcessHeap(), 0, list );
1103 }
1104
1105
1106 /***********************************************************************
1107  *           WIN_FixCoordinates
1108  *
1109  * Fix the coordinates - Helper for WIN_CreateWindowEx.
1110  * returns default show mode in sw.
1111  */
1112 static void WIN_FixCoordinates( CREATESTRUCTW *cs, INT *sw)
1113 {
1114 #define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1115     POINT pos[2];
1116
1117     if (cs->dwExStyle & WS_EX_MDICHILD)
1118     {
1119         UINT id = 0;
1120
1121         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
1122         if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id);
1123
1124         TRACE("MDI child id %04x\n", id);
1125     }
1126
1127     if (cs->style & (WS_CHILD | WS_POPUP))
1128     {
1129         if (cs->dwExStyle & WS_EX_MDICHILD)
1130         {
1131             if (IS_DEFAULT(cs->x))
1132             {
1133                 cs->x = pos[0].x;
1134                 cs->y = pos[0].y;
1135             }
1136             if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
1137             if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
1138         }
1139         else
1140         {
1141             if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
1142             if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
1143         }
1144     }
1145     else  /* overlapped window */
1146     {
1147         HMONITOR monitor;
1148         MONITORINFO mon_info;
1149         STARTUPINFOW info;
1150
1151         if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
1152
1153         monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
1154         mon_info.cbSize = sizeof(mon_info);
1155         GetMonitorInfoW( monitor, &mon_info );
1156         GetStartupInfoW( &info );
1157
1158         if (IS_DEFAULT(cs->x))
1159         {
1160             if (!IS_DEFAULT(cs->y)) *sw = cs->y;
1161             cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
1162             cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
1163         }
1164
1165         if (IS_DEFAULT(cs->cx))
1166         {
1167             if (info.dwFlags & STARTF_USESIZE)
1168             {
1169                 cs->cx = info.dwXSize;
1170                 cs->cy = info.dwYSize;
1171             }
1172             else
1173             {
1174                 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
1175                 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1176             }
1177         }
1178         /* neither x nor cx are default. Check the y values .
1179          * In the trace we see Outlook and Outlook Express using
1180          * cy set to CW_USEDEFAULT when opening the address book.
1181          */
1182         else if (IS_DEFAULT(cs->cy))
1183         {
1184             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
1185             cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
1186         }
1187     }
1188 #undef IS_DEFAULT
1189 }
1190
1191 /***********************************************************************
1192  *           dump_window_styles
1193  */
1194 static void dump_window_styles( DWORD style, DWORD exstyle )
1195 {
1196     TRACE( "style:" );
1197     if(style & WS_POPUP) TRACE(" WS_POPUP");
1198     if(style & WS_CHILD) TRACE(" WS_CHILD");
1199     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
1200     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
1201     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
1202     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
1203     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
1204     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
1205     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
1206     else
1207     {
1208         if(style & WS_BORDER) TRACE(" WS_BORDER");
1209         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
1210     }
1211     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
1212     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
1213     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
1214     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
1215     if (style & WS_CHILD)
1216     {
1217         if(style & WS_GROUP) TRACE(" WS_GROUP");
1218         if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
1219     }
1220     else
1221     {
1222         if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
1223         if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
1224     }
1225
1226     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
1227 #define DUMPED_STYLES \
1228     ((DWORD)(WS_POPUP | \
1229      WS_CHILD | \
1230      WS_MINIMIZE | \
1231      WS_VISIBLE | \
1232      WS_DISABLED | \
1233      WS_CLIPSIBLINGS | \
1234      WS_CLIPCHILDREN | \
1235      WS_MAXIMIZE | \
1236      WS_BORDER | \
1237      WS_DLGFRAME | \
1238      WS_VSCROLL | \
1239      WS_HSCROLL | \
1240      WS_SYSMENU | \
1241      WS_THICKFRAME | \
1242      WS_GROUP | \
1243      WS_TABSTOP | \
1244      WS_MINIMIZEBOX | \
1245      WS_MAXIMIZEBOX))
1246
1247     if(style & ~DUMPED_STYLES) TRACE(" %08x", style & ~DUMPED_STYLES);
1248     TRACE("\n");
1249 #undef DUMPED_STYLES
1250
1251     TRACE( "exstyle:" );
1252     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
1253     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
1254     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
1255     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
1256     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
1257     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
1258     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
1259     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
1260     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
1261     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
1262     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
1263     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
1264     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
1265     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
1266     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
1267     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
1268     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
1269     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
1270     if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL");
1271
1272 #define DUMPED_EX_STYLES \
1273     ((DWORD)(WS_EX_DLGMODALFRAME | \
1274      WS_EX_DRAGDETECT | \
1275      WS_EX_NOPARENTNOTIFY | \
1276      WS_EX_TOPMOST | \
1277      WS_EX_ACCEPTFILES | \
1278      WS_EX_TRANSPARENT | \
1279      WS_EX_MDICHILD | \
1280      WS_EX_TOOLWINDOW | \
1281      WS_EX_WINDOWEDGE | \
1282      WS_EX_CLIENTEDGE | \
1283      WS_EX_CONTEXTHELP | \
1284      WS_EX_RIGHT | \
1285      WS_EX_RTLREADING | \
1286      WS_EX_LEFTSCROLLBAR | \
1287      WS_EX_CONTROLPARENT | \
1288      WS_EX_STATICEDGE | \
1289      WS_EX_APPWINDOW | \
1290      WS_EX_LAYERED | \
1291      WS_EX_LAYOUTRTL))
1292
1293     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08x", exstyle & ~DUMPED_EX_STYLES);
1294     TRACE("\n");
1295 #undef DUMPED_EX_STYLES
1296 }
1297
1298
1299 /***********************************************************************
1300  *           WIN_CreateWindowEx
1301  *
1302  * Implementation of CreateWindowEx().
1303  */
1304 HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode )
1305 {
1306     INT cx, cy, style, sw = SW_SHOW;
1307     LRESULT result;
1308     RECT rect;
1309     WND *wndPtr;
1310     HWND hwnd, parent, owner, top_child = 0;
1311     MDICREATESTRUCTW mdi_cs;
1312     CBT_CREATEWNDW cbtc;
1313     CREATESTRUCTW cbcs;
1314
1315     TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1316           unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName),
1317           debugstr_w(className),
1318           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1319           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1320     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1321
1322     /* Fix the styles for MDI children */
1323     if (cs->dwExStyle & WS_EX_MDICHILD)
1324     {
1325         UINT flags = 0;
1326
1327         wndPtr = WIN_GetPtr(cs->hwndParent);
1328         if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1329         {
1330             flags = wndPtr->flags;
1331             WIN_ReleasePtr(wndPtr);
1332         }
1333
1334         if (!(flags & WIN_ISMDICLIENT))
1335         {
1336             WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1337             return 0;
1338         }
1339
1340         /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1341          * MDICREATESTRUCT members have the originally passed values.
1342          *
1343          * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1344          * have the same layout.
1345          */
1346         mdi_cs.szClass = cs->lpszClass;
1347         mdi_cs.szTitle = cs->lpszName;
1348         mdi_cs.hOwner = cs->hInstance;
1349         mdi_cs.x = cs->x;
1350         mdi_cs.y = cs->y;
1351         mdi_cs.cx = cs->cx;
1352         mdi_cs.cy = cs->cy;
1353         mdi_cs.style = cs->style;
1354         mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1355
1356         cs->lpCreateParams = &mdi_cs;
1357
1358         if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1359         {
1360             if (cs->style & WS_POPUP)
1361             {
1362                 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1363                 return 0;
1364             }
1365             cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1366         }
1367         else
1368         {
1369             cs->style &= ~WS_POPUP;
1370             cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1371                 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1372         }
1373
1374         top_child = GetWindow(cs->hwndParent, GW_CHILD);
1375
1376         if (top_child)
1377         {
1378             /* Restore current maximized child */
1379             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1380             {
1381                 TRACE("Restoring current maximized child %p\n", top_child);
1382                 if (cs->style & WS_MAXIMIZE)
1383                 {
1384                     /* if the new window is maximized don't bother repainting */
1385                     SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
1386                     ShowWindow( top_child, SW_SHOWNORMAL );
1387                     SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
1388                 }
1389                 else ShowWindow( top_child, SW_SHOWNORMAL );
1390             }
1391         }
1392     }
1393
1394     /* Find the parent window */
1395
1396     parent = cs->hwndParent;
1397     owner = 0;
1398
1399     if (cs->hwndParent == HWND_MESSAGE)
1400     {
1401         cs->hwndParent = parent = get_hwnd_message_parent();
1402     }
1403     else if (cs->hwndParent)
1404     {
1405         if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1406         {
1407             parent = GetDesktopWindow();
1408             owner = cs->hwndParent;
1409         }
1410         else
1411         {
1412             DWORD parent_style = GetWindowLongW( parent, GWL_EXSTYLE );
1413             if ((parent_style & WS_EX_LAYOUTRTL) && !(parent_style & WS_EX_NOINHERITLAYOUT))
1414                 cs->dwExStyle |= WS_EX_LAYOUTRTL;
1415         }
1416     }
1417     else
1418     {
1419         static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
1420
1421         if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1422         {
1423             WARN("No parent for child window\n" );
1424             SetLastError(ERROR_TLW_WITH_WSCHILD);
1425             return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1426         }
1427         /* are we creating the desktop or HWND_MESSAGE parent itself? */
1428         if (className != (LPCWSTR)DESKTOP_CLASS_ATOM &&
1429             (IS_INTRESOURCE(className) || strcmpiW( className, messageW )))
1430         {
1431             DWORD layout;
1432             GetProcessDefaultLayout( &layout );
1433             if (layout & LAYOUT_RTL) cs->dwExStyle |= WS_EX_LAYOUTRTL;
1434             parent = GetDesktopWindow();
1435         }
1436     }
1437
1438     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1439
1440     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1441         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1442           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1443         cs->dwExStyle |= WS_EX_WINDOWEDGE;
1444     else
1445         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1446
1447     /* Create the window structure */
1448
1449     if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
1450         return 0;
1451     hwnd = wndPtr->obj.handle;
1452
1453     /* Fill the window structure */
1454
1455     wndPtr->tid            = GetCurrentThreadId();
1456     wndPtr->hInstance      = cs->hInstance;
1457     wndPtr->text           = NULL;
1458     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
1459     wndPtr->dwExStyle      = cs->dwExStyle;
1460     wndPtr->wIDmenu        = 0;
1461     wndPtr->helpContext    = 0;
1462     wndPtr->pScroll        = NULL;
1463     wndPtr->userdata       = 0;
1464     wndPtr->hIcon          = 0;
1465     wndPtr->hIconSmall     = 0;
1466     wndPtr->hSysMenu       = 0;
1467
1468     wndPtr->min_pos.x = wndPtr->min_pos.y = -1;
1469     wndPtr->max_pos.x = wndPtr->max_pos.y = -1;
1470     SetRect( &wndPtr->normal_rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1471
1472     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1473
1474     /*
1475      * Correct the window styles.
1476      *
1477      * It affects only the style loaded into the WIN structure.
1478      */
1479
1480     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1481     {
1482         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1483         if (!(wndPtr->dwStyle & WS_POPUP))
1484             wndPtr->dwStyle |= WS_CAPTION;
1485     }
1486
1487     /* WS_EX_WINDOWEDGE depends on some other styles */
1488     if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1489         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1490     else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1491     {
1492         if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1493             (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1494             wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1495     }
1496     else
1497         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1498
1499     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1500         wndPtr->flags |= WIN_NEED_SIZE;
1501
1502     SERVER_START_REQ( set_window_info )
1503     {
1504         req->handle    = wine_server_user_handle( hwnd );
1505         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1506         req->style     = wndPtr->dwStyle;
1507         req->ex_style  = wndPtr->dwExStyle;
1508         req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1509         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1510         req->extra_offset = -1;
1511         wine_server_call( req );
1512     }
1513     SERVER_END_REQ;
1514
1515     /* Set the window menu */
1516
1517     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1518     {
1519         if (cs->hMenu)
1520         {
1521             if (!MENU_SetMenu(hwnd, cs->hMenu))
1522             {
1523                 WIN_ReleasePtr( wndPtr );
1524                 free_window_handle( hwnd );
1525                 return 0;
1526             }
1527         }
1528         else
1529         {
1530             LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1531             if (menuName)
1532             {
1533                 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1534                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1535             }
1536         }
1537     }
1538     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1539
1540     /* call the WH_CBT hook */
1541
1542     /* the window style passed to the hook must be the real window style,
1543      * rather than just the window style that the caller to CreateWindowEx
1544      * passed in, so we have to copy the original CREATESTRUCT and get the
1545      * the real style. */
1546     cbcs = *cs;
1547     cbcs.style = wndPtr->dwStyle;
1548     cbtc.lpcs = &cbcs;
1549     cbtc.hwndInsertAfter = HWND_TOP;
1550     WIN_ReleasePtr( wndPtr );
1551     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1552
1553     /* send the WM_GETMINMAXINFO message and fix the size if needed */
1554
1555     cx = cs->cx;
1556     cy = cs->cy;
1557     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1558     {
1559         POINT maxSize, maxPos, minTrack, maxTrack;
1560         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1561         if (maxTrack.x < cx) cx = maxTrack.x;
1562         if (maxTrack.y < cy) cy = maxTrack.y;
1563         if (minTrack.x > cx) cx = minTrack.x;
1564         if (minTrack.y > cy) cy = minTrack.y;
1565     }
1566
1567     if (cx < 0) cx = 0;
1568     if (cy < 0) cy = 0;
1569     SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1570     /* check for wraparound */
1571     if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1572     if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1573     if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1574
1575     /* send WM_NCCREATE */
1576
1577     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1578     if (unicode)
1579         result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1580     else
1581         result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1582     if (!result)
1583     {
1584         WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1585         goto failed;
1586     }
1587
1588     /* send WM_NCCALCSIZE */
1589
1590     if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1591     {
1592         /* yes, even if the CBT hook was called with HWND_TOP */
1593         HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1594         RECT client_rect = rect;
1595
1596         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1597         MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1598         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1599         MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1600         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1601     }
1602     else return 0;
1603
1604     /* send WM_CREATE */
1605
1606     if (unicode)
1607         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1608     else
1609         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1610     if (result == -1) goto failed;
1611
1612     /* call the driver */
1613
1614     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1615
1616     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1617
1618     /* send the size messages */
1619
1620     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1621           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1622     if (!(wndPtr->flags & WIN_NEED_SIZE))
1623     {
1624         WIN_ReleasePtr( wndPtr );
1625         WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1626         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1627                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1628         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1629     }
1630     else WIN_ReleasePtr( wndPtr );
1631
1632     /* Show the window, maximizing or minimizing if needed */
1633
1634     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1635     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1636     {
1637         RECT newPos;
1638         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1639
1640         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1641         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1642         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1643         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1644                       newPos.bottom - newPos.top, swFlag );
1645     }
1646
1647     /* Notify the parent window only */
1648
1649     send_parent_notify( hwnd, WM_CREATE );
1650     if (!IsWindow( hwnd )) return 0;
1651
1652     if (cs->style & WS_VISIBLE)
1653     {
1654         if (cs->style & WS_MAXIMIZE)
1655             sw = SW_SHOW;
1656         else if (cs->style & WS_MINIMIZE)
1657             sw = SW_SHOWMINIMIZED;
1658
1659         ShowWindow( hwnd, sw );
1660         if (cs->dwExStyle & WS_EX_MDICHILD)
1661         {
1662             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1663             /* ShowWindow won't activate child windows */
1664             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1665         }
1666     }
1667
1668     /* Call WH_SHELL hook */
1669
1670     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1671         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1672
1673     TRACE("created window %p\n", hwnd);
1674     return hwnd;
1675
1676 failed:
1677     WIN_DestroyWindow( hwnd );
1678     return 0;
1679 }
1680
1681
1682 /***********************************************************************
1683  *              CreateWindowExA (USER32.@)
1684  */
1685 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1686                                  LPCSTR windowName, DWORD style, INT x,
1687                                  INT y, INT width, INT height,
1688                                  HWND parent, HMENU menu,
1689                                  HINSTANCE instance, LPVOID data )
1690 {
1691     CREATESTRUCTA cs;
1692
1693     cs.lpCreateParams = data;
1694     cs.hInstance      = instance;
1695     cs.hMenu          = menu;
1696     cs.hwndParent     = parent;
1697     cs.x              = x;
1698     cs.y              = y;
1699     cs.cx             = width;
1700     cs.cy             = height;
1701     cs.style          = style;
1702     cs.lpszName       = windowName;
1703     cs.lpszClass      = className;
1704     cs.dwExStyle      = exStyle;
1705
1706     if (!IS_INTRESOURCE(className))
1707     {
1708         WCHAR bufferW[256];
1709         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1710             return 0;
1711         return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1712     }
1713     /* Note: we rely on the fact that CREATESTRUCTA and */
1714     /* CREATESTRUCTW have the same layout. */
1715     return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1716 }
1717
1718
1719 /***********************************************************************
1720  *              CreateWindowExW (USER32.@)
1721  */
1722 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1723                                  LPCWSTR windowName, DWORD style, INT x,
1724                                  INT y, INT width, INT height,
1725                                  HWND parent, HMENU menu,
1726                                  HINSTANCE instance, LPVOID data )
1727 {
1728     CREATESTRUCTW cs;
1729
1730     cs.lpCreateParams = data;
1731     cs.hInstance      = instance;
1732     cs.hMenu          = menu;
1733     cs.hwndParent     = parent;
1734     cs.x              = x;
1735     cs.y              = y;
1736     cs.cx             = width;
1737     cs.cy             = height;
1738     cs.style          = style;
1739     cs.lpszName       = windowName;
1740     cs.lpszClass      = className;
1741     cs.dwExStyle      = exStyle;
1742
1743     return wow_handlers.create_window( &cs, className, instance, TRUE );
1744 }
1745
1746
1747 /***********************************************************************
1748  *           WIN_SendDestroyMsg
1749  */
1750 static void WIN_SendDestroyMsg( HWND hwnd )
1751 {
1752     GUITHREADINFO info;
1753
1754     info.cbSize = sizeof(info);
1755     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1756     {
1757         if (hwnd == info.hwndCaret) DestroyCaret();
1758         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1759     }
1760
1761     /*
1762      * Send the WM_DESTROY to the window.
1763      */
1764     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1765
1766     /*
1767      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1768      * make sure that the window still exists when we come back.
1769      */
1770     if (IsWindow(hwnd))
1771     {
1772         HWND* pWndArray;
1773         int i;
1774
1775         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1776
1777         for (i = 0; pWndArray[i]; i++)
1778         {
1779             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1780         }
1781         HeapFree( GetProcessHeap(), 0, pWndArray );
1782     }
1783     else
1784       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1785 }
1786
1787
1788 /***********************************************************************
1789  *              DestroyWindow (USER32.@)
1790  */
1791 BOOL WINAPI DestroyWindow( HWND hwnd )
1792 {
1793     BOOL is_child;
1794
1795     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1796     {
1797         SetLastError( ERROR_ACCESS_DENIED );
1798         return FALSE;
1799     }
1800
1801     TRACE("(%p)\n", hwnd);
1802
1803       /* Call hooks */
1804
1805     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1806
1807     if (MENU_IsMenuActive() == hwnd)
1808         EndMenu();
1809
1810     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1811
1812     if (is_child)
1813     {
1814         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1815             send_parent_notify( hwnd, WM_DESTROY );
1816     }
1817     else if (!GetWindow( hwnd, GW_OWNER ))
1818     {
1819         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1820         /* FIXME: clean up palette - see "Internals" p.352 */
1821     }
1822
1823     if (!IsWindow(hwnd)) return TRUE;
1824
1825       /* Hide the window */
1826     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1827     {
1828         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1829         if (is_child)
1830             ShowWindow( hwnd, SW_HIDE );
1831         else
1832             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1833                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1834     }
1835
1836     if (!IsWindow(hwnd)) return TRUE;
1837
1838       /* Recursively destroy owned windows */
1839
1840     if (!is_child)
1841     {
1842         for (;;)
1843         {
1844             int i, got_one = 0;
1845             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1846             if (list)
1847             {
1848                 for (i = 0; list[i]; i++)
1849                 {
1850                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1851                     if (WIN_IsCurrentThread( list[i] ))
1852                     {
1853                         DestroyWindow( list[i] );
1854                         got_one = 1;
1855                         continue;
1856                     }
1857                     WIN_SetOwner( list[i], 0 );
1858                 }
1859                 HeapFree( GetProcessHeap(), 0, list );
1860             }
1861             if (!got_one) break;
1862         }
1863     }
1864
1865       /* Send destroy messages */
1866
1867     WIN_SendDestroyMsg( hwnd );
1868     if (!IsWindow( hwnd )) return TRUE;
1869
1870     if (GetClipboardOwner() == hwnd)
1871         CLIPBOARD_ReleaseOwner();
1872
1873       /* Destroy the window storage */
1874
1875     WIN_DestroyWindow( hwnd );
1876     return TRUE;
1877 }
1878
1879
1880 /***********************************************************************
1881  *              CloseWindow (USER32.@)
1882  */
1883 BOOL WINAPI CloseWindow( HWND hwnd )
1884 {
1885     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1886     ShowWindow( hwnd, SW_MINIMIZE );
1887     return TRUE;
1888 }
1889
1890
1891 /***********************************************************************
1892  *              OpenIcon (USER32.@)
1893  */
1894 BOOL WINAPI OpenIcon( HWND hwnd )
1895 {
1896     if (!IsIconic( hwnd )) return FALSE;
1897     ShowWindow( hwnd, SW_SHOWNORMAL );
1898     return TRUE;
1899 }
1900
1901
1902 /***********************************************************************
1903  *              FindWindowExW (USER32.@)
1904  */
1905 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1906 {
1907     HWND *list = NULL;
1908     HWND retvalue = 0;
1909     int i = 0, len = 0;
1910     WCHAR *buffer = NULL;
1911
1912     if (!parent && child) parent = GetDesktopWindow();
1913     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1914
1915     if (title)
1916     {
1917         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1918         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1919     }
1920
1921     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1922
1923     if (child)
1924     {
1925         child = WIN_GetFullHandle( child );
1926         while (list[i] && list[i] != child) i++;
1927         if (!list[i]) goto done;
1928         i++;  /* start from next window */
1929     }
1930
1931     if (title)
1932     {
1933         while (list[i])
1934         {
1935             if (GetWindowTextW( list[i], buffer, len + 1 ))
1936             {
1937                 if (!strcmpiW( buffer, title )) break;
1938             }
1939             else
1940             {
1941                 if (!title[0]) break;
1942             }
1943             i++;
1944         }
1945     }
1946     retvalue = list[i];
1947
1948  done:
1949     HeapFree( GetProcessHeap(), 0, list );
1950     HeapFree( GetProcessHeap(), 0, buffer );
1951     return retvalue;
1952 }
1953
1954
1955
1956 /***********************************************************************
1957  *              FindWindowA (USER32.@)
1958  */
1959 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1960 {
1961     HWND ret = FindWindowExA( 0, 0, className, title );
1962     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1963     return ret;
1964 }
1965
1966
1967 /***********************************************************************
1968  *              FindWindowExA (USER32.@)
1969  */
1970 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1971 {
1972     LPWSTR titleW = NULL;
1973     HWND hwnd = 0;
1974
1975     if (title)
1976     {
1977         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1978         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1979         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1980     }
1981
1982     if (!IS_INTRESOURCE(className))
1983     {
1984         WCHAR classW[256];
1985         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1986             hwnd = FindWindowExW( parent, child, classW, titleW );
1987     }
1988     else
1989     {
1990         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1991     }
1992
1993     HeapFree( GetProcessHeap(), 0, titleW );
1994     return hwnd;
1995 }
1996
1997
1998 /***********************************************************************
1999  *              FindWindowW (USER32.@)
2000  */
2001 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2002 {
2003     return FindWindowExW( 0, 0, className, title );
2004 }
2005
2006
2007 /**********************************************************************
2008  *              GetDesktopWindow (USER32.@)
2009  */
2010 HWND WINAPI GetDesktopWindow(void)
2011 {
2012     struct user_thread_info *thread_info = get_user_thread_info();
2013
2014     if (thread_info->top_window) return thread_info->top_window;
2015
2016     SERVER_START_REQ( get_desktop_window )
2017     {
2018         req->force = 0;
2019         if (!wine_server_call( req ))
2020         {
2021             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2022             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2023         }
2024     }
2025     SERVER_END_REQ;
2026
2027     if (!thread_info->top_window)
2028     {
2029         USEROBJECTFLAGS flags;
2030         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2031                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2032         {
2033             static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2034             static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2035             STARTUPINFOW si;
2036             PROCESS_INFORMATION pi;
2037             WCHAR windir[MAX_PATH];
2038             WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2039             WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2040             void *redir;
2041
2042             memset( &si, 0, sizeof(si) );
2043             si.cb = sizeof(si);
2044             si.dwFlags = STARTF_USESTDHANDLES;
2045             si.hStdInput  = 0;
2046             si.hStdOutput = 0;
2047             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
2048
2049             GetSystemDirectoryW( windir, MAX_PATH );
2050             strcpyW( app, windir );
2051             strcatW( app, explorer );
2052             strcpyW( cmdline, app );
2053             strcatW( cmdline, args );
2054
2055             Wow64DisableWow64FsRedirection( &redir );
2056             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2057                                 NULL, windir, &si, &pi ))
2058             {
2059                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2060                 WaitForInputIdle( pi.hProcess, 10000 );
2061                 CloseHandle( pi.hThread );
2062                 CloseHandle( pi.hProcess );
2063             }
2064             else WARN( "failed to start explorer, err %d\n", GetLastError() );
2065             Wow64RevertWow64FsRedirection( redir );
2066         }
2067         else TRACE( "not starting explorer since winstation is not visible\n" );
2068
2069         SERVER_START_REQ( get_desktop_window )
2070         {
2071             req->force = 1;
2072             if (!wine_server_call( req ))
2073             {
2074                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2075                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2076             }
2077         }
2078         SERVER_END_REQ;
2079     }
2080
2081     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2082         ERR( "failed to create desktop window\n" );
2083
2084     return thread_info->top_window;
2085 }
2086
2087
2088 /*******************************************************************
2089  *              EnableWindow (USER32.@)
2090  */
2091 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2092 {
2093     BOOL retvalue;
2094     HWND full_handle;
2095
2096     if (is_broadcast(hwnd))
2097     {
2098         SetLastError( ERROR_INVALID_PARAMETER );
2099         return FALSE;
2100     }
2101
2102     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2103         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2104
2105     hwnd = full_handle;
2106
2107     TRACE("( %p, %d )\n", hwnd, enable);
2108
2109     retvalue = !IsWindowEnabled( hwnd );
2110
2111     if (enable && retvalue)
2112     {
2113         WIN_SetStyle( hwnd, 0, WS_DISABLED );
2114         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2115     }
2116     else if (!enable && !retvalue)
2117     {
2118         HWND capture_wnd;
2119
2120         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2121
2122         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2123
2124         if (hwnd == GetFocus())
2125             SetFocus( 0 );  /* A disabled window can't have the focus */
2126
2127         capture_wnd = GetCapture();
2128         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2129             ReleaseCapture();  /* A disabled window can't capture the mouse */
2130
2131         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2132     }
2133     return retvalue;
2134 }
2135
2136
2137 /***********************************************************************
2138  *              IsWindowEnabled (USER32.@)
2139  */
2140 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2141 {
2142     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2143 }
2144
2145
2146 /***********************************************************************
2147  *              IsWindowUnicode (USER32.@)
2148  */
2149 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2150 {
2151     WND * wndPtr;
2152     BOOL retvalue = FALSE;
2153
2154     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2155
2156     if (wndPtr == WND_DESKTOP) return TRUE;
2157
2158     if (wndPtr != WND_OTHER_PROCESS)
2159     {
2160         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2161         WIN_ReleasePtr( wndPtr );
2162     }
2163     else
2164     {
2165         SERVER_START_REQ( get_window_info )
2166         {
2167             req->handle = wine_server_user_handle( hwnd );
2168             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2169         }
2170         SERVER_END_REQ;
2171     }
2172     return retvalue;
2173 }
2174
2175
2176 /**********************************************************************
2177  *           WIN_GetWindowLong
2178  *
2179  * Helper function for GetWindowLong().
2180  */
2181 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2182 {
2183     LONG_PTR retvalue = 0;
2184     WND *wndPtr;
2185
2186     if (offset == GWLP_HWNDPARENT)
2187     {
2188         HWND parent = GetAncestor( hwnd, GA_PARENT );
2189         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2190         return (ULONG_PTR)parent;
2191     }
2192
2193     if (!(wndPtr = WIN_GetPtr( hwnd )))
2194     {
2195         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2196         return 0;
2197     }
2198
2199     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2200     {
2201         if (offset == GWLP_WNDPROC)
2202         {
2203             SetLastError( ERROR_ACCESS_DENIED );
2204             return 0;
2205         }
2206         SERVER_START_REQ( set_window_info )
2207         {
2208             req->handle = wine_server_user_handle( hwnd );
2209             req->flags  = 0;  /* don't set anything, just retrieve */
2210             req->extra_offset = (offset >= 0) ? offset : -1;
2211             req->extra_size = (offset >= 0) ? size : 0;
2212             if (!wine_server_call_err( req ))
2213             {
2214                 switch(offset)
2215                 {
2216                 case GWL_STYLE:      retvalue = reply->old_style; break;
2217                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
2218                 case GWLP_ID:        retvalue = reply->old_id; break;
2219                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2220                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2221                 default:
2222                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2223                     else SetLastError( ERROR_INVALID_INDEX );
2224                     break;
2225                 }
2226             }
2227         }
2228         SERVER_END_REQ;
2229         return retvalue;
2230     }
2231
2232     /* now we have a valid wndPtr */
2233
2234     if (offset >= 0)
2235     {
2236         if (offset > (int)(wndPtr->cbWndExtra - size))
2237         {
2238             WARN("Invalid offset %d\n", offset );
2239             WIN_ReleasePtr( wndPtr );
2240             SetLastError( ERROR_INVALID_INDEX );
2241             return 0;
2242         }
2243         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2244
2245         /* Special case for dialog window procedure */
2246         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2247             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2248         WIN_ReleasePtr( wndPtr );
2249         return retvalue;
2250     }
2251
2252     switch(offset)
2253     {
2254     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2255     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2256     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2257     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2258     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2259     case GWLP_WNDPROC:
2260         /* This looks like a hack only for the edit control (see tests). This makes these controls
2261          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2262          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2263          */
2264         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2265             retvalue = (ULONG_PTR)wndPtr->winproc;
2266         else
2267             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2268         break;
2269     default:
2270         WARN("Unknown offset %d\n", offset );
2271         SetLastError( ERROR_INVALID_INDEX );
2272         break;
2273     }
2274     WIN_ReleasePtr(wndPtr);
2275     return retvalue;
2276 }
2277
2278
2279 /**********************************************************************
2280  *           WIN_SetWindowLong
2281  *
2282  * Helper function for SetWindowLong().
2283  *
2284  * 0 is the failure code. However, in the case of failure SetLastError
2285  * must be set to distinguish between a 0 return value and a failure.
2286  */
2287 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2288 {
2289     STYLESTRUCT style;
2290     BOOL ok, made_visible = FALSE;
2291     LONG_PTR retval = 0;
2292     WND *wndPtr;
2293
2294     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2295
2296     if (is_broadcast(hwnd))
2297     {
2298         SetLastError( ERROR_INVALID_PARAMETER );
2299         return FALSE;
2300     }
2301
2302     if (!(wndPtr = WIN_GetPtr( hwnd )))
2303     {
2304         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2305         return 0;
2306     }
2307     if (wndPtr == WND_DESKTOP)
2308     {
2309         /* can't change anything on the desktop window */
2310         SetLastError( ERROR_ACCESS_DENIED );
2311         return 0;
2312     }
2313     if (wndPtr == WND_OTHER_PROCESS)
2314     {
2315         if (offset == GWLP_WNDPROC)
2316         {
2317             SetLastError( ERROR_ACCESS_DENIED );
2318             return 0;
2319         }
2320         if (offset > 32767 || offset < -32767)
2321         {
2322             SetLastError( ERROR_INVALID_INDEX );
2323             return 0;
2324         }
2325         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2326     }
2327
2328     /* first some special cases */
2329     switch( offset )
2330     {
2331     case GWL_STYLE:
2332         style.styleOld = wndPtr->dwStyle;
2333         style.styleNew = newval;
2334         WIN_ReleasePtr( wndPtr );
2335         SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2336         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2337         newval = style.styleNew;
2338         /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2339         if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2340         /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2341            WS_EX_WINDOWEDGE too */
2342         break;
2343     case GWL_EXSTYLE:
2344         style.styleOld = wndPtr->dwExStyle;
2345         style.styleNew = newval;
2346         WIN_ReleasePtr( wndPtr );
2347         SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2348         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2349         /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2350         newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2351         /* WS_EX_WINDOWEDGE depends on some other styles */
2352         if (newval & WS_EX_DLGMODALFRAME)
2353             newval |= WS_EX_WINDOWEDGE;
2354         else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2355             newval |= WS_EX_WINDOWEDGE;
2356         else
2357             newval &= ~WS_EX_WINDOWEDGE;
2358         break;
2359     case GWLP_HWNDPARENT:
2360         if (wndPtr->parent == GetDesktopWindow())
2361         {
2362             WIN_ReleasePtr( wndPtr );
2363             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2364         }
2365         else
2366         {
2367             WIN_ReleasePtr( wndPtr );
2368             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2369         }
2370     case GWLP_WNDPROC:
2371     {
2372         WNDPROC proc;
2373         UINT old_flags = wndPtr->flags;
2374         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2375         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2376         if (proc) wndPtr->winproc = proc;
2377         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2378         else wndPtr->flags &= ~WIN_ISUNICODE;
2379         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2380         {
2381             WIN_ReleasePtr( wndPtr );
2382             return retval;
2383         }
2384         /* update is_unicode flag on the server side */
2385         break;
2386     }
2387     case GWLP_ID:
2388     case GWLP_HINSTANCE:
2389     case GWLP_USERDATA:
2390         break;
2391     case DWLP_DLGPROC:
2392         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2393             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2394         {
2395             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2396             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2397             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2398             WIN_ReleasePtr( wndPtr );
2399             return retval;
2400         }
2401         /* fall through */
2402     default:
2403         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2404         {
2405             WARN("Invalid offset %d\n", offset );
2406             WIN_ReleasePtr( wndPtr );
2407             SetLastError( ERROR_INVALID_INDEX );
2408             return 0;
2409         }
2410         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2411         {
2412             /* already set to the same value */
2413             WIN_ReleasePtr( wndPtr );
2414             return newval;
2415         }
2416         break;
2417     }
2418
2419     SERVER_START_REQ( set_window_info )
2420     {
2421         req->handle = wine_server_user_handle( hwnd );
2422         req->extra_offset = -1;
2423         switch(offset)
2424         {
2425         case GWL_STYLE:
2426             req->flags = SET_WIN_STYLE;
2427             req->style = newval;
2428             break;
2429         case GWL_EXSTYLE:
2430             req->flags = SET_WIN_EXSTYLE;
2431             req->ex_style = newval;
2432             break;
2433         case GWLP_ID:
2434             req->flags = SET_WIN_ID;
2435             req->id = newval;
2436             break;
2437         case GWLP_HINSTANCE:
2438             req->flags = SET_WIN_INSTANCE;
2439             req->instance = wine_server_client_ptr( (void *)newval );
2440             break;
2441         case GWLP_WNDPROC:
2442             req->flags = SET_WIN_UNICODE;
2443             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2444             break;
2445         case GWLP_USERDATA:
2446             req->flags = SET_WIN_USERDATA;
2447             req->user_data = newval;
2448             break;
2449         default:
2450             req->flags = SET_WIN_EXTRA;
2451             req->extra_offset = offset;
2452             req->extra_size = size;
2453             set_win_data( &req->extra_value, newval, size );
2454         }
2455         if ((ok = !wine_server_call_err( req )))
2456         {
2457             switch(offset)
2458             {
2459             case GWL_STYLE:
2460                 wndPtr->dwStyle = newval;
2461                 retval = reply->old_style;
2462                 break;
2463             case GWL_EXSTYLE:
2464                 wndPtr->dwExStyle = newval;
2465                 retval = reply->old_ex_style;
2466                 break;
2467             case GWLP_ID:
2468                 wndPtr->wIDmenu = newval;
2469                 retval = reply->old_id;
2470                 break;
2471             case GWLP_HINSTANCE:
2472                 wndPtr->hInstance = (HINSTANCE)newval;
2473                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2474                 break;
2475             case GWLP_WNDPROC:
2476                 break;
2477             case GWLP_USERDATA:
2478                 wndPtr->userdata = newval;
2479                 retval = reply->old_user_data;
2480                 break;
2481             default:
2482                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2483                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2484                 break;
2485             }
2486         }
2487     }
2488     SERVER_END_REQ;
2489
2490     if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2491         (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2492     {
2493         made_visible = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2494         invalidate_dce( wndPtr, NULL );
2495     }
2496     WIN_ReleasePtr( wndPtr );
2497
2498     if (!ok) return 0;
2499
2500     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2501     {
2502         style.styleOld = retval;
2503         style.styleNew = newval;
2504         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2505         if (made_visible) update_window_state( hwnd );
2506         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2507     }
2508
2509     return retval;
2510 }
2511
2512
2513 /**********************************************************************
2514  *              GetWindowWord (USER32.@)
2515  */
2516 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2517 {
2518     switch(offset)
2519     {
2520     case GWLP_ID:
2521     case GWLP_HINSTANCE:
2522     case GWLP_HWNDPARENT:
2523         break;
2524     default:
2525         if (offset < 0)
2526         {
2527             WARN("Invalid offset %d\n", offset );
2528             SetLastError( ERROR_INVALID_INDEX );
2529             return 0;
2530         }
2531         break;
2532     }
2533     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2534 }
2535
2536
2537 /**********************************************************************
2538  *              GetWindowLongA (USER32.@)
2539  */
2540 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2541 {
2542     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2543 }
2544
2545
2546 /**********************************************************************
2547  *              GetWindowLongW (USER32.@)
2548  */
2549 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2550 {
2551     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2552 }
2553
2554
2555 /**********************************************************************
2556  *              SetWindowWord (USER32.@)
2557  */
2558 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2559 {
2560     switch(offset)
2561     {
2562     case GWLP_ID:
2563     case GWLP_HINSTANCE:
2564     case GWLP_HWNDPARENT:
2565         break;
2566     default:
2567         if (offset < 0)
2568         {
2569             WARN("Invalid offset %d\n", offset );
2570             SetLastError( ERROR_INVALID_INDEX );
2571             return 0;
2572         }
2573         break;
2574     }
2575     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2576 }
2577
2578
2579 /**********************************************************************
2580  *              SetWindowLongA (USER32.@)
2581  *
2582  * See SetWindowLongW.
2583  */
2584 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2585 {
2586     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2587 }
2588
2589
2590 /**********************************************************************
2591  *              SetWindowLongW (USER32.@) Set window attribute
2592  *
2593  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2594  * value in a window's extra memory.
2595  *
2596  * The _hwnd_ parameter specifies the window.  is the handle to a
2597  * window that has extra memory. The _newval_ parameter contains the
2598  * new attribute or extra memory value.  If positive, the _offset_
2599  * parameter is the byte-addressed location in the window's extra
2600  * memory to set.  If negative, _offset_ specifies the window
2601  * attribute to set, and should be one of the following values:
2602  *
2603  * GWL_EXSTYLE      The window's extended window style
2604  *
2605  * GWL_STYLE        The window's window style.
2606  *
2607  * GWLP_WNDPROC     Pointer to the window's window procedure.
2608  *
2609  * GWLP_HINSTANCE   The window's pplication instance handle.
2610  *
2611  * GWLP_ID          The window's identifier.
2612  *
2613  * GWLP_USERDATA    The window's user-specified data.
2614  *
2615  * If the window is a dialog box, the _offset_ parameter can be one of
2616  * the following values:
2617  *
2618  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2619  *
2620  * DWLP_MSGRESULT   The return value of a message
2621  *                  that the dialog box procedure processed.
2622  *
2623  * DWLP_USER        Application specific information.
2624  *
2625  * RETURNS
2626  *
2627  * If successful, returns the previous value located at _offset_. Otherwise,
2628  * returns 0.
2629  *
2630  * NOTES
2631  *
2632  * Extra memory for a window class is specified by a nonzero cbWndExtra
2633  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2634  * time of class creation.
2635  *
2636  * Using GWL_WNDPROC to set a new window procedure effectively creates
2637  * a window subclass. Use CallWindowProc() in the new windows procedure
2638  * to pass messages to the superclass's window procedure.
2639  *
2640  * The user data is reserved for use by the application which created
2641  * the window.
2642  *
2643  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2644  * instead, call the EnableWindow() function to change the window's
2645  * disabled state.
2646  *
2647  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2648  * SetParent() instead.
2649  *
2650  * Win95:
2651  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2652  * it sends WM_STYLECHANGING before changing the settings
2653  * and WM_STYLECHANGED afterwards.
2654  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2655  */
2656 LONG WINAPI SetWindowLongW(
2657     HWND hwnd,  /* [in] window to alter */
2658     INT offset, /* [in] offset, in bytes, of location to alter */
2659     LONG newval /* [in] new value of location */
2660 ) {
2661     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2662 }
2663
2664
2665 /*******************************************************************
2666  *              GetWindowTextA (USER32.@)
2667  */
2668 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2669 {
2670     WCHAR *buffer;
2671
2672     if (!lpString) return 0;
2673
2674     if (WIN_IsCurrentProcess( hwnd ))
2675         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2676
2677     /* when window belongs to other process, don't send a message */
2678     if (nMaxCount <= 0) return 0;
2679     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2680     get_server_window_text( hwnd, buffer, nMaxCount );
2681     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2682         lpString[nMaxCount-1] = 0;
2683     HeapFree( GetProcessHeap(), 0, buffer );
2684     return strlen(lpString);
2685 }
2686
2687
2688 /*******************************************************************
2689  *              InternalGetWindowText (USER32.@)
2690  */
2691 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2692 {
2693     WND *win;
2694
2695     if (nMaxCount <= 0) return 0;
2696     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2697     if (win == WND_DESKTOP) lpString[0] = 0;
2698     else if (win != WND_OTHER_PROCESS)
2699     {
2700         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2701         else lpString[0] = 0;
2702         WIN_ReleasePtr( win );
2703     }
2704     else
2705     {
2706         get_server_window_text( hwnd, lpString, nMaxCount );
2707     }
2708     return strlenW(lpString);
2709 }
2710
2711
2712 /*******************************************************************
2713  *              GetWindowTextW (USER32.@)
2714  */
2715 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2716 {
2717     if (!lpString) return 0;
2718
2719     if (WIN_IsCurrentProcess( hwnd ))
2720         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2721
2722     /* when window belongs to other process, don't send a message */
2723     if (nMaxCount <= 0) return 0;
2724     get_server_window_text( hwnd, lpString, nMaxCount );
2725     return strlenW(lpString);
2726 }
2727
2728
2729 /*******************************************************************
2730  *              SetWindowTextA (USER32.@)
2731  *              SetWindowText  (USER32.@)
2732  */
2733 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2734 {
2735     if (is_broadcast(hwnd))
2736     {
2737         SetLastError( ERROR_INVALID_PARAMETER );
2738         return FALSE;
2739     }
2740     if (!WIN_IsCurrentProcess( hwnd ))
2741         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2742                debugstr_a(lpString), hwnd );
2743     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2744 }
2745
2746
2747 /*******************************************************************
2748  *              SetWindowTextW (USER32.@)
2749  */
2750 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2751 {
2752     if (is_broadcast(hwnd))
2753     {
2754         SetLastError( ERROR_INVALID_PARAMETER );
2755         return FALSE;
2756     }
2757     if (!WIN_IsCurrentProcess( hwnd ))
2758         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2759                debugstr_w(lpString), hwnd );
2760     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2761 }
2762
2763
2764 /*******************************************************************
2765  *              GetWindowTextLengthA (USER32.@)
2766  */
2767 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2768 {
2769     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2770 }
2771
2772 /*******************************************************************
2773  *              GetWindowTextLengthW (USER32.@)
2774  */
2775 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2776 {
2777     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2778 }
2779
2780
2781 /*******************************************************************
2782  *              IsWindow (USER32.@)
2783  */
2784 BOOL WINAPI IsWindow( HWND hwnd )
2785 {
2786     WND *ptr;
2787     BOOL ret;
2788
2789     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2790     if (ptr == WND_DESKTOP) return TRUE;
2791
2792     if (ptr != WND_OTHER_PROCESS)
2793     {
2794         WIN_ReleasePtr( ptr );
2795         return TRUE;
2796     }
2797
2798     /* check other processes */
2799     SERVER_START_REQ( get_window_info )
2800     {
2801         req->handle = wine_server_user_handle( hwnd );
2802         ret = !wine_server_call_err( req );
2803     }
2804     SERVER_END_REQ;
2805     return ret;
2806 }
2807
2808
2809 /***********************************************************************
2810  *              GetWindowThreadProcessId (USER32.@)
2811  */
2812 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2813 {
2814     WND *ptr;
2815     DWORD tid = 0;
2816
2817     if (!(ptr = WIN_GetPtr( hwnd )))
2818     {
2819         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2820         return 0;
2821     }
2822
2823     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2824     {
2825         /* got a valid window */
2826         tid = ptr->tid;
2827         if (process) *process = GetCurrentProcessId();
2828         WIN_ReleasePtr( ptr );
2829         return tid;
2830     }
2831
2832     /* check other processes */
2833     SERVER_START_REQ( get_window_info )
2834     {
2835         req->handle = wine_server_user_handle( hwnd );
2836         if (!wine_server_call_err( req ))
2837         {
2838             tid = (DWORD)reply->tid;
2839             if (process) *process = (DWORD)reply->pid;
2840         }
2841     }
2842     SERVER_END_REQ;
2843     return tid;
2844 }
2845
2846
2847 /*****************************************************************
2848  *              GetParent (USER32.@)
2849  */
2850 HWND WINAPI GetParent( HWND hwnd )
2851 {
2852     WND *wndPtr;
2853     HWND retvalue = 0;
2854
2855     if (!(wndPtr = WIN_GetPtr( hwnd )))
2856     {
2857         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2858         return 0;
2859     }
2860     if (wndPtr == WND_DESKTOP) return 0;
2861     if (wndPtr == WND_OTHER_PROCESS)
2862     {
2863         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2864         if (style & (WS_POPUP | WS_CHILD))
2865         {
2866             SERVER_START_REQ( get_window_tree )
2867             {
2868                 req->handle = wine_server_user_handle( hwnd );
2869                 if (!wine_server_call_err( req ))
2870                 {
2871                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2872                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2873                 }
2874             }
2875             SERVER_END_REQ;
2876         }
2877     }
2878     else
2879     {
2880         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2881         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2882         WIN_ReleasePtr( wndPtr );
2883     }
2884     return retvalue;
2885 }
2886
2887
2888 /*****************************************************************
2889  *              GetAncestor (USER32.@)
2890  */
2891 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2892 {
2893     WND *win;
2894     HWND *list, ret = 0;
2895
2896     switch(type)
2897     {
2898     case GA_PARENT:
2899         if (!(win = WIN_GetPtr( hwnd )))
2900         {
2901             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2902             return 0;
2903         }
2904         if (win == WND_DESKTOP) return 0;
2905         if (win != WND_OTHER_PROCESS)
2906         {
2907             ret = win->parent;
2908             WIN_ReleasePtr( win );
2909         }
2910         else /* need to query the server */
2911         {
2912             SERVER_START_REQ( get_window_tree )
2913             {
2914                 req->handle = wine_server_user_handle( hwnd );
2915                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2916             }
2917             SERVER_END_REQ;
2918         }
2919         break;
2920
2921     case GA_ROOT:
2922         if (!(list = list_window_parents( hwnd ))) return 0;
2923
2924         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2925         else
2926         {
2927             int count = 2;
2928             while (list[count]) count++;
2929             ret = list[count - 2];  /* get the one before the desktop */
2930         }
2931         HeapFree( GetProcessHeap(), 0, list );
2932         break;
2933
2934     case GA_ROOTOWNER:
2935         if (is_desktop_window( hwnd )) return 0;
2936         ret = WIN_GetFullHandle( hwnd );
2937         for (;;)
2938         {
2939             HWND parent = GetParent( ret );
2940             if (!parent) break;
2941             ret = parent;
2942         }
2943         break;
2944     }
2945     return ret;
2946 }
2947
2948
2949 /*****************************************************************
2950  *              SetParent (USER32.@)
2951  */
2952 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2953 {
2954     HWND full_handle;
2955     HWND old_parent = 0;
2956     BOOL was_visible;
2957     WND *wndPtr;
2958     POINT pt;
2959     BOOL ret;
2960
2961     if (is_broadcast(hwnd) || is_broadcast(parent))
2962     {
2963         SetLastError(ERROR_INVALID_PARAMETER);
2964         return 0;
2965     }
2966
2967     if (!parent) parent = GetDesktopWindow();
2968     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2969     else parent = WIN_GetFullHandle( parent );
2970
2971     if (!IsWindow( parent ))
2972     {
2973         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2974         return 0;
2975     }
2976
2977     /* Some applications try to set a child as a parent */
2978     if (IsChild(hwnd, parent))
2979     {
2980         SetLastError( ERROR_INVALID_PARAMETER );
2981         return 0;
2982     }
2983
2984     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2985         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2986
2987     if (full_handle == parent)
2988     {
2989         SetLastError( ERROR_INVALID_PARAMETER );
2990         return 0;
2991     }
2992
2993     /* Windows hides the window first, then shows it again
2994      * including the WM_SHOWWINDOW messages and all */
2995     was_visible = ShowWindow( hwnd, SW_HIDE );
2996
2997     wndPtr = WIN_GetPtr( hwnd );
2998     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2999
3000     pt.x = wndPtr->rectWindow.left;
3001     pt.y = wndPtr->rectWindow.top;
3002
3003     SERVER_START_REQ( set_parent )
3004     {
3005         req->handle = wine_server_user_handle( hwnd );
3006         req->parent = wine_server_user_handle( parent );
3007         if ((ret = !wine_server_call( req )))
3008         {
3009             old_parent = wine_server_ptr_handle( reply->old_parent );
3010             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3011         }
3012
3013     }
3014     SERVER_END_REQ;
3015     WIN_ReleasePtr( wndPtr );
3016     if (!ret) return 0;
3017
3018     USER_Driver->pSetParent( full_handle, parent, old_parent );
3019
3020     /* SetParent additionally needs to make hwnd the topmost window
3021        in the x-order and send the expected WM_WINDOWPOSCHANGING and
3022        WM_WINDOWPOSCHANGED notification messages.
3023     */
3024     SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3025
3026     if (was_visible) ShowWindow( hwnd, SW_SHOW );
3027
3028     return old_parent;
3029 }
3030
3031
3032 /*******************************************************************
3033  *              IsChild (USER32.@)
3034  */
3035 BOOL WINAPI IsChild( HWND parent, HWND child )
3036 {
3037     HWND *list = list_window_parents( child );
3038     int i;
3039     BOOL ret;
3040
3041     if (!list) return FALSE;
3042     parent = WIN_GetFullHandle( parent );
3043     for (i = 0; list[i]; i++) if (list[i] == parent) break;
3044     ret = list[i] && list[i+1];
3045     HeapFree( GetProcessHeap(), 0, list );
3046     return ret;
3047 }
3048
3049
3050 /***********************************************************************
3051  *              IsWindowVisible (USER32.@)
3052  */
3053 BOOL WINAPI IsWindowVisible( HWND hwnd )
3054 {
3055     HWND *list;
3056     BOOL retval = TRUE;
3057     int i;
3058
3059     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3060     if (!(list = list_window_parents( hwnd ))) return TRUE;
3061     if (list[0])
3062     {
3063         for (i = 0; list[i+1]; i++)
3064             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3065         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3066     }
3067     HeapFree( GetProcessHeap(), 0, list );
3068     return retval;
3069 }
3070
3071
3072 /***********************************************************************
3073  *           WIN_IsWindowDrawable
3074  *
3075  * hwnd is drawable when it is visible, all parents are not
3076  * minimized, and it is itself not minimized unless we are
3077  * trying to draw its default class icon.
3078  */
3079 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3080 {
3081     HWND *list;
3082     BOOL retval = TRUE;
3083     int i;
3084     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3085
3086     if (!(style & WS_VISIBLE)) return FALSE;
3087     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
3088
3089     if (!(list = list_window_parents( hwnd ))) return TRUE;
3090     if (list[0])
3091     {
3092         for (i = 0; list[i+1]; i++)
3093             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3094                 break;
3095         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3096     }
3097     HeapFree( GetProcessHeap(), 0, list );
3098     return retval;
3099 }
3100
3101
3102 /*******************************************************************
3103  *              GetTopWindow (USER32.@)
3104  */
3105 HWND WINAPI GetTopWindow( HWND hwnd )
3106 {
3107     if (!hwnd) hwnd = GetDesktopWindow();
3108     return GetWindow( hwnd, GW_CHILD );
3109 }
3110
3111
3112 /*******************************************************************
3113  *              GetWindow (USER32.@)
3114  */
3115 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3116 {
3117     HWND retval = 0;
3118
3119     if (rel == GW_OWNER)  /* this one may be available locally */
3120     {
3121         WND *wndPtr = WIN_GetPtr( hwnd );
3122         if (!wndPtr)
3123         {
3124             SetLastError( ERROR_INVALID_HANDLE );
3125             return 0;
3126         }
3127         if (wndPtr == WND_DESKTOP) return 0;
3128         if (wndPtr != WND_OTHER_PROCESS)
3129         {
3130             retval = wndPtr->owner;
3131             WIN_ReleasePtr( wndPtr );
3132             return retval;
3133         }
3134         /* else fall through to server call */
3135     }
3136
3137     SERVER_START_REQ( get_window_tree )
3138     {
3139         req->handle = wine_server_user_handle( hwnd );
3140         if (!wine_server_call_err( req ))
3141         {
3142             switch(rel)
3143             {
3144             case GW_HWNDFIRST:
3145                 retval = wine_server_ptr_handle( reply->first_sibling );
3146                 break;
3147             case GW_HWNDLAST:
3148                 retval = wine_server_ptr_handle( reply->last_sibling );
3149                 break;
3150             case GW_HWNDNEXT:
3151                 retval = wine_server_ptr_handle( reply->next_sibling );
3152                 break;
3153             case GW_HWNDPREV:
3154                 retval = wine_server_ptr_handle( reply->prev_sibling );
3155                 break;
3156             case GW_OWNER:
3157                 retval = wine_server_ptr_handle( reply->owner );
3158                 break;
3159             case GW_CHILD:
3160                 retval = wine_server_ptr_handle( reply->first_child );
3161                 break;
3162             }
3163         }
3164     }
3165     SERVER_END_REQ;
3166     return retval;
3167 }
3168
3169
3170 /*******************************************************************
3171  *              ShowOwnedPopups (USER32.@)
3172  */
3173 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3174 {
3175     int count = 0;
3176     WND *pWnd;
3177     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3178
3179     if (!win_array) return TRUE;
3180
3181     while (win_array[count]) count++;
3182     while (--count >= 0)
3183     {
3184         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3185         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3186         if (pWnd == WND_OTHER_PROCESS) continue;
3187         if (fShow)
3188         {
3189             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3190             {
3191                 WIN_ReleasePtr( pWnd );
3192                 /* In Windows, ShowOwnedPopups(TRUE) generates
3193                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3194                  * regardless of the state of the owner
3195                  */
3196                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3197                 continue;
3198             }
3199         }
3200         else
3201         {
3202             if (pWnd->dwStyle & WS_VISIBLE)
3203             {
3204                 WIN_ReleasePtr( pWnd );
3205                 /* In Windows, ShowOwnedPopups(FALSE) generates
3206                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3207                  * regardless of the state of the owner
3208                  */
3209                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3210                 continue;
3211             }
3212         }
3213         WIN_ReleasePtr( pWnd );
3214     }
3215     HeapFree( GetProcessHeap(), 0, win_array );
3216     return TRUE;
3217 }
3218
3219
3220 /*******************************************************************
3221  *              GetLastActivePopup (USER32.@)
3222  */
3223 HWND WINAPI GetLastActivePopup( HWND hwnd )
3224 {
3225     HWND retval = hwnd;
3226
3227     SERVER_START_REQ( get_window_info )
3228     {
3229         req->handle = wine_server_user_handle( hwnd );
3230         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3231     }
3232     SERVER_END_REQ;
3233     return retval;
3234 }
3235
3236
3237 /*******************************************************************
3238  *           WIN_ListChildren
3239  *
3240  * Build an array of the children of a given window. The array must be
3241  * freed with HeapFree. Returns NULL when no windows are found.
3242  */
3243 HWND *WIN_ListChildren( HWND hwnd )
3244 {
3245     if (!hwnd)
3246     {
3247         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3248         return NULL;
3249     }
3250     return list_window_children( 0, hwnd, NULL, 0 );
3251 }
3252
3253
3254 /*******************************************************************
3255  *              EnumWindows (USER32.@)
3256  */
3257 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3258 {
3259     HWND *list;
3260     BOOL ret = TRUE;
3261     int i;
3262
3263     USER_CheckNotLock();
3264
3265     /* We have to build a list of all windows first, to avoid */
3266     /* unpleasant side-effects, for instance if the callback */
3267     /* function changes the Z-order of the windows.          */
3268
3269     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3270
3271     /* Now call the callback function for every window */
3272
3273     for (i = 0; list[i]; i++)
3274     {
3275         /* Make sure that the window still exists */
3276         if (!IsWindow( list[i] )) continue;
3277         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3278     }
3279     HeapFree( GetProcessHeap(), 0, list );
3280     return ret;
3281 }
3282
3283
3284 /**********************************************************************
3285  *              EnumThreadWindows (USER32.@)
3286  */
3287 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3288 {
3289     HWND *list;
3290     int i;
3291     BOOL ret = TRUE;
3292
3293     USER_CheckNotLock();
3294
3295     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3296
3297     /* Now call the callback function for every window */
3298
3299     for (i = 0; list[i]; i++)
3300         if (!(ret = func( list[i], lParam ))) break;
3301     HeapFree( GetProcessHeap(), 0, list );
3302     return ret;
3303 }
3304
3305
3306 /***********************************************************************
3307  *              EnumDesktopWindows   (USER32.@)
3308  */
3309 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3310 {
3311     HWND *list;
3312     int i;
3313
3314     USER_CheckNotLock();
3315
3316     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3317
3318     for (i = 0; list[i]; i++)
3319         if (!func( list[i], lparam )) break;
3320     HeapFree( GetProcessHeap(), 0, list );
3321     return TRUE;
3322 }
3323
3324
3325 /**********************************************************************
3326  *           WIN_EnumChildWindows
3327  *
3328  * Helper function for EnumChildWindows().
3329  */
3330 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3331 {
3332     HWND *childList;
3333     BOOL ret = FALSE;
3334
3335     for ( ; *list; list++)
3336     {
3337         /* Make sure that the window still exists */
3338         if (!IsWindow( *list )) continue;
3339         /* Build children list first */
3340         childList = WIN_ListChildren( *list );
3341
3342         ret = func( *list, lParam );
3343
3344         if (childList)
3345         {
3346             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3347             HeapFree( GetProcessHeap(), 0, childList );
3348         }
3349         if (!ret) return FALSE;
3350     }
3351     return TRUE;
3352 }
3353
3354
3355 /**********************************************************************
3356  *              EnumChildWindows (USER32.@)
3357  */
3358 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3359 {
3360     HWND *list;
3361     BOOL ret;
3362
3363     USER_CheckNotLock();
3364
3365     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3366     ret = WIN_EnumChildWindows( list, func, lParam );
3367     HeapFree( GetProcessHeap(), 0, list );
3368     return ret;
3369 }
3370
3371
3372 /*******************************************************************
3373  *              AnyPopup (USER32.@)
3374  */
3375 BOOL WINAPI AnyPopup(void)
3376 {
3377     int i;
3378     BOOL retvalue;
3379     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3380
3381     if (!list) return FALSE;
3382     for (i = 0; list[i]; i++)
3383     {
3384         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3385     }
3386     retvalue = (list[i] != 0);
3387     HeapFree( GetProcessHeap(), 0, list );
3388     return retvalue;
3389 }
3390
3391
3392 /*******************************************************************
3393  *              FlashWindow (USER32.@)
3394  */
3395 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3396 {
3397     WND *wndPtr;
3398
3399     TRACE("%p\n", hWnd);
3400
3401     if (IsIconic( hWnd ))
3402     {
3403         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3404
3405         wndPtr = WIN_GetPtr(hWnd);
3406         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3407         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3408         {
3409             wndPtr->flags |= WIN_NCACTIVATED;
3410         }
3411         else
3412         {
3413             wndPtr->flags &= ~WIN_NCACTIVATED;
3414         }
3415         WIN_ReleasePtr( wndPtr );
3416         return TRUE;
3417     }
3418     else
3419     {
3420         WPARAM wparam;
3421
3422         wndPtr = WIN_GetPtr(hWnd);
3423         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3424         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3425
3426         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3427         else wparam = (hWnd == GetForegroundWindow());
3428
3429         WIN_ReleasePtr( wndPtr );
3430         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3431         return wparam;
3432     }
3433 }
3434
3435 /*******************************************************************
3436  *              FlashWindowEx (USER32.@)
3437  */
3438 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3439 {
3440     FIXME("%p\n", pfwi);
3441     return TRUE;
3442 }
3443
3444 /*******************************************************************
3445  *              GetWindowContextHelpId (USER32.@)
3446  */
3447 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3448 {
3449     DWORD retval;
3450     WND *wnd = WIN_GetPtr( hwnd );
3451     if (!wnd || wnd == WND_DESKTOP) return 0;
3452     if (wnd == WND_OTHER_PROCESS)
3453     {
3454         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3455         return 0;
3456     }
3457     retval = wnd->helpContext;
3458     WIN_ReleasePtr( wnd );
3459     return retval;
3460 }
3461
3462
3463 /*******************************************************************
3464  *              SetWindowContextHelpId (USER32.@)
3465  */
3466 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3467 {
3468     WND *wnd = WIN_GetPtr( hwnd );
3469     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3470     if (wnd == WND_OTHER_PROCESS)
3471     {
3472         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3473         return 0;
3474     }
3475     wnd->helpContext = id;
3476     WIN_ReleasePtr( wnd );
3477     return TRUE;
3478 }
3479
3480
3481 /*******************************************************************
3482  *              DragDetect (USER32.@)
3483  */
3484 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3485 {
3486     MSG msg;
3487     RECT rect;
3488     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3489     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3490
3491     rect.left = pt.x - wDragWidth;
3492     rect.right = pt.x + wDragWidth;
3493
3494     rect.top = pt.y - wDragHeight;
3495     rect.bottom = pt.y + wDragHeight;
3496
3497     SetCapture(hWnd);
3498
3499     while(1)
3500     {
3501         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3502         {
3503             if( msg.message == WM_LBUTTONUP )
3504             {
3505                 ReleaseCapture();
3506                 return 0;
3507             }
3508             if( msg.message == WM_MOUSEMOVE )
3509             {
3510                 POINT tmp;
3511                 tmp.x = (short)LOWORD(msg.lParam);
3512                 tmp.y = (short)HIWORD(msg.lParam);
3513                 if( !PtInRect( &rect, tmp ))
3514                 {
3515                     ReleaseCapture();
3516                     return 1;
3517                 }
3518             }
3519         }
3520         WaitMessage();
3521     }
3522     return 0;
3523 }
3524
3525 /******************************************************************************
3526  *              GetWindowModuleFileNameA (USER32.@)
3527  */
3528 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3529 {
3530     WND *win;
3531     HINSTANCE hinst;
3532
3533     TRACE( "%p, %p, %u\n", hwnd, module, size );
3534
3535     win = WIN_GetPtr( hwnd );
3536     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3537     {
3538         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3539         return 0;
3540     }
3541     hinst = win->hInstance;
3542     WIN_ReleasePtr( win );
3543
3544     return GetModuleFileNameA( hinst, module, size );
3545 }
3546
3547 /******************************************************************************
3548  *              GetWindowModuleFileNameW (USER32.@)
3549  */
3550 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3551 {
3552     WND *win;
3553     HINSTANCE hinst;
3554
3555     TRACE( "%p, %p, %u\n", hwnd, module, size );
3556
3557     win = WIN_GetPtr( hwnd );
3558     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3559     {
3560         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3561         return 0;
3562     }
3563     hinst = win->hInstance;
3564     WIN_ReleasePtr( win );
3565
3566     return GetModuleFileNameW( hinst, module, size );
3567 }
3568
3569 /******************************************************************************
3570  *              GetWindowInfo (USER32.@)
3571  *
3572  * Note: tests show that Windows doesn't check cbSize of the structure.
3573  */
3574 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3575 {
3576     if (!pwi) return FALSE;
3577     if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3578
3579     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3580     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3581     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3582
3583     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3584     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3585
3586     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3587     pwi->wCreatorVersion = 0x0400;
3588
3589     return TRUE;
3590 }
3591
3592 /******************************************************************************
3593  *              SwitchDesktop (USER32.@)
3594  *
3595  * NOTES: Sets the current input or interactive desktop.
3596  */
3597 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3598 {
3599     FIXME("(hwnd %p) stub!\n", hDesktop);
3600     return TRUE;
3601 }
3602
3603
3604 /***********************************************************************
3605  *           __wine_set_pixel_format
3606  */
3607 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3608 {
3609     WND *win = WIN_GetPtr( hwnd );
3610
3611     if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3612     {
3613         WARN( "setting format %d on win %p not supported\n", format, hwnd );
3614         return FALSE;
3615     }
3616     win->pixel_format = format;
3617     WIN_ReleasePtr( win );
3618
3619     update_window_state( hwnd );
3620     return TRUE;
3621 }
3622
3623
3624 /*****************************************************************************
3625  *              SetLayeredWindowAttributes (USER32.@)
3626  */
3627 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3628 {
3629     BOOL ret;
3630
3631     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3632
3633     SERVER_START_REQ( set_window_layered_info )
3634     {
3635         req->handle = wine_server_user_handle( hwnd );
3636         req->color_key = key;
3637         req->alpha = alpha;
3638         req->flags = flags;
3639         ret = !wine_server_call_err( req );
3640     }
3641     SERVER_END_REQ;
3642
3643     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3644
3645     return ret;
3646 }
3647
3648
3649 /*****************************************************************************
3650  *              GetLayeredWindowAttributes (USER32.@)
3651  */
3652 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3653 {
3654     BOOL ret;
3655
3656     SERVER_START_REQ( get_window_layered_info )
3657     {
3658         req->handle = wine_server_user_handle( hwnd );
3659         if ((ret = !wine_server_call_err( req )))
3660         {
3661             if (key) *key = reply->color_key;
3662             if (alpha) *alpha = reply->alpha;
3663             if (flags) *flags = reply->flags;
3664         }
3665     }
3666     SERVER_END_REQ;
3667
3668     return ret;
3669 }
3670
3671
3672 /*****************************************************************************
3673  *              UpdateLayeredWindowIndirect  (USER32.@)
3674  */
3675 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3676 {
3677     DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3678     RECT window_rect, client_rect;
3679     SIZE offset;
3680
3681     if (!info ||
3682         info->cbSize != sizeof(*info) ||
3683         info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3684         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3685         GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3686     {
3687         SetLastError( ERROR_INVALID_PARAMETER );
3688         return FALSE;
3689     }
3690
3691     WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3692
3693     if (info->pptDst)
3694     {
3695         offset.cx = info->pptDst->x - window_rect.left;
3696         offset.cy = info->pptDst->y - window_rect.top;
3697         OffsetRect( &client_rect, offset.cx, offset.cy );
3698         OffsetRect( &window_rect, offset.cx, offset.cy );
3699         flags &= ~SWP_NOMOVE;
3700     }
3701     if (info->psize)
3702     {
3703         offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3704         offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3705         if (info->psize->cx <= 0 || info->psize->cy <= 0)
3706         {
3707             SetLastError( ERROR_INVALID_PARAMETER );
3708             return FALSE;
3709         }
3710         if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3711         {
3712             SetLastError( ERROR_INCORRECT_SIZE );
3713             return FALSE;
3714         }
3715         client_rect.right  += offset.cx;
3716         client_rect.bottom += offset.cy;
3717         window_rect.right  += offset.cx;
3718         window_rect.bottom += offset.cy;
3719         flags &= ~SWP_NOSIZE;
3720     }
3721
3722     TRACE( "window %p win %s client %s\n", hwnd,
3723            wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3724
3725     if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3726
3727     set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3728     return TRUE;
3729 }
3730
3731
3732 /*****************************************************************************
3733  *              UpdateLayeredWindow (USER32.@)
3734  */
3735 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3736                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3737                                  DWORD flags)
3738 {
3739     UPDATELAYEREDWINDOWINFO info;
3740
3741     if (flags & ULW_EX_NORESIZE)  /* only valid for UpdateLayeredWindowIndirect */
3742     {
3743         SetLastError( ERROR_INVALID_PARAMETER );
3744         return FALSE;
3745     }
3746     info.cbSize   = sizeof(info);
3747     info.hdcDst   = hdcDst;
3748     info.pptDst   = pptDst;
3749     info.psize    = psize;
3750     info.hdcSrc   = hdcSrc;
3751     info.pptSrc   = pptSrc;
3752     info.crKey    = crKey;
3753     info.pblend   = pblend;
3754     info.dwFlags  = flags;
3755     info.prcDirty = NULL;
3756     return UpdateLayeredWindowIndirect( hwnd, &info );
3757 }
3758
3759
3760 /******************************************************************************
3761  *                    GetProcessDefaultLayout [USER32.@]
3762  *
3763  * Gets the default layout for parentless windows.
3764  */
3765 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3766 {
3767     if (!layout)
3768     {
3769         SetLastError( ERROR_NOACCESS );
3770         return FALSE;
3771     }
3772     if (process_layout == ~0u)
3773     {
3774         static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3775                                               '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3776         static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3777                                            '\\','%','0','4','x','%','0','4','x',
3778                                            '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3779         WCHAR *str, buffer[MAX_PATH];
3780         DWORD i, len, version_layout = 0;
3781         DWORD user_lang = GetUserDefaultLangID();
3782         DWORD *languages;
3783         void *data = NULL;
3784
3785         GetModuleFileNameW( 0, buffer, MAX_PATH );
3786         if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3787         if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3788         if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3789         if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3790
3791         len /= sizeof(DWORD);
3792         for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3793         if (i == len)  /* try neutral language */
3794             for (i = 0; i < len; i++)
3795                 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3796         if (i == len) i = 0;  /* default to the first one */
3797
3798         sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3799         if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3800         TRACE( "found description %s\n", debugstr_w( str ));
3801         if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3802
3803     done:
3804         HeapFree( GetProcessHeap(), 0, data );
3805         process_layout = version_layout;
3806     }
3807     *layout = process_layout;
3808     return TRUE;
3809 }
3810
3811
3812 /******************************************************************************
3813  *                    SetProcessDefaultLayout [USER32.@]
3814  *
3815  * Sets the default layout for parentless windows.
3816  */
3817 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3818 {
3819     process_layout = layout;
3820     return TRUE;
3821 }
3822
3823
3824 /* 64bit versions */
3825
3826 #ifdef GetWindowLongPtrW
3827 #undef GetWindowLongPtrW
3828 #endif
3829
3830 #ifdef GetWindowLongPtrA
3831 #undef GetWindowLongPtrA
3832 #endif
3833
3834 #ifdef SetWindowLongPtrW
3835 #undef SetWindowLongPtrW
3836 #endif
3837
3838 #ifdef SetWindowLongPtrA
3839 #undef SetWindowLongPtrA
3840 #endif
3841
3842 /*****************************************************************************
3843  *              GetWindowLongPtrW (USER32.@)
3844  */
3845 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3846 {
3847     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3848 }
3849
3850 /*****************************************************************************
3851  *              GetWindowLongPtrA (USER32.@)
3852  */
3853 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3854 {
3855     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3856 }
3857
3858 /*****************************************************************************
3859  *              SetWindowLongPtrW (USER32.@)
3860  */
3861 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3862 {
3863     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3864 }
3865
3866 /*****************************************************************************
3867  *              SetWindowLongPtrA (USER32.@)
3868  */
3869 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3870 {
3871     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3872 }