wbemprox: Support overriding the CIM to VARIANT type mapping for method parameters.
[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
1471     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1472
1473     /*
1474      * Correct the window styles.
1475      *
1476      * It affects only the style loaded into the WIN structure.
1477      */
1478
1479     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1480     {
1481         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1482         if (!(wndPtr->dwStyle & WS_POPUP))
1483             wndPtr->dwStyle |= WS_CAPTION;
1484     }
1485
1486     /* WS_EX_WINDOWEDGE depends on some other styles */
1487     if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
1488         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1489     else if (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME))
1490     {
1491         if (!((wndPtr->dwExStyle & WS_EX_STATICEDGE) &&
1492             (wndPtr->dwStyle & (WS_CHILD | WS_POPUP))))
1493             wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1494     }
1495     else
1496         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1497
1498     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1499         wndPtr->flags |= WIN_NEED_SIZE;
1500
1501     SERVER_START_REQ( set_window_info )
1502     {
1503         req->handle    = wine_server_user_handle( hwnd );
1504         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1505         req->style     = wndPtr->dwStyle;
1506         req->ex_style  = wndPtr->dwExStyle;
1507         req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1508         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1509         req->extra_offset = -1;
1510         wine_server_call( req );
1511     }
1512     SERVER_END_REQ;
1513
1514     /* Set the window menu */
1515
1516     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1517     {
1518         if (cs->hMenu)
1519         {
1520             if (!MENU_SetMenu(hwnd, cs->hMenu))
1521             {
1522                 WIN_ReleasePtr( wndPtr );
1523                 free_window_handle( hwnd );
1524                 return 0;
1525             }
1526         }
1527         else
1528         {
1529             LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1530             if (menuName)
1531             {
1532                 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1533                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1534             }
1535         }
1536     }
1537     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1538
1539     /* call the WH_CBT hook */
1540
1541     /* the window style passed to the hook must be the real window style,
1542      * rather than just the window style that the caller to CreateWindowEx
1543      * passed in, so we have to copy the original CREATESTRUCT and get the
1544      * the real style. */
1545     cbcs = *cs;
1546     cbcs.style = wndPtr->dwStyle;
1547     cbtc.lpcs = &cbcs;
1548     cbtc.hwndInsertAfter = HWND_TOP;
1549     WIN_ReleasePtr( wndPtr );
1550     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1551
1552     /* send the WM_GETMINMAXINFO message and fix the size if needed */
1553
1554     cx = cs->cx;
1555     cy = cs->cy;
1556     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1557     {
1558         POINT maxSize, maxPos, minTrack, maxTrack;
1559         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1560         if (maxTrack.x < cx) cx = maxTrack.x;
1561         if (maxTrack.y < cy) cy = maxTrack.y;
1562         if (minTrack.x > cx) cx = minTrack.x;
1563         if (minTrack.y > cy) cy = minTrack.y;
1564     }
1565
1566     if (cx < 0) cx = 0;
1567     if (cy < 0) cy = 0;
1568     SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1569     /* check for wraparound */
1570     if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1571     if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1572     if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1573
1574     /* send WM_NCCREATE */
1575
1576     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1577     if (unicode)
1578         result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1579     else
1580         result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1581     if (!result)
1582     {
1583         WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1584         goto failed;
1585     }
1586
1587     /* send WM_NCCALCSIZE */
1588
1589     if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1590     {
1591         /* yes, even if the CBT hook was called with HWND_TOP */
1592         HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1593         RECT client_rect = rect;
1594
1595         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1596         MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1597         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1598         MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1599         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1600     }
1601     else return 0;
1602
1603     /* send WM_CREATE */
1604
1605     if (unicode)
1606         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1607     else
1608         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1609     if (result == -1) goto failed;
1610
1611     /* call the driver */
1612
1613     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1614
1615     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1616
1617     /* send the size messages */
1618
1619     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1620           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1621     if (!(wndPtr->flags & WIN_NEED_SIZE))
1622     {
1623         WIN_ReleasePtr( wndPtr );
1624         WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1625         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1626                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1627         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1628     }
1629     else WIN_ReleasePtr( wndPtr );
1630
1631     /* Show the window, maximizing or minimizing if needed */
1632
1633     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1634     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1635     {
1636         RECT newPos;
1637         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1638
1639         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1640         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1641         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1642         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1643                       newPos.bottom - newPos.top, swFlag );
1644     }
1645
1646     /* Notify the parent window only */
1647
1648     send_parent_notify( hwnd, WM_CREATE );
1649     if (!IsWindow( hwnd )) return 0;
1650
1651     if (cs->style & WS_VISIBLE)
1652     {
1653         if (cs->style & WS_MAXIMIZE)
1654             sw = SW_SHOW;
1655         else if (cs->style & WS_MINIMIZE)
1656             sw = SW_SHOWMINIMIZED;
1657
1658         ShowWindow( hwnd, sw );
1659         if (cs->dwExStyle & WS_EX_MDICHILD)
1660         {
1661             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1662             /* ShowWindow won't activate child windows */
1663             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1664         }
1665     }
1666
1667     /* Call WH_SHELL hook */
1668
1669     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1670         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1671
1672     TRACE("created window %p\n", hwnd);
1673     return hwnd;
1674
1675 failed:
1676     WIN_DestroyWindow( hwnd );
1677     return 0;
1678 }
1679
1680
1681 /***********************************************************************
1682  *              CreateWindowExA (USER32.@)
1683  */
1684 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1685                                  LPCSTR windowName, DWORD style, INT x,
1686                                  INT y, INT width, INT height,
1687                                  HWND parent, HMENU menu,
1688                                  HINSTANCE instance, LPVOID data )
1689 {
1690     CREATESTRUCTA cs;
1691
1692     cs.lpCreateParams = data;
1693     cs.hInstance      = instance;
1694     cs.hMenu          = menu;
1695     cs.hwndParent     = parent;
1696     cs.x              = x;
1697     cs.y              = y;
1698     cs.cx             = width;
1699     cs.cy             = height;
1700     cs.style          = style;
1701     cs.lpszName       = windowName;
1702     cs.lpszClass      = className;
1703     cs.dwExStyle      = exStyle;
1704
1705     if (!IS_INTRESOURCE(className))
1706     {
1707         WCHAR bufferW[256];
1708         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1709             return 0;
1710         return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1711     }
1712     /* Note: we rely on the fact that CREATESTRUCTA and */
1713     /* CREATESTRUCTW have the same layout. */
1714     return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1715 }
1716
1717
1718 /***********************************************************************
1719  *              CreateWindowExW (USER32.@)
1720  */
1721 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1722                                  LPCWSTR windowName, DWORD style, INT x,
1723                                  INT y, INT width, INT height,
1724                                  HWND parent, HMENU menu,
1725                                  HINSTANCE instance, LPVOID data )
1726 {
1727     CREATESTRUCTW cs;
1728
1729     cs.lpCreateParams = data;
1730     cs.hInstance      = instance;
1731     cs.hMenu          = menu;
1732     cs.hwndParent     = parent;
1733     cs.x              = x;
1734     cs.y              = y;
1735     cs.cx             = width;
1736     cs.cy             = height;
1737     cs.style          = style;
1738     cs.lpszName       = windowName;
1739     cs.lpszClass      = className;
1740     cs.dwExStyle      = exStyle;
1741
1742     return wow_handlers.create_window( &cs, className, instance, TRUE );
1743 }
1744
1745
1746 /***********************************************************************
1747  *           WIN_SendDestroyMsg
1748  */
1749 static void WIN_SendDestroyMsg( HWND hwnd )
1750 {
1751     GUITHREADINFO info;
1752
1753     info.cbSize = sizeof(info);
1754     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1755     {
1756         if (hwnd == info.hwndCaret) DestroyCaret();
1757         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1758     }
1759
1760     /*
1761      * Send the WM_DESTROY to the window.
1762      */
1763     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1764
1765     /*
1766      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1767      * make sure that the window still exists when we come back.
1768      */
1769     if (IsWindow(hwnd))
1770     {
1771         HWND* pWndArray;
1772         int i;
1773
1774         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1775
1776         for (i = 0; pWndArray[i]; i++)
1777         {
1778             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1779         }
1780         HeapFree( GetProcessHeap(), 0, pWndArray );
1781     }
1782     else
1783       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1784 }
1785
1786
1787 /***********************************************************************
1788  *              DestroyWindow (USER32.@)
1789  */
1790 BOOL WINAPI DestroyWindow( HWND hwnd )
1791 {
1792     BOOL is_child;
1793
1794     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1795     {
1796         SetLastError( ERROR_ACCESS_DENIED );
1797         return FALSE;
1798     }
1799
1800     TRACE("(%p)\n", hwnd);
1801
1802       /* Call hooks */
1803
1804     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1805
1806     if (MENU_IsMenuActive() == hwnd)
1807         EndMenu();
1808
1809     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1810
1811     if (is_child)
1812     {
1813         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1814             send_parent_notify( hwnd, WM_DESTROY );
1815     }
1816     else if (!GetWindow( hwnd, GW_OWNER ))
1817     {
1818         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1819         /* FIXME: clean up palette - see "Internals" p.352 */
1820     }
1821
1822     if (!IsWindow(hwnd)) return TRUE;
1823
1824       /* Hide the window */
1825     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1826     {
1827         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1828         if (is_child)
1829             ShowWindow( hwnd, SW_HIDE );
1830         else
1831             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1832                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1833     }
1834
1835     if (!IsWindow(hwnd)) return TRUE;
1836
1837       /* Recursively destroy owned windows */
1838
1839     if (!is_child)
1840     {
1841         for (;;)
1842         {
1843             int i, got_one = 0;
1844             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1845             if (list)
1846             {
1847                 for (i = 0; list[i]; i++)
1848                 {
1849                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1850                     if (WIN_IsCurrentThread( list[i] ))
1851                     {
1852                         DestroyWindow( list[i] );
1853                         got_one = 1;
1854                         continue;
1855                     }
1856                     WIN_SetOwner( list[i], 0 );
1857                 }
1858                 HeapFree( GetProcessHeap(), 0, list );
1859             }
1860             if (!got_one) break;
1861         }
1862     }
1863
1864       /* Send destroy messages */
1865
1866     WIN_SendDestroyMsg( hwnd );
1867     if (!IsWindow( hwnd )) return TRUE;
1868
1869     if (GetClipboardOwner() == hwnd)
1870         CLIPBOARD_ReleaseOwner();
1871
1872       /* Destroy the window storage */
1873
1874     WIN_DestroyWindow( hwnd );
1875     return TRUE;
1876 }
1877
1878
1879 /***********************************************************************
1880  *              CloseWindow (USER32.@)
1881  */
1882 BOOL WINAPI CloseWindow( HWND hwnd )
1883 {
1884     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1885     ShowWindow( hwnd, SW_MINIMIZE );
1886     return TRUE;
1887 }
1888
1889
1890 /***********************************************************************
1891  *              OpenIcon (USER32.@)
1892  */
1893 BOOL WINAPI OpenIcon( HWND hwnd )
1894 {
1895     if (!IsIconic( hwnd )) return FALSE;
1896     ShowWindow( hwnd, SW_SHOWNORMAL );
1897     return TRUE;
1898 }
1899
1900
1901 /***********************************************************************
1902  *              FindWindowExW (USER32.@)
1903  */
1904 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1905 {
1906     HWND *list = NULL;
1907     HWND retvalue = 0;
1908     int i = 0, len = 0;
1909     WCHAR *buffer = NULL;
1910
1911     if (!parent && child) parent = GetDesktopWindow();
1912     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1913
1914     if (title)
1915     {
1916         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1917         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1918     }
1919
1920     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1921
1922     if (child)
1923     {
1924         child = WIN_GetFullHandle( child );
1925         while (list[i] && list[i] != child) i++;
1926         if (!list[i]) goto done;
1927         i++;  /* start from next window */
1928     }
1929
1930     if (title)
1931     {
1932         while (list[i])
1933         {
1934             if (GetWindowTextW( list[i], buffer, len + 1 ))
1935             {
1936                 if (!strcmpiW( buffer, title )) break;
1937             }
1938             else
1939             {
1940                 if (!title[0]) break;
1941             }
1942             i++;
1943         }
1944     }
1945     retvalue = list[i];
1946
1947  done:
1948     HeapFree( GetProcessHeap(), 0, list );
1949     HeapFree( GetProcessHeap(), 0, buffer );
1950     return retvalue;
1951 }
1952
1953
1954
1955 /***********************************************************************
1956  *              FindWindowA (USER32.@)
1957  */
1958 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1959 {
1960     HWND ret = FindWindowExA( 0, 0, className, title );
1961     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1962     return ret;
1963 }
1964
1965
1966 /***********************************************************************
1967  *              FindWindowExA (USER32.@)
1968  */
1969 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1970 {
1971     LPWSTR titleW = NULL;
1972     HWND hwnd = 0;
1973
1974     if (title)
1975     {
1976         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1977         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1978         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1979     }
1980
1981     if (!IS_INTRESOURCE(className))
1982     {
1983         WCHAR classW[256];
1984         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1985             hwnd = FindWindowExW( parent, child, classW, titleW );
1986     }
1987     else
1988     {
1989         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1990     }
1991
1992     HeapFree( GetProcessHeap(), 0, titleW );
1993     return hwnd;
1994 }
1995
1996
1997 /***********************************************************************
1998  *              FindWindowW (USER32.@)
1999  */
2000 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
2001 {
2002     return FindWindowExW( 0, 0, className, title );
2003 }
2004
2005
2006 /**********************************************************************
2007  *              GetDesktopWindow (USER32.@)
2008  */
2009 HWND WINAPI GetDesktopWindow(void)
2010 {
2011     struct user_thread_info *thread_info = get_user_thread_info();
2012
2013     if (thread_info->top_window) return thread_info->top_window;
2014
2015     SERVER_START_REQ( get_desktop_window )
2016     {
2017         req->force = 0;
2018         if (!wine_server_call( req ))
2019         {
2020             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2021             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2022         }
2023     }
2024     SERVER_END_REQ;
2025
2026     if (!thread_info->top_window)
2027     {
2028         USEROBJECTFLAGS flags;
2029         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
2030                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
2031         {
2032             static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
2033             static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
2034             STARTUPINFOW si;
2035             PROCESS_INFORMATION pi;
2036             WCHAR windir[MAX_PATH];
2037             WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
2038             WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
2039             void *redir;
2040
2041             memset( &si, 0, sizeof(si) );
2042             si.cb = sizeof(si);
2043             si.dwFlags = STARTF_USESTDHANDLES;
2044             si.hStdInput  = 0;
2045             si.hStdOutput = 0;
2046             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
2047
2048             GetSystemDirectoryW( windir, MAX_PATH );
2049             strcpyW( app, windir );
2050             strcatW( app, explorer );
2051             strcpyW( cmdline, app );
2052             strcatW( cmdline, args );
2053
2054             Wow64DisableWow64FsRedirection( &redir );
2055             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
2056                                 NULL, windir, &si, &pi ))
2057             {
2058                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
2059                 WaitForInputIdle( pi.hProcess, 10000 );
2060                 CloseHandle( pi.hThread );
2061                 CloseHandle( pi.hProcess );
2062             }
2063             else WARN( "failed to start explorer, err %d\n", GetLastError() );
2064             Wow64RevertWow64FsRedirection( redir );
2065         }
2066         else TRACE( "not starting explorer since winstation is not visible\n" );
2067
2068         SERVER_START_REQ( get_desktop_window )
2069         {
2070             req->force = 1;
2071             if (!wine_server_call( req ))
2072             {
2073                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
2074                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
2075             }
2076         }
2077         SERVER_END_REQ;
2078     }
2079
2080     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
2081         ERR( "failed to create desktop window\n" );
2082
2083     return thread_info->top_window;
2084 }
2085
2086
2087 /*******************************************************************
2088  *              EnableWindow (USER32.@)
2089  */
2090 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
2091 {
2092     BOOL retvalue;
2093     HWND full_handle;
2094
2095     if (is_broadcast(hwnd))
2096     {
2097         SetLastError( ERROR_INVALID_PARAMETER );
2098         return FALSE;
2099     }
2100
2101     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2102         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
2103
2104     hwnd = full_handle;
2105
2106     TRACE("( %p, %d )\n", hwnd, enable);
2107
2108     retvalue = !IsWindowEnabled( hwnd );
2109
2110     if (enable && retvalue)
2111     {
2112         WIN_SetStyle( hwnd, 0, WS_DISABLED );
2113         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
2114     }
2115     else if (!enable && !retvalue)
2116     {
2117         HWND capture_wnd;
2118
2119         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
2120
2121         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
2122
2123         if (hwnd == GetFocus())
2124             SetFocus( 0 );  /* A disabled window can't have the focus */
2125
2126         capture_wnd = GetCapture();
2127         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
2128             ReleaseCapture();  /* A disabled window can't capture the mouse */
2129
2130         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
2131     }
2132     return retvalue;
2133 }
2134
2135
2136 /***********************************************************************
2137  *              IsWindowEnabled (USER32.@)
2138  */
2139 BOOL WINAPI IsWindowEnabled(HWND hWnd)
2140 {
2141     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
2142 }
2143
2144
2145 /***********************************************************************
2146  *              IsWindowUnicode (USER32.@)
2147  */
2148 BOOL WINAPI IsWindowUnicode( HWND hwnd )
2149 {
2150     WND * wndPtr;
2151     BOOL retvalue = FALSE;
2152
2153     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
2154
2155     if (wndPtr == WND_DESKTOP) return TRUE;
2156
2157     if (wndPtr != WND_OTHER_PROCESS)
2158     {
2159         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2160         WIN_ReleasePtr( wndPtr );
2161     }
2162     else
2163     {
2164         SERVER_START_REQ( get_window_info )
2165         {
2166             req->handle = wine_server_user_handle( hwnd );
2167             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2168         }
2169         SERVER_END_REQ;
2170     }
2171     return retvalue;
2172 }
2173
2174
2175 /**********************************************************************
2176  *           WIN_GetWindowLong
2177  *
2178  * Helper function for GetWindowLong().
2179  */
2180 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2181 {
2182     LONG_PTR retvalue = 0;
2183     WND *wndPtr;
2184
2185     if (offset == GWLP_HWNDPARENT)
2186     {
2187         HWND parent = GetAncestor( hwnd, GA_PARENT );
2188         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2189         return (ULONG_PTR)parent;
2190     }
2191
2192     if (!(wndPtr = WIN_GetPtr( hwnd )))
2193     {
2194         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2195         return 0;
2196     }
2197
2198     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2199     {
2200         if (offset == GWLP_WNDPROC)
2201         {
2202             SetLastError( ERROR_ACCESS_DENIED );
2203             return 0;
2204         }
2205         SERVER_START_REQ( set_window_info )
2206         {
2207             req->handle = wine_server_user_handle( hwnd );
2208             req->flags  = 0;  /* don't set anything, just retrieve */
2209             req->extra_offset = (offset >= 0) ? offset : -1;
2210             req->extra_size = (offset >= 0) ? size : 0;
2211             if (!wine_server_call_err( req ))
2212             {
2213                 switch(offset)
2214                 {
2215                 case GWL_STYLE:      retvalue = reply->old_style; break;
2216                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
2217                 case GWLP_ID:        retvalue = reply->old_id; break;
2218                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2219                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2220                 default:
2221                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2222                     else SetLastError( ERROR_INVALID_INDEX );
2223                     break;
2224                 }
2225             }
2226         }
2227         SERVER_END_REQ;
2228         return retvalue;
2229     }
2230
2231     /* now we have a valid wndPtr */
2232
2233     if (offset >= 0)
2234     {
2235         if (offset > (int)(wndPtr->cbWndExtra - size))
2236         {
2237             WARN("Invalid offset %d\n", offset );
2238             WIN_ReleasePtr( wndPtr );
2239             SetLastError( ERROR_INVALID_INDEX );
2240             return 0;
2241         }
2242         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2243
2244         /* Special case for dialog window procedure */
2245         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2246             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2247         WIN_ReleasePtr( wndPtr );
2248         return retvalue;
2249     }
2250
2251     switch(offset)
2252     {
2253     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2254     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2255     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2256     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2257     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2258     case GWLP_WNDPROC:
2259         /* This looks like a hack only for the edit control (see tests). This makes these controls
2260          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2261          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2262          */
2263         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2264             retvalue = (ULONG_PTR)wndPtr->winproc;
2265         else
2266             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2267         break;
2268     default:
2269         WARN("Unknown offset %d\n", offset );
2270         SetLastError( ERROR_INVALID_INDEX );
2271         break;
2272     }
2273     WIN_ReleasePtr(wndPtr);
2274     return retvalue;
2275 }
2276
2277
2278 /**********************************************************************
2279  *           WIN_SetWindowLong
2280  *
2281  * Helper function for SetWindowLong().
2282  *
2283  * 0 is the failure code. However, in the case of failure SetLastError
2284  * must be set to distinguish between a 0 return value and a failure.
2285  */
2286 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2287 {
2288     STYLESTRUCT style;
2289     BOOL ok, made_visible = FALSE;
2290     LONG_PTR retval = 0;
2291     WND *wndPtr;
2292
2293     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2294
2295     if (is_broadcast(hwnd))
2296     {
2297         SetLastError( ERROR_INVALID_PARAMETER );
2298         return FALSE;
2299     }
2300
2301     if (!(wndPtr = WIN_GetPtr( hwnd )))
2302     {
2303         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2304         return 0;
2305     }
2306     if (wndPtr == WND_DESKTOP)
2307     {
2308         /* can't change anything on the desktop window */
2309         SetLastError( ERROR_ACCESS_DENIED );
2310         return 0;
2311     }
2312     if (wndPtr == WND_OTHER_PROCESS)
2313     {
2314         if (offset == GWLP_WNDPROC)
2315         {
2316             SetLastError( ERROR_ACCESS_DENIED );
2317             return 0;
2318         }
2319         if (offset > 32767 || offset < -32767)
2320         {
2321             SetLastError( ERROR_INVALID_INDEX );
2322             return 0;
2323         }
2324         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2325     }
2326
2327     /* first some special cases */
2328     switch( offset )
2329     {
2330     case GWL_STYLE:
2331         style.styleOld = wndPtr->dwStyle;
2332         style.styleNew = newval;
2333         WIN_ReleasePtr( wndPtr );
2334         SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2335         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2336         newval = style.styleNew;
2337         /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2338         if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2339         /* FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change
2340            WS_EX_WINDOWEDGE too */
2341         break;
2342     case GWL_EXSTYLE:
2343         style.styleOld = wndPtr->dwExStyle;
2344         style.styleNew = newval;
2345         WIN_ReleasePtr( wndPtr );
2346         SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2347         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2348         /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2349         newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2350         /* WS_EX_WINDOWEDGE depends on some other styles */
2351         if (newval & WS_EX_DLGMODALFRAME)
2352             newval |= WS_EX_WINDOWEDGE;
2353         else if (!(newval & WS_EX_STATICEDGE) && (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
2354             newval |= WS_EX_WINDOWEDGE;
2355         else
2356             newval &= ~WS_EX_WINDOWEDGE;
2357         break;
2358     case GWLP_HWNDPARENT:
2359         if (wndPtr->parent == GetDesktopWindow())
2360         {
2361             WIN_ReleasePtr( wndPtr );
2362             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2363         }
2364         else
2365         {
2366             WIN_ReleasePtr( wndPtr );
2367             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2368         }
2369     case GWLP_WNDPROC:
2370     {
2371         WNDPROC proc;
2372         UINT old_flags = wndPtr->flags;
2373         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2374         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2375         if (proc) wndPtr->winproc = proc;
2376         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2377         else wndPtr->flags &= ~WIN_ISUNICODE;
2378         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2379         {
2380             WIN_ReleasePtr( wndPtr );
2381             return retval;
2382         }
2383         /* update is_unicode flag on the server side */
2384         break;
2385     }
2386     case GWLP_ID:
2387     case GWLP_HINSTANCE:
2388     case GWLP_USERDATA:
2389         break;
2390     case DWLP_DLGPROC:
2391         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2392             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2393         {
2394             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2395             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2396             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2397             WIN_ReleasePtr( wndPtr );
2398             return retval;
2399         }
2400         /* fall through */
2401     default:
2402         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2403         {
2404             WARN("Invalid offset %d\n", offset );
2405             WIN_ReleasePtr( wndPtr );
2406             SetLastError( ERROR_INVALID_INDEX );
2407             return 0;
2408         }
2409         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2410         {
2411             /* already set to the same value */
2412             WIN_ReleasePtr( wndPtr );
2413             return newval;
2414         }
2415         break;
2416     }
2417
2418     SERVER_START_REQ( set_window_info )
2419     {
2420         req->handle = wine_server_user_handle( hwnd );
2421         req->extra_offset = -1;
2422         switch(offset)
2423         {
2424         case GWL_STYLE:
2425             req->flags = SET_WIN_STYLE;
2426             req->style = newval;
2427             break;
2428         case GWL_EXSTYLE:
2429             req->flags = SET_WIN_EXSTYLE;
2430             req->ex_style = newval;
2431             break;
2432         case GWLP_ID:
2433             req->flags = SET_WIN_ID;
2434             req->id = newval;
2435             break;
2436         case GWLP_HINSTANCE:
2437             req->flags = SET_WIN_INSTANCE;
2438             req->instance = wine_server_client_ptr( (void *)newval );
2439             break;
2440         case GWLP_WNDPROC:
2441             req->flags = SET_WIN_UNICODE;
2442             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2443             break;
2444         case GWLP_USERDATA:
2445             req->flags = SET_WIN_USERDATA;
2446             req->user_data = newval;
2447             break;
2448         default:
2449             req->flags = SET_WIN_EXTRA;
2450             req->extra_offset = offset;
2451             req->extra_size = size;
2452             set_win_data( &req->extra_value, newval, size );
2453         }
2454         if ((ok = !wine_server_call_err( req )))
2455         {
2456             switch(offset)
2457             {
2458             case GWL_STYLE:
2459                 wndPtr->dwStyle = newval;
2460                 retval = reply->old_style;
2461                 break;
2462             case GWL_EXSTYLE:
2463                 wndPtr->dwExStyle = newval;
2464                 retval = reply->old_ex_style;
2465                 break;
2466             case GWLP_ID:
2467                 wndPtr->wIDmenu = newval;
2468                 retval = reply->old_id;
2469                 break;
2470             case GWLP_HINSTANCE:
2471                 wndPtr->hInstance = (HINSTANCE)newval;
2472                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2473                 break;
2474             case GWLP_WNDPROC:
2475                 break;
2476             case GWLP_USERDATA:
2477                 wndPtr->userdata = newval;
2478                 retval = reply->old_user_data;
2479                 break;
2480             default:
2481                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2482                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2483                 break;
2484             }
2485         }
2486     }
2487     SERVER_END_REQ;
2488
2489     if ((offset == GWL_STYLE && ((style.styleOld ^ style.styleNew) & WS_VISIBLE)) ||
2490         (offset == GWL_EXSTYLE && ((style.styleOld ^ style.styleNew) & WS_EX_LAYERED)))
2491     {
2492         made_visible = !(wndPtr->flags & WIN_HIDDEN) && (wndPtr->dwStyle & WS_VISIBLE);
2493         invalidate_dce( wndPtr, NULL );
2494     }
2495     WIN_ReleasePtr( wndPtr );
2496
2497     if (!ok) return 0;
2498
2499     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2500     {
2501         style.styleOld = retval;
2502         style.styleNew = newval;
2503         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2504         if (made_visible) update_window_state( hwnd );
2505         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2506     }
2507
2508     return retval;
2509 }
2510
2511
2512 /**********************************************************************
2513  *              GetWindowWord (USER32.@)
2514  */
2515 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2516 {
2517     switch(offset)
2518     {
2519     case GWLP_ID:
2520     case GWLP_HINSTANCE:
2521     case GWLP_HWNDPARENT:
2522         break;
2523     default:
2524         if (offset < 0)
2525         {
2526             WARN("Invalid offset %d\n", offset );
2527             SetLastError( ERROR_INVALID_INDEX );
2528             return 0;
2529         }
2530         break;
2531     }
2532     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2533 }
2534
2535
2536 /**********************************************************************
2537  *              GetWindowLongA (USER32.@)
2538  */
2539 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2540 {
2541     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2542 }
2543
2544
2545 /**********************************************************************
2546  *              GetWindowLongW (USER32.@)
2547  */
2548 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2549 {
2550     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2551 }
2552
2553
2554 /**********************************************************************
2555  *              SetWindowWord (USER32.@)
2556  */
2557 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2558 {
2559     switch(offset)
2560     {
2561     case GWLP_ID:
2562     case GWLP_HINSTANCE:
2563     case GWLP_HWNDPARENT:
2564         break;
2565     default:
2566         if (offset < 0)
2567         {
2568             WARN("Invalid offset %d\n", offset );
2569             SetLastError( ERROR_INVALID_INDEX );
2570             return 0;
2571         }
2572         break;
2573     }
2574     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2575 }
2576
2577
2578 /**********************************************************************
2579  *              SetWindowLongA (USER32.@)
2580  *
2581  * See SetWindowLongW.
2582  */
2583 LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2584 {
2585     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2586 }
2587
2588
2589 /**********************************************************************
2590  *              SetWindowLongW (USER32.@) Set window attribute
2591  *
2592  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2593  * value in a window's extra memory.
2594  *
2595  * The _hwnd_ parameter specifies the window.  is the handle to a
2596  * window that has extra memory. The _newval_ parameter contains the
2597  * new attribute or extra memory value.  If positive, the _offset_
2598  * parameter is the byte-addressed location in the window's extra
2599  * memory to set.  If negative, _offset_ specifies the window
2600  * attribute to set, and should be one of the following values:
2601  *
2602  * GWL_EXSTYLE      The window's extended window style
2603  *
2604  * GWL_STYLE        The window's window style.
2605  *
2606  * GWLP_WNDPROC     Pointer to the window's window procedure.
2607  *
2608  * GWLP_HINSTANCE   The window's pplication instance handle.
2609  *
2610  * GWLP_ID          The window's identifier.
2611  *
2612  * GWLP_USERDATA    The window's user-specified data.
2613  *
2614  * If the window is a dialog box, the _offset_ parameter can be one of
2615  * the following values:
2616  *
2617  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2618  *
2619  * DWLP_MSGRESULT   The return value of a message
2620  *                  that the dialog box procedure processed.
2621  *
2622  * DWLP_USER        Application specific information.
2623  *
2624  * RETURNS
2625  *
2626  * If successful, returns the previous value located at _offset_. Otherwise,
2627  * returns 0.
2628  *
2629  * NOTES
2630  *
2631  * Extra memory for a window class is specified by a nonzero cbWndExtra
2632  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2633  * time of class creation.
2634  *
2635  * Using GWL_WNDPROC to set a new window procedure effectively creates
2636  * a window subclass. Use CallWindowProc() in the new windows procedure
2637  * to pass messages to the superclass's window procedure.
2638  *
2639  * The user data is reserved for use by the application which created
2640  * the window.
2641  *
2642  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2643  * instead, call the EnableWindow() function to change the window's
2644  * disabled state.
2645  *
2646  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2647  * SetParent() instead.
2648  *
2649  * Win95:
2650  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2651  * it sends WM_STYLECHANGING before changing the settings
2652  * and WM_STYLECHANGED afterwards.
2653  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2654  */
2655 LONG WINAPI SetWindowLongW(
2656     HWND hwnd,  /* [in] window to alter */
2657     INT offset, /* [in] offset, in bytes, of location to alter */
2658     LONG newval /* [in] new value of location */
2659 ) {
2660     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2661 }
2662
2663
2664 /*******************************************************************
2665  *              GetWindowTextA (USER32.@)
2666  */
2667 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2668 {
2669     WCHAR *buffer;
2670
2671     if (!lpString) return 0;
2672
2673     if (WIN_IsCurrentProcess( hwnd ))
2674         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2675
2676     /* when window belongs to other process, don't send a message */
2677     if (nMaxCount <= 0) return 0;
2678     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2679     get_server_window_text( hwnd, buffer, nMaxCount );
2680     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2681         lpString[nMaxCount-1] = 0;
2682     HeapFree( GetProcessHeap(), 0, buffer );
2683     return strlen(lpString);
2684 }
2685
2686
2687 /*******************************************************************
2688  *              InternalGetWindowText (USER32.@)
2689  */
2690 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2691 {
2692     WND *win;
2693
2694     if (nMaxCount <= 0) return 0;
2695     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2696     if (win == WND_DESKTOP) lpString[0] = 0;
2697     else if (win != WND_OTHER_PROCESS)
2698     {
2699         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2700         else lpString[0] = 0;
2701         WIN_ReleasePtr( win );
2702     }
2703     else
2704     {
2705         get_server_window_text( hwnd, lpString, nMaxCount );
2706     }
2707     return strlenW(lpString);
2708 }
2709
2710
2711 /*******************************************************************
2712  *              GetWindowTextW (USER32.@)
2713  */
2714 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2715 {
2716     if (!lpString) return 0;
2717
2718     if (WIN_IsCurrentProcess( hwnd ))
2719         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2720
2721     /* when window belongs to other process, don't send a message */
2722     if (nMaxCount <= 0) return 0;
2723     get_server_window_text( hwnd, lpString, nMaxCount );
2724     return strlenW(lpString);
2725 }
2726
2727
2728 /*******************************************************************
2729  *              SetWindowTextA (USER32.@)
2730  *              SetWindowText  (USER32.@)
2731  */
2732 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2733 {
2734     if (is_broadcast(hwnd))
2735     {
2736         SetLastError( ERROR_INVALID_PARAMETER );
2737         return FALSE;
2738     }
2739     if (!WIN_IsCurrentProcess( hwnd ))
2740         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2741                debugstr_a(lpString), hwnd );
2742     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2743 }
2744
2745
2746 /*******************************************************************
2747  *              SetWindowTextW (USER32.@)
2748  */
2749 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2750 {
2751     if (is_broadcast(hwnd))
2752     {
2753         SetLastError( ERROR_INVALID_PARAMETER );
2754         return FALSE;
2755     }
2756     if (!WIN_IsCurrentProcess( hwnd ))
2757         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2758                debugstr_w(lpString), hwnd );
2759     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2760 }
2761
2762
2763 /*******************************************************************
2764  *              GetWindowTextLengthA (USER32.@)
2765  */
2766 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2767 {
2768     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2769 }
2770
2771 /*******************************************************************
2772  *              GetWindowTextLengthW (USER32.@)
2773  */
2774 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2775 {
2776     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2777 }
2778
2779
2780 /*******************************************************************
2781  *              IsWindow (USER32.@)
2782  */
2783 BOOL WINAPI IsWindow( HWND hwnd )
2784 {
2785     WND *ptr;
2786     BOOL ret;
2787
2788     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2789     if (ptr == WND_DESKTOP) return TRUE;
2790
2791     if (ptr != WND_OTHER_PROCESS)
2792     {
2793         WIN_ReleasePtr( ptr );
2794         return TRUE;
2795     }
2796
2797     /* check other processes */
2798     SERVER_START_REQ( get_window_info )
2799     {
2800         req->handle = wine_server_user_handle( hwnd );
2801         ret = !wine_server_call_err( req );
2802     }
2803     SERVER_END_REQ;
2804     return ret;
2805 }
2806
2807
2808 /***********************************************************************
2809  *              GetWindowThreadProcessId (USER32.@)
2810  */
2811 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2812 {
2813     WND *ptr;
2814     DWORD tid = 0;
2815
2816     if (!(ptr = WIN_GetPtr( hwnd )))
2817     {
2818         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2819         return 0;
2820     }
2821
2822     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2823     {
2824         /* got a valid window */
2825         tid = ptr->tid;
2826         if (process) *process = GetCurrentProcessId();
2827         WIN_ReleasePtr( ptr );
2828         return tid;
2829     }
2830
2831     /* check other processes */
2832     SERVER_START_REQ( get_window_info )
2833     {
2834         req->handle = wine_server_user_handle( hwnd );
2835         if (!wine_server_call_err( req ))
2836         {
2837             tid = (DWORD)reply->tid;
2838             if (process) *process = (DWORD)reply->pid;
2839         }
2840     }
2841     SERVER_END_REQ;
2842     return tid;
2843 }
2844
2845
2846 /*****************************************************************
2847  *              GetParent (USER32.@)
2848  */
2849 HWND WINAPI GetParent( HWND hwnd )
2850 {
2851     WND *wndPtr;
2852     HWND retvalue = 0;
2853
2854     if (!(wndPtr = WIN_GetPtr( hwnd )))
2855     {
2856         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2857         return 0;
2858     }
2859     if (wndPtr == WND_DESKTOP) return 0;
2860     if (wndPtr == WND_OTHER_PROCESS)
2861     {
2862         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2863         if (style & (WS_POPUP | WS_CHILD))
2864         {
2865             SERVER_START_REQ( get_window_tree )
2866             {
2867                 req->handle = wine_server_user_handle( hwnd );
2868                 if (!wine_server_call_err( req ))
2869                 {
2870                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2871                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2872                 }
2873             }
2874             SERVER_END_REQ;
2875         }
2876     }
2877     else
2878     {
2879         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2880         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2881         WIN_ReleasePtr( wndPtr );
2882     }
2883     return retvalue;
2884 }
2885
2886
2887 /*****************************************************************
2888  *              GetAncestor (USER32.@)
2889  */
2890 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2891 {
2892     WND *win;
2893     HWND *list, ret = 0;
2894
2895     switch(type)
2896     {
2897     case GA_PARENT:
2898         if (!(win = WIN_GetPtr( hwnd )))
2899         {
2900             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2901             return 0;
2902         }
2903         if (win == WND_DESKTOP) return 0;
2904         if (win != WND_OTHER_PROCESS)
2905         {
2906             ret = win->parent;
2907             WIN_ReleasePtr( win );
2908         }
2909         else /* need to query the server */
2910         {
2911             SERVER_START_REQ( get_window_tree )
2912             {
2913                 req->handle = wine_server_user_handle( hwnd );
2914                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2915             }
2916             SERVER_END_REQ;
2917         }
2918         break;
2919
2920     case GA_ROOT:
2921         if (!(list = list_window_parents( hwnd ))) return 0;
2922
2923         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2924         else
2925         {
2926             int count = 2;
2927             while (list[count]) count++;
2928             ret = list[count - 2];  /* get the one before the desktop */
2929         }
2930         HeapFree( GetProcessHeap(), 0, list );
2931         break;
2932
2933     case GA_ROOTOWNER:
2934         if (is_desktop_window( hwnd )) return 0;
2935         ret = WIN_GetFullHandle( hwnd );
2936         for (;;)
2937         {
2938             HWND parent = GetParent( ret );
2939             if (!parent) break;
2940             ret = parent;
2941         }
2942         break;
2943     }
2944     return ret;
2945 }
2946
2947
2948 /*****************************************************************
2949  *              SetParent (USER32.@)
2950  */
2951 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2952 {
2953     HWND full_handle;
2954     HWND old_parent = 0;
2955     BOOL was_visible;
2956     WND *wndPtr;
2957     POINT pt;
2958     BOOL ret;
2959
2960     if (is_broadcast(hwnd) || is_broadcast(parent))
2961     {
2962         SetLastError(ERROR_INVALID_PARAMETER);
2963         return 0;
2964     }
2965
2966     if (!parent) parent = GetDesktopWindow();
2967     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2968     else parent = WIN_GetFullHandle( parent );
2969
2970     if (!IsWindow( parent ))
2971     {
2972         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2973         return 0;
2974     }
2975
2976     /* Some applications try to set a child as a parent */
2977     if (IsChild(hwnd, parent))
2978     {
2979         SetLastError( ERROR_INVALID_PARAMETER );
2980         return 0;
2981     }
2982
2983     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2984         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2985
2986     if (full_handle == parent)
2987     {
2988         SetLastError( ERROR_INVALID_PARAMETER );
2989         return 0;
2990     }
2991
2992     /* Windows hides the window first, then shows it again
2993      * including the WM_SHOWWINDOW messages and all */
2994     was_visible = ShowWindow( hwnd, SW_HIDE );
2995
2996     wndPtr = WIN_GetPtr( hwnd );
2997     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2998
2999     pt.x = wndPtr->rectWindow.left;
3000     pt.y = wndPtr->rectWindow.top;
3001
3002     SERVER_START_REQ( set_parent )
3003     {
3004         req->handle = wine_server_user_handle( hwnd );
3005         req->parent = wine_server_user_handle( parent );
3006         if ((ret = !wine_server_call( req )))
3007         {
3008             old_parent = wine_server_ptr_handle( reply->old_parent );
3009             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
3010         }
3011
3012     }
3013     SERVER_END_REQ;
3014     WIN_ReleasePtr( wndPtr );
3015     if (!ret) return 0;
3016
3017     USER_Driver->pSetParent( full_handle, parent, old_parent );
3018
3019     /* SetParent additionally needs to make hwnd the topmost window
3020        in the x-order and send the expected WM_WINDOWPOSCHANGING and
3021        WM_WINDOWPOSCHANGED notification messages.
3022     */
3023     SetWindowPos( hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE );
3024
3025     if (was_visible) ShowWindow( hwnd, SW_SHOW );
3026
3027     return old_parent;
3028 }
3029
3030
3031 /*******************************************************************
3032  *              IsChild (USER32.@)
3033  */
3034 BOOL WINAPI IsChild( HWND parent, HWND child )
3035 {
3036     HWND *list = list_window_parents( child );
3037     int i;
3038     BOOL ret;
3039
3040     if (!list) return FALSE;
3041     parent = WIN_GetFullHandle( parent );
3042     for (i = 0; list[i]; i++) if (list[i] == parent) break;
3043     ret = list[i] && list[i+1];
3044     HeapFree( GetProcessHeap(), 0, list );
3045     return ret;
3046 }
3047
3048
3049 /***********************************************************************
3050  *              IsWindowVisible (USER32.@)
3051  */
3052 BOOL WINAPI IsWindowVisible( HWND hwnd )
3053 {
3054     HWND *list;
3055     BOOL retval = TRUE;
3056     int i;
3057
3058     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
3059     if (!(list = list_window_parents( hwnd ))) return TRUE;
3060     if (list[0])
3061     {
3062         for (i = 0; list[i+1]; i++)
3063             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
3064         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3065     }
3066     HeapFree( GetProcessHeap(), 0, list );
3067     return retval;
3068 }
3069
3070
3071 /***********************************************************************
3072  *           WIN_IsWindowDrawable
3073  *
3074  * hwnd is drawable when it is visible, all parents are not
3075  * minimized, and it is itself not minimized unless we are
3076  * trying to draw its default class icon.
3077  */
3078 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
3079 {
3080     HWND *list;
3081     BOOL retval = TRUE;
3082     int i;
3083     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
3084
3085     if (!(style & WS_VISIBLE)) return FALSE;
3086     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
3087
3088     if (!(list = list_window_parents( hwnd ))) return TRUE;
3089     if (list[0])
3090     {
3091         for (i = 0; list[i+1]; i++)
3092             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
3093                 break;
3094         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
3095     }
3096     HeapFree( GetProcessHeap(), 0, list );
3097     return retval;
3098 }
3099
3100
3101 /*******************************************************************
3102  *              GetTopWindow (USER32.@)
3103  */
3104 HWND WINAPI GetTopWindow( HWND hwnd )
3105 {
3106     if (!hwnd) hwnd = GetDesktopWindow();
3107     return GetWindow( hwnd, GW_CHILD );
3108 }
3109
3110
3111 /*******************************************************************
3112  *              GetWindow (USER32.@)
3113  */
3114 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
3115 {
3116     HWND retval = 0;
3117
3118     if (rel == GW_OWNER)  /* this one may be available locally */
3119     {
3120         WND *wndPtr = WIN_GetPtr( hwnd );
3121         if (!wndPtr)
3122         {
3123             SetLastError( ERROR_INVALID_HANDLE );
3124             return 0;
3125         }
3126         if (wndPtr == WND_DESKTOP) return 0;
3127         if (wndPtr != WND_OTHER_PROCESS)
3128         {
3129             retval = wndPtr->owner;
3130             WIN_ReleasePtr( wndPtr );
3131             return retval;
3132         }
3133         /* else fall through to server call */
3134     }
3135
3136     SERVER_START_REQ( get_window_tree )
3137     {
3138         req->handle = wine_server_user_handle( hwnd );
3139         if (!wine_server_call_err( req ))
3140         {
3141             switch(rel)
3142             {
3143             case GW_HWNDFIRST:
3144                 retval = wine_server_ptr_handle( reply->first_sibling );
3145                 break;
3146             case GW_HWNDLAST:
3147                 retval = wine_server_ptr_handle( reply->last_sibling );
3148                 break;
3149             case GW_HWNDNEXT:
3150                 retval = wine_server_ptr_handle( reply->next_sibling );
3151                 break;
3152             case GW_HWNDPREV:
3153                 retval = wine_server_ptr_handle( reply->prev_sibling );
3154                 break;
3155             case GW_OWNER:
3156                 retval = wine_server_ptr_handle( reply->owner );
3157                 break;
3158             case GW_CHILD:
3159                 retval = wine_server_ptr_handle( reply->first_child );
3160                 break;
3161             }
3162         }
3163     }
3164     SERVER_END_REQ;
3165     return retval;
3166 }
3167
3168
3169 /*******************************************************************
3170  *              ShowOwnedPopups (USER32.@)
3171  */
3172 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
3173 {
3174     int count = 0;
3175     WND *pWnd;
3176     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3177
3178     if (!win_array) return TRUE;
3179
3180     while (win_array[count]) count++;
3181     while (--count >= 0)
3182     {
3183         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3184         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3185         if (pWnd == WND_OTHER_PROCESS) continue;
3186         if (fShow)
3187         {
3188             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3189             {
3190                 WIN_ReleasePtr( pWnd );
3191                 /* In Windows, ShowOwnedPopups(TRUE) generates
3192                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3193                  * regardless of the state of the owner
3194                  */
3195                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3196                 continue;
3197             }
3198         }
3199         else
3200         {
3201             if (pWnd->dwStyle & WS_VISIBLE)
3202             {
3203                 WIN_ReleasePtr( pWnd );
3204                 /* In Windows, ShowOwnedPopups(FALSE) generates
3205                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3206                  * regardless of the state of the owner
3207                  */
3208                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3209                 continue;
3210             }
3211         }
3212         WIN_ReleasePtr( pWnd );
3213     }
3214     HeapFree( GetProcessHeap(), 0, win_array );
3215     return TRUE;
3216 }
3217
3218
3219 /*******************************************************************
3220  *              GetLastActivePopup (USER32.@)
3221  */
3222 HWND WINAPI GetLastActivePopup( HWND hwnd )
3223 {
3224     HWND retval = hwnd;
3225
3226     SERVER_START_REQ( get_window_info )
3227     {
3228         req->handle = wine_server_user_handle( hwnd );
3229         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3230     }
3231     SERVER_END_REQ;
3232     return retval;
3233 }
3234
3235
3236 /*******************************************************************
3237  *           WIN_ListChildren
3238  *
3239  * Build an array of the children of a given window. The array must be
3240  * freed with HeapFree. Returns NULL when no windows are found.
3241  */
3242 HWND *WIN_ListChildren( HWND hwnd )
3243 {
3244     if (!hwnd)
3245     {
3246         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3247         return NULL;
3248     }
3249     return list_window_children( 0, hwnd, NULL, 0 );
3250 }
3251
3252
3253 /*******************************************************************
3254  *              EnumWindows (USER32.@)
3255  */
3256 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3257 {
3258     HWND *list;
3259     BOOL ret = TRUE;
3260     int i;
3261
3262     USER_CheckNotLock();
3263
3264     /* We have to build a list of all windows first, to avoid */
3265     /* unpleasant side-effects, for instance if the callback */
3266     /* function changes the Z-order of the windows.          */
3267
3268     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3269
3270     /* Now call the callback function for every window */
3271
3272     for (i = 0; list[i]; i++)
3273     {
3274         /* Make sure that the window still exists */
3275         if (!IsWindow( list[i] )) continue;
3276         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3277     }
3278     HeapFree( GetProcessHeap(), 0, list );
3279     return ret;
3280 }
3281
3282
3283 /**********************************************************************
3284  *              EnumThreadWindows (USER32.@)
3285  */
3286 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3287 {
3288     HWND *list;
3289     int i;
3290     BOOL ret = TRUE;
3291
3292     USER_CheckNotLock();
3293
3294     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3295
3296     /* Now call the callback function for every window */
3297
3298     for (i = 0; list[i]; i++)
3299         if (!(ret = func( list[i], lParam ))) break;
3300     HeapFree( GetProcessHeap(), 0, list );
3301     return ret;
3302 }
3303
3304
3305 /***********************************************************************
3306  *              EnumDesktopWindows   (USER32.@)
3307  */
3308 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3309 {
3310     HWND *list;
3311     int i;
3312
3313     USER_CheckNotLock();
3314
3315     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3316
3317     for (i = 0; list[i]; i++)
3318         if (!func( list[i], lparam )) break;
3319     HeapFree( GetProcessHeap(), 0, list );
3320     return TRUE;
3321 }
3322
3323
3324 /**********************************************************************
3325  *           WIN_EnumChildWindows
3326  *
3327  * Helper function for EnumChildWindows().
3328  */
3329 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3330 {
3331     HWND *childList;
3332     BOOL ret = FALSE;
3333
3334     for ( ; *list; list++)
3335     {
3336         /* Make sure that the window still exists */
3337         if (!IsWindow( *list )) continue;
3338         /* Build children list first */
3339         childList = WIN_ListChildren( *list );
3340
3341         ret = func( *list, lParam );
3342
3343         if (childList)
3344         {
3345             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3346             HeapFree( GetProcessHeap(), 0, childList );
3347         }
3348         if (!ret) return FALSE;
3349     }
3350     return TRUE;
3351 }
3352
3353
3354 /**********************************************************************
3355  *              EnumChildWindows (USER32.@)
3356  */
3357 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3358 {
3359     HWND *list;
3360     BOOL ret;
3361
3362     USER_CheckNotLock();
3363
3364     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3365     ret = WIN_EnumChildWindows( list, func, lParam );
3366     HeapFree( GetProcessHeap(), 0, list );
3367     return ret;
3368 }
3369
3370
3371 /*******************************************************************
3372  *              AnyPopup (USER32.@)
3373  */
3374 BOOL WINAPI AnyPopup(void)
3375 {
3376     int i;
3377     BOOL retvalue;
3378     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3379
3380     if (!list) return FALSE;
3381     for (i = 0; list[i]; i++)
3382     {
3383         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3384     }
3385     retvalue = (list[i] != 0);
3386     HeapFree( GetProcessHeap(), 0, list );
3387     return retvalue;
3388 }
3389
3390
3391 /*******************************************************************
3392  *              FlashWindow (USER32.@)
3393  */
3394 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3395 {
3396     WND *wndPtr;
3397
3398     TRACE("%p\n", hWnd);
3399
3400     if (IsIconic( hWnd ))
3401     {
3402         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3403
3404         wndPtr = WIN_GetPtr(hWnd);
3405         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3406         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3407         {
3408             wndPtr->flags |= WIN_NCACTIVATED;
3409         }
3410         else
3411         {
3412             wndPtr->flags &= ~WIN_NCACTIVATED;
3413         }
3414         WIN_ReleasePtr( wndPtr );
3415         return TRUE;
3416     }
3417     else
3418     {
3419         WPARAM wparam;
3420
3421         wndPtr = WIN_GetPtr(hWnd);
3422         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3423         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3424
3425         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3426         else wparam = (hWnd == GetForegroundWindow());
3427
3428         WIN_ReleasePtr( wndPtr );
3429         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3430         return wparam;
3431     }
3432 }
3433
3434 /*******************************************************************
3435  *              FlashWindowEx (USER32.@)
3436  */
3437 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3438 {
3439     FIXME("%p\n", pfwi);
3440     return TRUE;
3441 }
3442
3443 /*******************************************************************
3444  *              GetWindowContextHelpId (USER32.@)
3445  */
3446 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3447 {
3448     DWORD retval;
3449     WND *wnd = WIN_GetPtr( hwnd );
3450     if (!wnd || wnd == WND_DESKTOP) return 0;
3451     if (wnd == WND_OTHER_PROCESS)
3452     {
3453         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3454         return 0;
3455     }
3456     retval = wnd->helpContext;
3457     WIN_ReleasePtr( wnd );
3458     return retval;
3459 }
3460
3461
3462 /*******************************************************************
3463  *              SetWindowContextHelpId (USER32.@)
3464  */
3465 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3466 {
3467     WND *wnd = WIN_GetPtr( hwnd );
3468     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3469     if (wnd == WND_OTHER_PROCESS)
3470     {
3471         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3472         return 0;
3473     }
3474     wnd->helpContext = id;
3475     WIN_ReleasePtr( wnd );
3476     return TRUE;
3477 }
3478
3479
3480 /*******************************************************************
3481  *              DragDetect (USER32.@)
3482  */
3483 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3484 {
3485     MSG msg;
3486     RECT rect;
3487     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3488     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3489
3490     rect.left = pt.x - wDragWidth;
3491     rect.right = pt.x + wDragWidth;
3492
3493     rect.top = pt.y - wDragHeight;
3494     rect.bottom = pt.y + wDragHeight;
3495
3496     SetCapture(hWnd);
3497
3498     while(1)
3499     {
3500         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3501         {
3502             if( msg.message == WM_LBUTTONUP )
3503             {
3504                 ReleaseCapture();
3505                 return 0;
3506             }
3507             if( msg.message == WM_MOUSEMOVE )
3508             {
3509                 POINT tmp;
3510                 tmp.x = (short)LOWORD(msg.lParam);
3511                 tmp.y = (short)HIWORD(msg.lParam);
3512                 if( !PtInRect( &rect, tmp ))
3513                 {
3514                     ReleaseCapture();
3515                     return 1;
3516                 }
3517             }
3518         }
3519         WaitMessage();
3520     }
3521     return 0;
3522 }
3523
3524 /******************************************************************************
3525  *              GetWindowModuleFileNameA (USER32.@)
3526  */
3527 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3528 {
3529     WND *win;
3530     HINSTANCE hinst;
3531
3532     TRACE( "%p, %p, %u\n", hwnd, module, size );
3533
3534     win = WIN_GetPtr( hwnd );
3535     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3536     {
3537         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3538         return 0;
3539     }
3540     hinst = win->hInstance;
3541     WIN_ReleasePtr( win );
3542
3543     return GetModuleFileNameA( hinst, module, size );
3544 }
3545
3546 /******************************************************************************
3547  *              GetWindowModuleFileNameW (USER32.@)
3548  */
3549 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3550 {
3551     WND *win;
3552     HINSTANCE hinst;
3553
3554     TRACE( "%p, %p, %u\n", hwnd, module, size );
3555
3556     win = WIN_GetPtr( hwnd );
3557     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3558     {
3559         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3560         return 0;
3561     }
3562     hinst = win->hInstance;
3563     WIN_ReleasePtr( win );
3564
3565     return GetModuleFileNameW( hinst, module, size );
3566 }
3567
3568 /******************************************************************************
3569  *              GetWindowInfo (USER32.@)
3570  *
3571  * Note: tests show that Windows doesn't check cbSize of the structure.
3572  */
3573 BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3574 {
3575     if (!pwi) return FALSE;
3576     if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3577
3578     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3579     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3580     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3581
3582     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3583     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3584
3585     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3586     pwi->wCreatorVersion = 0x0400;
3587
3588     return TRUE;
3589 }
3590
3591 /******************************************************************************
3592  *              SwitchDesktop (USER32.@)
3593  *
3594  * NOTES: Sets the current input or interactive desktop.
3595  */
3596 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3597 {
3598     FIXME("(hwnd %p) stub!\n", hDesktop);
3599     return TRUE;
3600 }
3601
3602
3603 /***********************************************************************
3604  *           __wine_set_pixel_format
3605  */
3606 BOOL CDECL __wine_set_pixel_format( HWND hwnd, int format )
3607 {
3608     WND *win = WIN_GetPtr( hwnd );
3609
3610     if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
3611     {
3612         WARN( "setting format %d on win %p not supported\n", format, hwnd );
3613         return FALSE;
3614     }
3615     win->pixel_format = format;
3616     WIN_ReleasePtr( win );
3617
3618     update_window_state( hwnd );
3619     return TRUE;
3620 }
3621
3622
3623 /*****************************************************************************
3624  *              SetLayeredWindowAttributes (USER32.@)
3625  */
3626 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3627 {
3628     BOOL ret;
3629
3630     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3631
3632     SERVER_START_REQ( set_window_layered_info )
3633     {
3634         req->handle = wine_server_user_handle( hwnd );
3635         req->color_key = key;
3636         req->alpha = alpha;
3637         req->flags = flags;
3638         ret = !wine_server_call_err( req );
3639     }
3640     SERVER_END_REQ;
3641
3642     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3643
3644     return ret;
3645 }
3646
3647
3648 /*****************************************************************************
3649  *              GetLayeredWindowAttributes (USER32.@)
3650  */
3651 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3652 {
3653     BOOL ret;
3654
3655     SERVER_START_REQ( get_window_layered_info )
3656     {
3657         req->handle = wine_server_user_handle( hwnd );
3658         if ((ret = !wine_server_call_err( req )))
3659         {
3660             if (key) *key = reply->color_key;
3661             if (alpha) *alpha = reply->alpha;
3662             if (flags) *flags = reply->flags;
3663         }
3664     }
3665     SERVER_END_REQ;
3666
3667     return ret;
3668 }
3669
3670
3671 /*****************************************************************************
3672  *              UpdateLayeredWindowIndirect  (USER32.@)
3673  */
3674 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3675 {
3676     DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
3677     RECT window_rect, client_rect;
3678     SIZE offset;
3679
3680     if (!info ||
3681         info->cbSize != sizeof(*info) ||
3682         info->dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
3683         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3684         GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3685     {
3686         SetLastError( ERROR_INVALID_PARAMETER );
3687         return FALSE;
3688     }
3689
3690     WIN_GetRectangles( hwnd, COORDS_PARENT, &window_rect, &client_rect );
3691
3692     if (info->pptDst)
3693     {
3694         offset.cx = info->pptDst->x - window_rect.left;
3695         offset.cy = info->pptDst->y - window_rect.top;
3696         OffsetRect( &client_rect, offset.cx, offset.cy );
3697         OffsetRect( &window_rect, offset.cx, offset.cy );
3698         flags &= ~SWP_NOMOVE;
3699     }
3700     if (info->psize)
3701     {
3702         offset.cx = info->psize->cx - (window_rect.right - window_rect.left);
3703         offset.cy = info->psize->cy - (window_rect.bottom - window_rect.top);
3704         if (info->psize->cx <= 0 || info->psize->cy <= 0)
3705         {
3706             SetLastError( ERROR_INVALID_PARAMETER );
3707             return FALSE;
3708         }
3709         if ((info->dwFlags & ULW_EX_NORESIZE) && (offset.cx || offset.cy))
3710         {
3711             SetLastError( ERROR_INCORRECT_SIZE );
3712             return FALSE;
3713         }
3714         client_rect.right  += offset.cx;
3715         client_rect.bottom += offset.cy;
3716         window_rect.right  += offset.cx;
3717         window_rect.bottom += offset.cy;
3718         flags &= ~SWP_NOSIZE;
3719     }
3720
3721     TRACE( "window %p win %s client %s\n", hwnd,
3722            wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(&client_rect) );
3723
3724     if (!USER_Driver->pUpdateLayeredWindow( hwnd, info, &window_rect )) return FALSE;
3725
3726     set_window_pos( hwnd, 0, flags, &window_rect, &client_rect, NULL );
3727     return TRUE;
3728 }
3729
3730
3731 /*****************************************************************************
3732  *              UpdateLayeredWindow (USER32.@)
3733  */
3734 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3735                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3736                                  DWORD flags)
3737 {
3738     UPDATELAYEREDWINDOWINFO info;
3739
3740     if (flags & ULW_EX_NORESIZE)  /* only valid for UpdateLayeredWindowIndirect */
3741     {
3742         SetLastError( ERROR_INVALID_PARAMETER );
3743         return FALSE;
3744     }
3745     info.cbSize   = sizeof(info);
3746     info.hdcDst   = hdcDst;
3747     info.pptDst   = pptDst;
3748     info.psize    = psize;
3749     info.hdcSrc   = hdcSrc;
3750     info.pptSrc   = pptSrc;
3751     info.crKey    = crKey;
3752     info.pblend   = pblend;
3753     info.dwFlags  = flags;
3754     info.prcDirty = NULL;
3755     return UpdateLayeredWindowIndirect( hwnd, &info );
3756 }
3757
3758
3759 /******************************************************************************
3760  *                    GetProcessDefaultLayout [USER32.@]
3761  *
3762  * Gets the default layout for parentless windows.
3763  */
3764 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3765 {
3766     if (!layout)
3767     {
3768         SetLastError( ERROR_NOACCESS );
3769         return FALSE;
3770     }
3771     if (process_layout == ~0u)
3772     {
3773         static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3774                                               '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3775         static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3776                                            '\\','%','0','4','x','%','0','4','x',
3777                                            '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3778         WCHAR *str, buffer[MAX_PATH];
3779         DWORD i, len, version_layout = 0;
3780         DWORD user_lang = GetUserDefaultLangID();
3781         DWORD *languages;
3782         void *data = NULL;
3783
3784         GetModuleFileNameW( 0, buffer, MAX_PATH );
3785         if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3786         if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3787         if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3788         if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3789
3790         len /= sizeof(DWORD);
3791         for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3792         if (i == len)  /* try neutral language */
3793             for (i = 0; i < len; i++)
3794                 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3795         if (i == len) i = 0;  /* default to the first one */
3796
3797         sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3798         if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3799         TRACE( "found description %s\n", debugstr_w( str ));
3800         if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3801
3802     done:
3803         HeapFree( GetProcessHeap(), 0, data );
3804         process_layout = version_layout;
3805     }
3806     *layout = process_layout;
3807     return TRUE;
3808 }
3809
3810
3811 /******************************************************************************
3812  *                    SetProcessDefaultLayout [USER32.@]
3813  *
3814  * Sets the default layout for parentless windows.
3815  */
3816 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3817 {
3818     process_layout = layout;
3819     return TRUE;
3820 }
3821
3822
3823 /* 64bit versions */
3824
3825 #ifdef GetWindowLongPtrW
3826 #undef GetWindowLongPtrW
3827 #endif
3828
3829 #ifdef GetWindowLongPtrA
3830 #undef GetWindowLongPtrA
3831 #endif
3832
3833 #ifdef SetWindowLongPtrW
3834 #undef SetWindowLongPtrW
3835 #endif
3836
3837 #ifdef SetWindowLongPtrA
3838 #undef SetWindowLongPtrA
3839 #endif
3840
3841 /*****************************************************************************
3842  *              GetWindowLongPtrW (USER32.@)
3843  */
3844 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3845 {
3846     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3847 }
3848
3849 /*****************************************************************************
3850  *              GetWindowLongPtrA (USER32.@)
3851  */
3852 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3853 {
3854     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3855 }
3856
3857 /*****************************************************************************
3858  *              SetWindowLongPtrW (USER32.@)
3859  */
3860 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3861 {
3862     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3863 }
3864
3865 /*****************************************************************************
3866  *              SetWindowLongPtrA (USER32.@)
3867  */
3868 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3869 {
3870     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3871 }