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