user32: Fix some failures in the MDI message test.
[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 "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "winproc.h"
37 #include "user_private.h"
38 #include "controls.h"
39 #include "winerror.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(win);
43
44 #define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
45 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
46
47 /**********************************************************************/
48
49 /* helper for Get/SetWindowLong */
50 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 {
52     if (size == sizeof(WORD))
53     {
54         WORD ret;
55         memcpy( &ret, ptr, sizeof(ret) );
56         return ret;
57     }
58     else if (size == sizeof(DWORD))
59     {
60         DWORD ret;
61         memcpy( &ret, ptr, sizeof(ret) );
62         return ret;
63     }
64     else
65     {
66         LONG_PTR ret;
67         memcpy( &ret, ptr, sizeof(ret) );
68         return ret;
69     }
70 }
71
72 /* helper for Get/SetWindowLong */
73 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 {
75     if (size == sizeof(WORD))
76     {
77         WORD newval = val;
78         memcpy( ptr, &newval, sizeof(newval) );
79     }
80     else if (size == sizeof(DWORD))
81     {
82         DWORD newval = val;
83         memcpy( ptr, &newval, sizeof(newval) );
84     }
85     else
86     {
87         memcpy( ptr, &val, sizeof(val) );
88     }
89 }
90
91
92 static void *user_handles[NB_USER_HANDLES];
93
94 /***********************************************************************
95  *           create_window_handle
96  *
97  * Create a window handle with the server.
98  */
99 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
100                                   HINSTANCE instance, BOOL unicode )
101 {
102     WORD index;
103     WND *win;
104     HWND full_parent = 0, full_owner = 0;
105     struct tagCLASS *class = NULL;
106     user_handle_t handle = 0;
107     int extra_bytes = 0;
108
109     /* if 16-bit instance, map to module handle */
110     if (instance && !HIWORD(instance))
111         instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
112
113     SERVER_START_REQ( create_window )
114     {
115         req->parent   = parent;
116         req->owner    = owner;
117         req->atom     = atom;
118         req->instance = instance;
119         if (!wine_server_call_err( req ))
120         {
121             handle = reply->handle;
122             full_parent = reply->parent;
123             full_owner  = reply->owner;
124             extra_bytes = reply->extra;
125             class = reply->class_ptr;
126         }
127     }
128     SERVER_END_REQ;
129
130     if (!handle)
131     {
132         WARN( "error %d creating window\n", GetLastError() );
133         return NULL;
134     }
135
136     if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
137     {
138         SERVER_START_REQ( destroy_window )
139         {
140             req->handle = handle;
141             wine_server_call( req );
142         }
143         SERVER_END_REQ;
144         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
145         return NULL;
146     }
147
148     if (!parent)  /* if parent is 0 we don't have a desktop window yet */
149     {
150         struct user_thread_info *thread_info = get_user_thread_info();
151
152         assert( !thread_info->desktop );
153         thread_info->desktop = full_parent ? full_parent : handle;
154         if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
155             ERR( "failed to create desktop window\n" );
156     }
157
158     USER_Lock();
159
160     index = USER_HANDLE_TO_INDEX(handle);
161     assert( index < NB_USER_HANDLES );
162     user_handles[index] = win;
163     win->hwndSelf   = handle;
164     win->parent     = full_parent;
165     win->owner      = full_owner;
166     win->dwMagic    = WND_MAGIC;
167     win->flags      = 0;
168     win->cbWndExtra = extra_bytes;
169     memset( win->wExtra, 0, extra_bytes );
170     CLASS_AddWindow( class, win, unicode );
171     return win;
172 }
173
174
175 /***********************************************************************
176  *           free_window_handle
177  *
178  * Free a window handle.
179  */
180 static WND *free_window_handle( HWND hwnd )
181 {
182     WND *ptr;
183     WORD index = USER_HANDLE_TO_INDEX(hwnd);
184
185     if (index >= NB_USER_HANDLES) return NULL;
186     USER_Lock();
187     if ((ptr = user_handles[index]))
188     {
189         SERVER_START_REQ( destroy_window )
190         {
191             req->handle = hwnd;
192             if (!wine_server_call_err( req ))
193             {
194                 user_handles[index] = NULL;
195                 ptr->dwMagic = 0;
196             }
197             else
198                 ptr = NULL;
199         }
200         SERVER_END_REQ;
201     }
202     USER_Unlock();
203     HeapFree( GetProcessHeap(), 0, ptr );
204     return ptr;
205 }
206
207
208 /*******************************************************************
209  *           list_window_children
210  *
211  * Build an array of the children of a given window. The array must be
212  * freed with HeapFree. Returns NULL when no windows are found.
213  */
214 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
215 {
216     HWND *list;
217     int size = 32;
218
219     for (;;)
220     {
221         int count = 0;
222
223         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
224
225         SERVER_START_REQ( get_window_children )
226         {
227             req->parent = hwnd;
228             req->atom = atom;
229             req->tid = tid;
230             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
231             if (!wine_server_call( req )) count = reply->count;
232         }
233         SERVER_END_REQ;
234         if (count && count < size)
235         {
236             list[count] = 0;
237             return list;
238         }
239         HeapFree( GetProcessHeap(), 0, list );
240         if (!count) break;
241         size = count + 1;  /* restart with a large enough buffer */
242     }
243     return NULL;
244 }
245
246
247 /*******************************************************************
248  *           list_window_parents
249  *
250  * Build an array of all parents of a given window, starting with
251  * the immediate parent. The array must be freed with HeapFree.
252  */
253 static HWND *list_window_parents( HWND hwnd )
254 {
255     WND *win;
256     HWND current, *list;
257     int pos = 0, size = 16, count = 0;
258
259     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
260
261     current = hwnd;
262     for (;;)
263     {
264         if (!(win = WIN_GetPtr( current ))) goto empty;
265         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
266         if (win == WND_DESKTOP)
267         {
268             if (!pos) goto empty;
269             list[pos] = 0;
270             return list;
271         }
272         list[pos] = current = win->parent;
273         WIN_ReleasePtr( win );
274         if (++pos == size - 1)
275         {
276             /* need to grow the list */
277             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
278             if (!new_list) goto empty;
279             list = new_list;
280             size += 16;
281         }
282     }
283
284     /* at least one parent belongs to another process, have to query the server */
285
286     for (;;)
287     {
288         count = 0;
289         SERVER_START_REQ( get_window_parents )
290         {
291             req->handle = hwnd;
292             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
293             if (!wine_server_call( req )) count = reply->count;
294         }
295         SERVER_END_REQ;
296         if (!count) goto empty;
297         if (size > count)
298         {
299             list[count] = 0;
300             return list;
301         }
302         HeapFree( GetProcessHeap(), 0, list );
303         size = count + 1;
304         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
305     }
306
307  empty:
308     HeapFree( GetProcessHeap(), 0, list );
309     return NULL;
310 }
311
312
313 /*******************************************************************
314  *           send_parent_notify
315  */
316 static void send_parent_notify( HWND hwnd, UINT msg )
317 {
318     if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
319         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
320     {
321         HWND parent = GetParent(hwnd);
322         if (parent && parent != GetDesktopWindow())
323             SendMessageW( parent, WM_PARENTNOTIFY,
324                           MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
325     }
326 }
327
328
329 /*******************************************************************
330  *              get_server_window_text
331  *
332  * Retrieve the window text from the server.
333  */
334 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
335 {
336     size_t len = 0;
337
338     SERVER_START_REQ( get_window_text )
339     {
340         req->handle = hwnd;
341         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
342         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
343     }
344     SERVER_END_REQ;
345     text[len / sizeof(WCHAR)] = 0;
346 }
347
348
349 /***********************************************************************
350  *           WIN_GetPtr
351  *
352  * Return a pointer to the WND structure if local to the process,
353  * or WND_OTHER_PROCESS if handle may be valid in other process.
354  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
355  */
356 WND *WIN_GetPtr( HWND hwnd )
357 {
358     WND * ptr;
359     WORD index = USER_HANDLE_TO_INDEX(hwnd);
360
361     if (index >= NB_USER_HANDLES) return NULL;
362
363     USER_Lock();
364     if ((ptr = user_handles[index]))
365     {
366         if (ptr->dwMagic == WND_MAGIC &&
367             (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
368             return ptr;
369         ptr = NULL;
370     }
371     else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
372     {
373         if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
374         else ptr = NULL;
375     }
376     else ptr = WND_OTHER_PROCESS;
377     USER_Unlock();
378     return ptr;
379 }
380
381
382 /***********************************************************************
383  *           WIN_IsCurrentProcess
384  *
385  * Check whether a given window belongs to the current process (and return the full handle).
386  */
387 HWND WIN_IsCurrentProcess( HWND hwnd )
388 {
389     WND *ptr;
390     HWND ret;
391
392     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
393     ret = ptr->hwndSelf;
394     WIN_ReleasePtr( ptr );
395     return ret;
396 }
397
398
399 /***********************************************************************
400  *           WIN_IsCurrentThread
401  *
402  * Check whether a given window belongs to the current thread (and return the full handle).
403  */
404 HWND WIN_IsCurrentThread( HWND hwnd )
405 {
406     WND *ptr;
407     HWND ret = 0;
408
409     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
410     if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
411     WIN_ReleasePtr( ptr );
412     return ret;
413 }
414
415
416 /***********************************************************************
417  *           WIN_Handle32
418  *
419  * Convert a 16-bit window handle to a full 32-bit handle.
420  */
421 HWND WIN_Handle32( HWND16 hwnd16 )
422 {
423     WND *ptr;
424     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
425
426     if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
427     /* do sign extension for -2 and -3 */
428     if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
429
430     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
431
432     if (ptr == WND_DESKTOP) return GetDesktopWindow();
433
434     if (ptr != WND_OTHER_PROCESS)
435     {
436         hwnd = ptr->hwndSelf;
437         WIN_ReleasePtr( ptr );
438     }
439     else  /* may belong to another process */
440     {
441         SERVER_START_REQ( get_window_info )
442         {
443             req->handle = hwnd;
444             if (!wine_server_call_err( req )) hwnd = reply->full_handle;
445         }
446         SERVER_END_REQ;
447     }
448     return hwnd;
449 }
450
451
452 /***********************************************************************
453  *           WIN_SetOwner
454  *
455  * Change the owner of a window.
456  */
457 HWND WIN_SetOwner( HWND hwnd, HWND owner )
458 {
459     WND *win = WIN_GetPtr( hwnd );
460     HWND ret = 0;
461
462     if (!win || win == WND_DESKTOP) return 0;
463     if (win == WND_OTHER_PROCESS)
464     {
465         if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
466         return 0;
467     }
468     SERVER_START_REQ( set_window_owner )
469     {
470         req->handle = hwnd;
471         req->owner  = owner;
472         if (!wine_server_call( req ))
473         {
474             win->owner = reply->full_owner;
475             ret = reply->prev_owner;
476         }
477     }
478     SERVER_END_REQ;
479     WIN_ReleasePtr( win );
480     return ret;
481 }
482
483
484 /***********************************************************************
485  *           WIN_SetStyle
486  *
487  * Change the style of a window.
488  */
489 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
490 {
491     BOOL ok;
492     ULONG new_style, old_style = 0;
493     WND *win = WIN_GetPtr( hwnd );
494
495     if (!win || win == WND_DESKTOP) return 0;
496     if (win == WND_OTHER_PROCESS)
497     {
498         if (IsWindow(hwnd))
499             ERR( "cannot set style %x/%x on other process window %p\n",
500                  set_bits, clear_bits, hwnd );
501         return 0;
502     }
503     new_style = (win->dwStyle | set_bits) & ~clear_bits;
504     if (new_style == win->dwStyle)
505     {
506         WIN_ReleasePtr( win );
507         return new_style;
508     }
509     SERVER_START_REQ( set_window_info )
510     {
511         req->handle = hwnd;
512         req->flags  = SET_WIN_STYLE;
513         req->style  = new_style;
514         req->extra_offset = -1;
515         if ((ok = !wine_server_call( req )))
516         {
517             old_style = reply->old_style;
518             win->dwStyle = new_style;
519         }
520     }
521     SERVER_END_REQ;
522     WIN_ReleasePtr( win );
523     if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
524     return old_style;
525 }
526
527
528 /***********************************************************************
529  *           WIN_GetRectangles
530  *
531  * Get the window and client rectangles.
532  */
533 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
534 {
535     WND *win = WIN_GetPtr( hwnd );
536     BOOL ret = TRUE;
537
538     if (!win) return FALSE;
539     if (win == WND_DESKTOP)
540     {
541         RECT rect;
542         rect.left = rect.top = 0;
543         rect.right  = GetSystemMetrics(SM_CXSCREEN);
544         rect.bottom = GetSystemMetrics(SM_CYSCREEN);
545         if (rectWindow) *rectWindow = rect;
546         if (rectClient) *rectClient = rect;
547     }
548     else if (win == WND_OTHER_PROCESS)
549     {
550         SERVER_START_REQ( get_window_rectangles )
551         {
552             req->handle = hwnd;
553             if ((ret = !wine_server_call( req )))
554             {
555                 if (rectWindow)
556                 {
557                     rectWindow->left   = reply->window.left;
558                     rectWindow->top    = reply->window.top;
559                     rectWindow->right  = reply->window.right;
560                     rectWindow->bottom = reply->window.bottom;
561                 }
562                 if (rectClient)
563                 {
564                     rectClient->left   = reply->client.left;
565                     rectClient->top    = reply->client.top;
566                     rectClient->right  = reply->client.right;
567                     rectClient->bottom = reply->client.bottom;
568                 }
569             }
570         }
571         SERVER_END_REQ;
572     }
573     else
574     {
575         if (rectWindow) *rectWindow = win->rectWindow;
576         if (rectClient) *rectClient = win->rectClient;
577         WIN_ReleasePtr( win );
578     }
579     return ret;
580 }
581
582
583 /***********************************************************************
584  *           WIN_DestroyWindow
585  *
586  * Destroy storage associated to a window. "Internals" p.358
587  */
588 LRESULT WIN_DestroyWindow( HWND hwnd )
589 {
590     WND *wndPtr;
591     HWND *list;
592     HMENU menu = 0, sys_menu;
593
594     TRACE("%p\n", hwnd );
595
596     /* free child windows */
597     if ((list = WIN_ListChildren( hwnd )))
598     {
599         int i;
600         for (i = 0; list[i]; i++)
601         {
602             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
603             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
604         }
605         HeapFree( GetProcessHeap(), 0, list );
606     }
607
608     /* Unlink now so we won't bother with the children later on */
609     SERVER_START_REQ( set_parent )
610     {
611         req->handle = hwnd;
612         req->parent = 0;
613         wine_server_call( req );
614     }
615     SERVER_END_REQ;
616
617     /*
618      * Send the WM_NCDESTROY to the window being destroyed.
619      */
620     SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
621
622     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
623
624     WINPOS_CheckInternalPos( hwnd );
625
626     /* free resources associated with the window */
627
628     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
629     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
630         menu = (HMENU)wndPtr->wIDmenu;
631     sys_menu = wndPtr->hSysMenu;
632     WIN_ReleasePtr( wndPtr );
633
634     if (menu) DestroyMenu( menu );
635     if (sys_menu) DestroyMenu( sys_menu );
636
637     USER_Driver->pDestroyWindow( hwnd );
638
639     free_window_handle( hwnd );
640     return 0;
641 }
642
643 /***********************************************************************
644  *           WIN_DestroyThreadWindows
645  *
646  * Destroy all children of 'wnd' owned by the current thread.
647  */
648 void WIN_DestroyThreadWindows( HWND hwnd )
649 {
650     HWND *list;
651     int i;
652
653     if (!(list = WIN_ListChildren( hwnd ))) return;
654     for (i = 0; list[i]; i++)
655     {
656         if (WIN_IsCurrentThread( list[i] ))
657             DestroyWindow( list[i] );
658         else
659             WIN_DestroyThreadWindows( list[i] );
660     }
661     HeapFree( GetProcessHeap(), 0, list );
662 }
663
664
665 /***********************************************************************
666  *           WIN_FixCoordinates
667  *
668  * Fix the coordinates - Helper for WIN_CreateWindowEx.
669  * returns default show mode in sw.
670  */
671 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
672 {
673 #define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
674     POINT pos[2];
675
676     if (cs->dwExStyle & WS_EX_MDICHILD)
677     {
678         UINT id = 0;
679
680         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
681         if (!(cs->style & WS_POPUP)) cs->hMenu = (HMENU)id;
682
683         TRACE("MDI child id %04x\n", id);
684     }
685
686     if (cs->style & (WS_CHILD | WS_POPUP))
687     {
688         if (cs->dwExStyle & WS_EX_MDICHILD)
689         {
690             if (IS_DEFAULT(cs->x))
691             {
692                 cs->x = pos[0].x;
693                 cs->y = pos[0].y;
694             }
695             if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
696             if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
697         }
698         else
699         {
700             if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
701             if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
702         }
703     }
704     else  /* overlapped window */
705     {
706         HMONITOR monitor;
707         MONITORINFO mon_info;
708         STARTUPINFOW info;
709
710         if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
711
712         monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
713         mon_info.cbSize = sizeof(mon_info);
714         GetMonitorInfoW( monitor, &mon_info );
715         GetStartupInfoW( &info );
716
717         if (IS_DEFAULT(cs->x))
718         {
719             if (!IS_DEFAULT(cs->y)) *sw = cs->y;
720             cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
721             cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
722         }
723
724         if (IS_DEFAULT(cs->cx))
725         {
726             if (info.dwFlags & STARTF_USESIZE)
727             {
728                 cs->cx = info.dwXSize;
729                 cs->cy = info.dwYSize;
730             }
731             else
732             {
733                 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
734                 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
735             }
736         }
737         /* neither x nor cx are default. Check the y values .
738          * In the trace we see Outlook and Outlook Express using
739          * cy set to CW_USEDEFAULT when opening the address book.
740          */
741         else if (IS_DEFAULT(cs->cy))
742         {
743             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
744             cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
745         }
746     }
747 #undef IS_DEFAULT
748 }
749
750 /***********************************************************************
751  *           dump_window_styles
752  */
753 static void dump_window_styles( DWORD style, DWORD exstyle )
754 {
755     TRACE( "style:" );
756     if(style & WS_POPUP) TRACE(" WS_POPUP");
757     if(style & WS_CHILD) TRACE(" WS_CHILD");
758     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
759     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
760     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
761     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
762     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
763     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
764     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
765     else
766     {
767         if(style & WS_BORDER) TRACE(" WS_BORDER");
768         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
769     }
770     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
771     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
772     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
773     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
774     if (style & WS_CHILD)
775     {
776         if(style & WS_GROUP) TRACE(" WS_GROUP");
777         if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
778     }
779     else
780     {
781         if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
782         if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
783     }
784
785     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
786 #define DUMPED_STYLES \
787     (WS_POPUP | \
788      WS_CHILD | \
789      WS_MINIMIZE | \
790      WS_VISIBLE | \
791      WS_DISABLED | \
792      WS_CLIPSIBLINGS | \
793      WS_CLIPCHILDREN | \
794      WS_MAXIMIZE | \
795      WS_BORDER | \
796      WS_DLGFRAME | \
797      WS_VSCROLL | \
798      WS_HSCROLL | \
799      WS_SYSMENU | \
800      WS_THICKFRAME | \
801      WS_GROUP | \
802      WS_TABSTOP | \
803      WS_MINIMIZEBOX | \
804      WS_MAXIMIZEBOX)
805
806     if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
807     TRACE("\n");
808 #undef DUMPED_STYLES
809
810     TRACE( "exstyle:" );
811     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
812     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
813     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
814     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
815     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
816     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
817     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
818     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
819     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
820     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
821     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
822     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
823     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
824     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
825     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
826     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
827     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
828     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
829
830 #define DUMPED_EX_STYLES \
831     (WS_EX_DLGMODALFRAME | \
832      WS_EX_DRAGDETECT | \
833      WS_EX_NOPARENTNOTIFY | \
834      WS_EX_TOPMOST | \
835      WS_EX_ACCEPTFILES | \
836      WS_EX_TRANSPARENT | \
837      WS_EX_MDICHILD | \
838      WS_EX_TOOLWINDOW | \
839      WS_EX_WINDOWEDGE | \
840      WS_EX_CLIENTEDGE | \
841      WS_EX_CONTEXTHELP | \
842      WS_EX_RIGHT | \
843      WS_EX_RTLREADING | \
844      WS_EX_LEFTSCROLLBAR | \
845      WS_EX_CONTROLPARENT | \
846      WS_EX_STATICEDGE | \
847      WS_EX_APPWINDOW | \
848      WS_EX_LAYERED)
849
850     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
851     TRACE("\n");
852 #undef DUMPED_EX_STYLES
853 }
854
855
856 /***********************************************************************
857  *           WIN_CreateWindowEx
858  *
859  * Implementation of CreateWindowEx().
860  */
861 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, UINT flags )
862 {
863     INT sw = SW_SHOW;
864     WND *wndPtr;
865     HWND hwnd, parent, owner, top_child = 0;
866     BOOL unicode = (flags & WIN_ISUNICODE) != 0;
867     MDICREATESTRUCTA mdi_cs;
868
869     TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
870           unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
871           unicode ? debugstr_w((LPCWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
872           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
873           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
874     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
875
876     /* Fix the styles for MDI children */
877     if (cs->dwExStyle & WS_EX_MDICHILD)
878     {
879         UINT flags = 0;
880
881         wndPtr = WIN_GetPtr(cs->hwndParent);
882         if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
883         {
884             flags = wndPtr->flags;
885             WIN_ReleasePtr(wndPtr);
886         }
887
888         if (!(flags & WIN_ISMDICLIENT))
889         {
890             WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
891             return 0;
892         }
893
894         /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
895          * MDICREATESTRUCT members have the originally passed values.
896          *
897          * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
898          * have the same layout.
899          */
900         mdi_cs.szClass = cs->lpszClass;
901         mdi_cs.szTitle = cs->lpszName;
902         mdi_cs.hOwner = cs->hInstance;
903         mdi_cs.x = cs->x;
904         mdi_cs.y = cs->y;
905         mdi_cs.cx = cs->cx;
906         mdi_cs.cy = cs->cy;
907         mdi_cs.style = cs->style;
908         mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
909
910         cs->lpCreateParams = (LPVOID)&mdi_cs;
911
912         if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
913         {
914             if (cs->style & WS_POPUP)
915             {
916                 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
917                 return 0;
918             }
919             cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
920         }
921         else
922         {
923             cs->style &= ~WS_POPUP;
924             cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
925                 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
926         }
927
928         top_child = GetWindow(cs->hwndParent, GW_CHILD);
929
930         if (top_child)
931         {
932             /* Restore current maximized child */
933             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
934             {
935                 TRACE("Restoring current maximized child %p\n", top_child);
936                 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
937                 ShowWindow( top_child, SW_SHOWNORMAL );
938                 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
939             }
940         }
941     }
942
943     /* Find the parent window */
944
945     parent = cs->hwndParent;
946     owner = 0;
947
948     if (cs->hwndParent == HWND_MESSAGE)
949     {
950       /* native ole32.OleInitialize uses HWND_MESSAGE to create the
951        * message window (style: WS_POPUP|WS_DISABLED)
952        */
953       FIXME("Parent is HWND_MESSAGE\n");
954       parent = GetDesktopWindow();
955     }
956     else if (cs->hwndParent)
957     {
958         if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
959         {
960             parent = GetDesktopWindow();
961             owner = cs->hwndParent;
962         }
963     }
964     else
965     {
966         if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
967         {
968             WARN("No parent for child window\n" );
969             SetLastError(ERROR_TLW_WITH_WSCHILD);
970             return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
971         }
972         if (classAtom != LOWORD(DESKTOP_CLASS_ATOM))  /* are we creating the desktop itself? */
973             parent = GetDesktopWindow();
974     }
975
976     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
977
978     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
979         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
980           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
981         cs->dwExStyle |= WS_EX_WINDOWEDGE;
982     else
983         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
984
985     /* Create the window structure */
986
987     if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, unicode )))
988         return 0;
989     hwnd = wndPtr->hwndSelf;
990
991     /* Fill the window structure */
992
993     wndPtr->tid            = GetCurrentThreadId();
994     wndPtr->hInstance      = cs->hInstance;
995     wndPtr->text           = NULL;
996     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
997     wndPtr->dwExStyle      = cs->dwExStyle;
998     wndPtr->wIDmenu        = 0;
999     wndPtr->helpContext    = 0;
1000     wndPtr->pVScroll       = NULL;
1001     wndPtr->pHScroll       = NULL;
1002     wndPtr->userdata       = 0;
1003     wndPtr->hIcon          = 0;
1004     wndPtr->hIconSmall     = 0;
1005     wndPtr->hSysMenu       = 0;
1006     wndPtr->flags         |= (flags & WIN_ISWIN32);
1007
1008     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1009
1010     /*
1011      * Correct the window styles.
1012      *
1013      * It affects only the style loaded into the WIN structure.
1014      */
1015
1016     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1017     {
1018         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1019         if (!(wndPtr->dwStyle & WS_POPUP))
1020             wndPtr->dwStyle |= WS_CAPTION;
1021     }
1022
1023     /*
1024      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1025      * why does the user get to set it?
1026      */
1027
1028     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1029           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1030         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1031     else
1032         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1033
1034     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1035         wndPtr->flags |= WIN_NEED_SIZE;
1036
1037     SERVER_START_REQ( set_window_info )
1038     {
1039         req->handle    = hwnd;
1040         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1041         req->style     = wndPtr->dwStyle;
1042         req->ex_style  = wndPtr->dwExStyle;
1043         req->instance  = (void *)wndPtr->hInstance;
1044         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1045         req->extra_offset = -1;
1046         wine_server_call( req );
1047     }
1048     SERVER_END_REQ;
1049
1050     /* Set the window menu */
1051
1052     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1053     {
1054         if (cs->hMenu)
1055         {
1056             if (!MENU_SetMenu(hwnd, cs->hMenu))
1057             {
1058                 WIN_ReleasePtr( wndPtr );
1059                 free_window_handle( hwnd );
1060                 return 0;
1061             }
1062         }
1063         else
1064         {
1065             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1066             if (menuName)
1067             {
1068                 if (!cs->hInstance || HIWORD(cs->hInstance))
1069                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1070                 else
1071                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1072
1073                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1074             }
1075         }
1076     }
1077     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1078     WIN_ReleasePtr( wndPtr );
1079
1080     if (!USER_Driver->pCreateWindow( hwnd, cs, unicode))
1081     {
1082         WIN_DestroyWindow( hwnd );
1083         return 0;
1084     }
1085
1086     /* Notify the parent window only */
1087
1088     send_parent_notify( hwnd, WM_CREATE );
1089     if (!IsWindow( hwnd )) return 0;
1090
1091     if (cs->style & WS_VISIBLE)
1092     {
1093         if (cs->style & WS_MAXIMIZE)
1094             sw = SW_SHOW;
1095         else if (cs->style & WS_MINIMIZE)
1096             sw = SW_SHOWMINIMIZED;
1097
1098         ShowWindow( hwnd, sw );
1099         if (cs->dwExStyle & WS_EX_MDICHILD)
1100         {
1101             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1102             /* ShowWindow won't activate child windows */
1103             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1104         }
1105     }
1106
1107     /* Call WH_SHELL hook */
1108
1109     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1110         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1111
1112     TRACE("created window %p\n", hwnd);
1113     return hwnd;
1114 }
1115
1116
1117 /***********************************************************************
1118  *              CreateWindow (USER.41)
1119  */
1120 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1121                               DWORD style, INT16 x, INT16 y, INT16 width,
1122                               INT16 height, HWND16 parent, HMENU16 menu,
1123                               HINSTANCE16 instance, LPVOID data )
1124 {
1125     return CreateWindowEx16( 0, className, windowName, style,
1126                              x, y, width, height, parent, menu, instance, data );
1127 }
1128
1129
1130 /***********************************************************************
1131  *              CreateWindowEx (USER.452)
1132  */
1133 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1134                                 LPCSTR windowName, DWORD style, INT16 x,
1135                                 INT16 y, INT16 width, INT16 height,
1136                                 HWND16 parent, HMENU16 menu,
1137                                 HINSTANCE16 instance, LPVOID data )
1138 {
1139     ATOM classAtom;
1140     CREATESTRUCTA cs;
1141     char buffer[256];
1142
1143     /* Find the class atom */
1144
1145     if (HIWORD(className))
1146     {
1147         if (!(classAtom = GlobalFindAtomA( className )))
1148         {
1149             ERR( "bad class name %s\n", debugstr_a(className) );
1150             return 0;
1151         }
1152     }
1153     else
1154     {
1155         classAtom = LOWORD(className);
1156         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1157         {
1158             ERR( "bad atom %x\n", classAtom);
1159             return 0;
1160         }
1161         className = buffer;
1162     }
1163
1164     /* Fix the coordinates */
1165
1166     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1167     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1168     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1169     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1170
1171     /* Create the window */
1172
1173     cs.lpCreateParams = data;
1174     cs.hInstance      = HINSTANCE_32(instance);
1175     cs.hMenu          = HMENU_32(menu);
1176     cs.hwndParent     = WIN_Handle32( parent );
1177     cs.style          = style;
1178     cs.lpszName       = windowName;
1179     cs.lpszClass      = className;
1180     cs.dwExStyle      = exStyle;
1181
1182     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, 0 ));
1183 }
1184
1185
1186 /***********************************************************************
1187  *              CreateWindowExA (USER32.@)
1188  */
1189 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1190                                  LPCSTR windowName, DWORD style, INT x,
1191                                  INT y, INT width, INT height,
1192                                  HWND parent, HMENU menu,
1193                                  HINSTANCE instance, LPVOID data )
1194 {
1195     ATOM classAtom;
1196     CREATESTRUCTA cs;
1197     char buffer[256];
1198
1199     /* Find the class atom */
1200
1201     if (HIWORD(className))
1202     {
1203         if (!(classAtom = GlobalFindAtomA( className )))
1204         {
1205             ERR( "bad class name %s\n", debugstr_a(className) );
1206             return 0;
1207         }
1208     }
1209     else
1210     {
1211         classAtom = LOWORD(className);
1212         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1213         {
1214             ERR( "bad atom %x\n", classAtom);
1215             return 0;
1216         }
1217         className = buffer;
1218     }
1219
1220     /* Create the window */
1221
1222     cs.lpCreateParams = data;
1223     cs.hInstance      = instance;
1224     cs.hMenu          = menu;
1225     cs.hwndParent     = parent;
1226     cs.x              = x;
1227     cs.y              = y;
1228     cs.cx             = width;
1229     cs.cy             = height;
1230     cs.style          = style;
1231     cs.lpszName       = windowName;
1232     cs.lpszClass      = className;
1233     cs.dwExStyle      = exStyle;
1234
1235     return WIN_CreateWindowEx( &cs, classAtom, WIN_ISWIN32 );
1236 }
1237
1238
1239 /***********************************************************************
1240  *              CreateWindowExW (USER32.@)
1241  */
1242 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1243                                  LPCWSTR windowName, DWORD style, INT x,
1244                                  INT y, INT width, INT height,
1245                                  HWND parent, HMENU menu,
1246                                  HINSTANCE instance, LPVOID data )
1247 {
1248     ATOM classAtom;
1249     CREATESTRUCTW cs;
1250     WCHAR buffer[256];
1251
1252     /* Find the class atom */
1253
1254     if (HIWORD(className))
1255     {
1256         if (!(classAtom = GlobalFindAtomW( className )))
1257         {
1258             ERR( "bad class name %s\n", debugstr_w(className) );
1259             return 0;
1260         }
1261     }
1262     else
1263     {
1264         classAtom = LOWORD(className);
1265         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1266         {
1267             ERR( "bad atom %x\n", classAtom);
1268             return 0;
1269         }
1270         className = buffer;
1271     }
1272
1273     /* Create the window */
1274
1275     cs.lpCreateParams = data;
1276     cs.hInstance      = instance;
1277     cs.hMenu          = menu;
1278     cs.hwndParent     = parent;
1279     cs.x              = x;
1280     cs.y              = y;
1281     cs.cx             = width;
1282     cs.cy             = height;
1283     cs.style          = style;
1284     cs.lpszName       = windowName;
1285     cs.lpszClass      = className;
1286     cs.dwExStyle      = exStyle;
1287
1288     /* Note: we rely on the fact that CREATESTRUCTA and */
1289     /* CREATESTRUCTW have the same layout. */
1290     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_ISWIN32 | WIN_ISUNICODE );
1291 }
1292
1293
1294 /***********************************************************************
1295  *           WIN_SendDestroyMsg
1296  */
1297 static void WIN_SendDestroyMsg( HWND hwnd )
1298 {
1299     GUITHREADINFO info;
1300
1301     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1302     {
1303         if (hwnd == info.hwndCaret) DestroyCaret();
1304         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1305     }
1306
1307     /*
1308      * Send the WM_DESTROY to the window.
1309      */
1310     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1311
1312     /*
1313      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1314      * make sure that the window still exists when we come back.
1315      */
1316     if (IsWindow(hwnd))
1317     {
1318         HWND* pWndArray;
1319         int i;
1320
1321         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1322
1323         for (i = 0; pWndArray[i]; i++)
1324         {
1325             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1326         }
1327         HeapFree( GetProcessHeap(), 0, pWndArray );
1328     }
1329     else
1330       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1331 }
1332
1333
1334 /***********************************************************************
1335  *              DestroyWindow (USER32.@)
1336  */
1337 BOOL WINAPI DestroyWindow( HWND hwnd )
1338 {
1339     BOOL is_child;
1340
1341     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1342     {
1343         SetLastError( ERROR_ACCESS_DENIED );
1344         return FALSE;
1345     }
1346
1347     TRACE("(%p)\n", hwnd);
1348
1349       /* Call hooks */
1350
1351     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1352
1353     if (MENU_IsMenuActive() == hwnd)
1354         EndMenu();
1355
1356     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1357
1358     if (is_child)
1359     {
1360         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1361             send_parent_notify( hwnd, WM_DESTROY );
1362     }
1363     else if (!GetWindow( hwnd, GW_OWNER ))
1364     {
1365         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1366         /* FIXME: clean up palette - see "Internals" p.352 */
1367     }
1368
1369     if (!IsWindow(hwnd)) return TRUE;
1370
1371       /* Hide the window */
1372     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1373     {
1374         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1375         if (is_child)
1376             ShowWindow( hwnd, SW_HIDE );
1377         else
1378             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1379                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1380     }
1381
1382     if (!IsWindow(hwnd)) return TRUE;
1383
1384       /* Recursively destroy owned windows */
1385
1386     if (!is_child)
1387     {
1388         for (;;)
1389         {
1390             int i, got_one = 0;
1391             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1392             if (list)
1393             {
1394                 for (i = 0; list[i]; i++)
1395                 {
1396                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1397                     if (WIN_IsCurrentThread( list[i] ))
1398                     {
1399                         DestroyWindow( list[i] );
1400                         got_one = 1;
1401                         continue;
1402                     }
1403                     WIN_SetOwner( list[i], 0 );
1404                 }
1405                 HeapFree( GetProcessHeap(), 0, list );
1406             }
1407             if (!got_one) break;
1408         }
1409     }
1410
1411       /* Send destroy messages */
1412
1413     WIN_SendDestroyMsg( hwnd );
1414     if (!IsWindow( hwnd )) return TRUE;
1415
1416     if (GetClipboardOwner() == hwnd)
1417         CLIPBOARD_ReleaseOwner();
1418
1419       /* Destroy the window storage */
1420
1421     WIN_DestroyWindow( hwnd );
1422     return TRUE;
1423 }
1424
1425
1426 /***********************************************************************
1427  *              CloseWindow (USER32.@)
1428  */
1429 BOOL WINAPI CloseWindow( HWND hwnd )
1430 {
1431     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1432     ShowWindow( hwnd, SW_MINIMIZE );
1433     return TRUE;
1434 }
1435
1436
1437 /***********************************************************************
1438  *              OpenIcon (USER32.@)
1439  */
1440 BOOL WINAPI OpenIcon( HWND hwnd )
1441 {
1442     if (!IsIconic( hwnd )) return FALSE;
1443     ShowWindow( hwnd, SW_SHOWNORMAL );
1444     return TRUE;
1445 }
1446
1447
1448 /***********************************************************************
1449  *           WIN_FindWindow
1450  *
1451  * Implementation of FindWindow() and FindWindowEx().
1452  */
1453 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1454 {
1455     HWND *list = NULL;
1456     HWND retvalue = 0;
1457     int i = 0, len = 0;
1458     WCHAR *buffer = NULL;
1459
1460     if (!parent) parent = GetDesktopWindow();
1461     if (title)
1462     {
1463         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1464         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1465     }
1466
1467     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1468
1469     if (child)
1470     {
1471         child = WIN_GetFullHandle( child );
1472         while (list[i] && list[i] != child) i++;
1473         if (!list[i]) goto done;
1474         i++;  /* start from next window */
1475     }
1476
1477     if (title)
1478     {
1479         while (list[i])
1480         {
1481             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1482             i++;
1483         }
1484     }
1485     retvalue = list[i];
1486
1487  done:
1488     HeapFree( GetProcessHeap(), 0, list );
1489     HeapFree( GetProcessHeap(), 0, buffer );
1490     return retvalue;
1491 }
1492
1493
1494
1495 /***********************************************************************
1496  *              FindWindowA (USER32.@)
1497  */
1498 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1499 {
1500     HWND ret = FindWindowExA( 0, 0, className, title );
1501     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1502     return ret;
1503 }
1504
1505
1506 /***********************************************************************
1507  *              FindWindowExA (USER32.@)
1508  */
1509 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1510                                LPCSTR className, LPCSTR title )
1511 {
1512     ATOM atom = 0;
1513     LPWSTR buffer;
1514     HWND hwnd;
1515     INT len;
1516
1517     if (className)
1518     {
1519         /* If the atom doesn't exist, then no class */
1520         /* with this name exists either. */
1521         if (!(atom = GlobalFindAtomA( className )))
1522         {
1523             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1524             return 0;
1525         }
1526     }
1527     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1528
1529     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1530     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1531     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1532     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1533     HeapFree( GetProcessHeap(), 0, buffer );
1534     return hwnd;
1535 }
1536
1537
1538 /***********************************************************************
1539  *              FindWindowExW (USER32.@)
1540  */
1541 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1542                                LPCWSTR className, LPCWSTR title )
1543 {
1544     ATOM atom = 0;
1545
1546     if (className)
1547     {
1548         /* If the atom doesn't exist, then no class */
1549         /* with this name exists either. */
1550         if (!(atom = GlobalFindAtomW( className )))
1551         {
1552             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1553             return 0;
1554         }
1555     }
1556     return WIN_FindWindow( parent, child, atom, title );
1557 }
1558
1559
1560 /***********************************************************************
1561  *              FindWindowW (USER32.@)
1562  */
1563 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1564 {
1565     return FindWindowExW( 0, 0, className, title );
1566 }
1567
1568
1569 /**********************************************************************
1570  *              GetDesktopWindow (USER32.@)
1571  */
1572 HWND WINAPI GetDesktopWindow(void)
1573 {
1574     struct user_thread_info *thread_info = get_user_thread_info();
1575
1576     if (thread_info->desktop) return thread_info->desktop;
1577
1578     SERVER_START_REQ( get_desktop_window )
1579     {
1580         req->force = 0;
1581         if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1582     }
1583     SERVER_END_REQ;
1584
1585     if (!thread_info->desktop)
1586     {
1587         static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1588         STARTUPINFOW si;
1589         PROCESS_INFORMATION pi;
1590         WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1591
1592         memset( &si, 0, sizeof(si) );
1593         si.cb = sizeof(si);
1594         GetSystemDirectoryW( cmdline, MAX_PATH );
1595         lstrcatW( cmdline, command_line );
1596         if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1597                             NULL, NULL, &si, &pi ))
1598         {
1599             TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1600             WaitForInputIdle( pi.hProcess, 10000 );
1601             CloseHandle( pi.hThread );
1602             CloseHandle( pi.hProcess );
1603
1604         }
1605         else WARN( "failed to start explorer, err %d\n", GetLastError() );
1606
1607         SERVER_START_REQ( get_desktop_window )
1608         {
1609             req->force = 1;
1610             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1611         }
1612         SERVER_END_REQ;
1613     }
1614
1615     if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1616         ERR( "failed to create desktop window\n" );
1617
1618     return thread_info->desktop;
1619 }
1620
1621
1622 /*******************************************************************
1623  *              EnableWindow (USER32.@)
1624  */
1625 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1626 {
1627     BOOL retvalue;
1628     HWND full_handle;
1629
1630     if (is_broadcast(hwnd))
1631     {
1632         SetLastError( ERROR_INVALID_PARAMETER );
1633         return FALSE;
1634     }
1635
1636     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1637         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1638
1639     hwnd = full_handle;
1640
1641     TRACE("( %p, %d )\n", hwnd, enable);
1642
1643     retvalue = !IsWindowEnabled( hwnd );
1644
1645     if (enable && retvalue)
1646     {
1647         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1648         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1649     }
1650     else if (!enable && !retvalue)
1651     {
1652         HWND capture_wnd;
1653
1654         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1655
1656         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1657
1658         if (hwnd == GetFocus())
1659             SetFocus( 0 );  /* A disabled window can't have the focus */
1660
1661         capture_wnd = GetCapture();
1662         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1663             ReleaseCapture();  /* A disabled window can't capture the mouse */
1664
1665         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1666     }
1667     return retvalue;
1668 }
1669
1670
1671 /***********************************************************************
1672  *              IsWindowEnabled (USER32.@)
1673  */
1674 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1675 {
1676     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1677 }
1678
1679
1680 /***********************************************************************
1681  *              IsWindowUnicode (USER32.@)
1682  */
1683 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1684 {
1685     WND * wndPtr;
1686     BOOL retvalue = FALSE;
1687
1688     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1689
1690     if (wndPtr == WND_DESKTOP) return TRUE;
1691
1692     if (wndPtr != WND_OTHER_PROCESS)
1693     {
1694         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1695         WIN_ReleasePtr( wndPtr );
1696     }
1697     else
1698     {
1699         SERVER_START_REQ( get_window_info )
1700         {
1701             req->handle = hwnd;
1702             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1703         }
1704         SERVER_END_REQ;
1705     }
1706     return retvalue;
1707 }
1708
1709
1710 /**********************************************************************
1711  *           WIN_GetWindowLong
1712  *
1713  * Helper function for GetWindowLong().
1714  */
1715 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1716 {
1717     LONG_PTR retvalue = 0;
1718     WND *wndPtr;
1719
1720     if (offset == GWLP_HWNDPARENT)
1721     {
1722         HWND parent = GetAncestor( hwnd, GA_PARENT );
1723         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1724         return (ULONG_PTR)parent;
1725     }
1726
1727     if (!(wndPtr = WIN_GetPtr( hwnd )))
1728     {
1729         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1730         return 0;
1731     }
1732
1733     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1734     {
1735         if (offset == GWLP_WNDPROC)
1736         {
1737             SetLastError( ERROR_ACCESS_DENIED );
1738             return 0;
1739         }
1740         SERVER_START_REQ( set_window_info )
1741         {
1742             req->handle = hwnd;
1743             req->flags  = 0;  /* don't set anything, just retrieve */
1744             req->extra_offset = (offset >= 0) ? offset : -1;
1745             req->extra_size = (offset >= 0) ? size : 0;
1746             if (!wine_server_call_err( req ))
1747             {
1748                 switch(offset)
1749                 {
1750                 case GWL_STYLE:      retvalue = reply->old_style; break;
1751                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1752                 case GWLP_ID:        retvalue = reply->old_id; break;
1753                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1754                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1755                 default:
1756                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1757                     else SetLastError( ERROR_INVALID_INDEX );
1758                     break;
1759                 }
1760             }
1761         }
1762         SERVER_END_REQ;
1763         return retvalue;
1764     }
1765
1766     /* now we have a valid wndPtr */
1767
1768     if (offset >= 0)
1769     {
1770         if (offset > (int)(wndPtr->cbWndExtra - size))
1771         {
1772             WARN("Invalid offset %d\n", offset );
1773             WIN_ReleasePtr( wndPtr );
1774             SetLastError( ERROR_INVALID_INDEX );
1775             return 0;
1776         }
1777         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1778
1779         /* Special case for dialog window procedure */
1780         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1781             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1782         WIN_ReleasePtr( wndPtr );
1783         return retvalue;
1784     }
1785
1786     switch(offset)
1787     {
1788     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1789     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1790     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1791     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1792     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break;
1793     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1794     default:
1795         WARN("Unknown offset %d\n", offset );
1796         SetLastError( ERROR_INVALID_INDEX );
1797         break;
1798     }
1799     WIN_ReleasePtr(wndPtr);
1800     return retvalue;
1801 }
1802
1803
1804 /**********************************************************************
1805  *           WIN_SetWindowLong
1806  *
1807  * Helper function for SetWindowLong().
1808  *
1809  * 0 is the failure code. However, in the case of failure SetLastError
1810  * must be set to distinguish between a 0 return value and a failure.
1811  */
1812 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1813 {
1814     STYLESTRUCT style;
1815     BOOL ok;
1816     LONG_PTR retval = 0;
1817     WND *wndPtr;
1818
1819     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1820
1821     if (is_broadcast(hwnd))
1822     {
1823         SetLastError( ERROR_INVALID_PARAMETER );
1824         return FALSE;
1825     }
1826
1827     if (!(wndPtr = WIN_GetPtr( hwnd )))
1828     {
1829         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1830         return 0;
1831     }
1832     if (wndPtr == WND_DESKTOP)
1833     {
1834         /* can't change anything on the desktop window */
1835         SetLastError( ERROR_ACCESS_DENIED );
1836         return 0;
1837     }
1838     if (wndPtr == WND_OTHER_PROCESS)
1839     {
1840         if (offset == GWLP_WNDPROC)
1841         {
1842             SetLastError( ERROR_ACCESS_DENIED );
1843             return 0;
1844         }
1845         if (offset > 32767 || offset < -32767)
1846         {
1847             SetLastError( ERROR_INVALID_INDEX );
1848             return 0;
1849         }
1850         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1851     }
1852
1853     /* first some special cases */
1854     switch( offset )
1855     {
1856     case GWL_STYLE:
1857     case GWL_EXSTYLE:
1858         style.styleOld =
1859             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1860         style.styleNew = newval;
1861         WIN_ReleasePtr( wndPtr );
1862         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1863         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1864         newval = style.styleNew;
1865         break;
1866     case GWLP_HWNDPARENT:
1867         if (wndPtr->parent == GetDesktopWindow())
1868         {
1869             WIN_ReleasePtr( wndPtr );
1870             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1871         }
1872         else
1873         {
1874             WIN_ReleasePtr( wndPtr );
1875             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1876         }
1877     case GWLP_WNDPROC:
1878     {
1879         WNDPROC proc;
1880         UINT old_flags = wndPtr->flags;
1881         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1882         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1883         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1884         if (proc) wndPtr->winproc = proc;
1885         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1886         else wndPtr->flags &= ~WIN_ISUNICODE;
1887         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1888         {
1889             WIN_ReleasePtr( wndPtr );
1890             return retval;
1891         }
1892         /* update is_unicode flag on the server side */
1893         break;
1894     }
1895     case GWLP_ID:
1896     case GWLP_HINSTANCE:
1897     case GWLP_USERDATA:
1898         break;
1899     case DWLP_DLGPROC:
1900         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1901             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1902         {
1903             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1904             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1905             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1906             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1907             WIN_ReleasePtr( wndPtr );
1908             return retval;
1909         }
1910         /* fall through */
1911     default:
1912         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1913         {
1914             WARN("Invalid offset %d\n", offset );
1915             WIN_ReleasePtr( wndPtr );
1916             SetLastError( ERROR_INVALID_INDEX );
1917             return 0;
1918         }
1919         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1920         {
1921             /* already set to the same value */
1922             WIN_ReleasePtr( wndPtr );
1923             return newval;
1924         }
1925         break;
1926     }
1927
1928     SERVER_START_REQ( set_window_info )
1929     {
1930         req->handle = hwnd;
1931         req->extra_offset = -1;
1932         switch(offset)
1933         {
1934         case GWL_STYLE:
1935             req->flags = SET_WIN_STYLE;
1936             req->style = newval;
1937             break;
1938         case GWL_EXSTYLE:
1939             req->flags = SET_WIN_EXSTYLE;
1940             req->ex_style = newval;
1941             break;
1942         case GWLP_ID:
1943             req->flags = SET_WIN_ID;
1944             req->id = newval;
1945             break;
1946         case GWLP_HINSTANCE:
1947             req->flags = SET_WIN_INSTANCE;
1948             req->instance = (void *)newval;
1949             break;
1950         case GWLP_WNDPROC:
1951             req->flags = SET_WIN_UNICODE;
1952             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1953             break;
1954         case GWLP_USERDATA:
1955             req->flags = SET_WIN_USERDATA;
1956             req->user_data = newval;
1957             break;
1958         default:
1959             req->flags = SET_WIN_EXTRA;
1960             req->extra_offset = offset;
1961             req->extra_size = size;
1962             set_win_data( &req->extra_value, newval, size );
1963         }
1964         if ((ok = !wine_server_call_err( req )))
1965         {
1966             switch(offset)
1967             {
1968             case GWL_STYLE:
1969                 wndPtr->dwStyle = newval;
1970                 retval = reply->old_style;
1971                 break;
1972             case GWL_EXSTYLE:
1973                 wndPtr->dwExStyle = newval;
1974                 retval = reply->old_ex_style;
1975                 break;
1976             case GWLP_ID:
1977                 wndPtr->wIDmenu = newval;
1978                 retval = reply->old_id;
1979                 break;
1980             case GWLP_HINSTANCE:
1981                 wndPtr->hInstance = (HINSTANCE)newval;
1982                 retval = (ULONG_PTR)reply->old_instance;
1983                 break;
1984             case GWLP_WNDPROC:
1985                 break;
1986             case GWLP_USERDATA:
1987                 wndPtr->userdata = newval;
1988                 retval = reply->old_user_data;
1989                 break;
1990             default:
1991                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
1992                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
1993                 break;
1994             }
1995         }
1996     }
1997     SERVER_END_REQ;
1998     WIN_ReleasePtr( wndPtr );
1999
2000     if (!ok) return 0;
2001
2002     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2003
2004     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2005         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2006
2007     return retval;
2008 }
2009
2010
2011 /**********************************************************************
2012  *              GetWindowLong (USER.135)
2013  */
2014 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2015 {
2016     WND *wndPtr;
2017     LONG_PTR retvalue;
2018     BOOL is_winproc = (offset == GWLP_WNDPROC);
2019
2020     if (offset >= 0)
2021     {
2022         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2023         {
2024             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2025             return 0;
2026         }
2027         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2028         {
2029             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2030             {
2031                 /*
2032                  * Some programs try to access last element from 16 bit
2033                  * code using illegal offset value. Hopefully this is
2034                  * what those programs really expect.
2035                  */
2036                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2037                 {
2038                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2039                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2040                     offset = offset2;
2041                 }
2042                 else
2043                 {
2044                     WARN("Invalid offset %d\n", offset );
2045                     WIN_ReleasePtr( wndPtr );
2046                     SetLastError( ERROR_INVALID_INDEX );
2047                     return 0;
2048                 }
2049             }
2050             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2051             WIN_ReleasePtr( wndPtr );
2052         }
2053     }
2054     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2055     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2056     return retvalue;
2057 }
2058
2059
2060 /**********************************************************************
2061  *              GetWindowWord (USER32.@)
2062  */
2063 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2064 {
2065     switch(offset)
2066     {
2067     case GWLP_ID:
2068     case GWLP_HINSTANCE:
2069     case GWLP_HWNDPARENT:
2070         break;
2071     default:
2072         if (offset < 0)
2073         {
2074             WARN("Invalid offset %d\n", offset );
2075             SetLastError( ERROR_INVALID_INDEX );
2076             return 0;
2077         }
2078         break;
2079     }
2080     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2081 }
2082
2083
2084 /**********************************************************************
2085  *              GetWindowLongA (USER32.@)
2086  */
2087 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2088 {
2089     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2090 }
2091
2092
2093 /**********************************************************************
2094  *              GetWindowLongW (USER32.@)
2095  */
2096 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2097 {
2098     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2099 }
2100
2101
2102 /**********************************************************************
2103  *              SetWindowLong (USER.136)
2104  */
2105 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2106 {
2107     WND *wndPtr;
2108     BOOL is_winproc = (offset == GWLP_WNDPROC);
2109
2110     if (offset == DWLP_DLGPROC)
2111     {
2112         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2113         {
2114             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2115             return 0;
2116         }
2117         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2118         {
2119             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2120                           (wndPtr->flags & WIN_ISDIALOG));
2121             WIN_ReleasePtr( wndPtr );
2122         }
2123     }
2124
2125     if (is_winproc)
2126     {
2127         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2128         WNDPROC old_proc = (WNDPROC)SetWindowLongA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2129         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2130     }
2131     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2132 }
2133
2134
2135 /**********************************************************************
2136  *              SetWindowWord (USER32.@)
2137  */
2138 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2139 {
2140     switch(offset)
2141     {
2142     case GWLP_ID:
2143     case GWLP_HINSTANCE:
2144     case GWLP_HWNDPARENT:
2145         break;
2146     default:
2147         if (offset < 0)
2148         {
2149             WARN("Invalid offset %d\n", offset );
2150             SetLastError( ERROR_INVALID_INDEX );
2151             return 0;
2152         }
2153         break;
2154     }
2155     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2156 }
2157
2158
2159 /**********************************************************************
2160  *              SetWindowLongA (USER32.@)
2161  *
2162  * See SetWindowLongW.
2163  */
2164 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2165 {
2166     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2167 }
2168
2169
2170 /**********************************************************************
2171  *              SetWindowLongW (USER32.@) Set window attribute
2172  *
2173  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2174  * value in a window's extra memory.
2175  *
2176  * The _hwnd_ parameter specifies the window.  is the handle to a
2177  * window that has extra memory. The _newval_ parameter contains the
2178  * new attribute or extra memory value.  If positive, the _offset_
2179  * parameter is the byte-addressed location in the window's extra
2180  * memory to set.  If negative, _offset_ specifies the window
2181  * attribute to set, and should be one of the following values:
2182  *
2183  * GWL_EXSTYLE      The window's extended window style
2184  *
2185  * GWL_STYLE        The window's window style.
2186  *
2187  * GWLP_WNDPROC     Pointer to the window's window procedure.
2188  *
2189  * GWLP_HINSTANCE   The window's pplication instance handle.
2190  *
2191  * GWLP_ID          The window's identifier.
2192  *
2193  * GWLP_USERDATA    The window's user-specified data.
2194  *
2195  * If the window is a dialog box, the _offset_ parameter can be one of
2196  * the following values:
2197  *
2198  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2199  *
2200  * DWLP_MSGRESULT   The return value of a message
2201  *                  that the dialog box procedure processed.
2202  *
2203  * DWLP_USER        Application specific information.
2204  *
2205  * RETURNS
2206  *
2207  * If successful, returns the previous value located at _offset_. Otherwise,
2208  * returns 0.
2209  *
2210  * NOTES
2211  *
2212  * Extra memory for a window class is specified by a nonzero cbWndExtra
2213  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2214  * time of class creation.
2215  *
2216  * Using GWL_WNDPROC to set a new window procedure effectively creates
2217  * a window subclass. Use CallWindowProc() in the new windows procedure
2218  * to pass messages to the superclass's window procedure.
2219  *
2220  * The user data is reserved for use by the application which created
2221  * the window.
2222  *
2223  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2224  * instead, call the EnableWindow() function to change the window's
2225  * disabled state.
2226  *
2227  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2228  * SetParent() instead.
2229  *
2230  * Win95:
2231  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2232  * it sends WM_STYLECHANGING before changing the settings
2233  * and WM_STYLECHANGED afterwards.
2234  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2235  */
2236 LONG WINAPI SetWindowLongW(
2237     HWND hwnd,  /* [in] window to alter */
2238     INT offset, /* [in] offset, in bytes, of location to alter */
2239     LONG newval /* [in] new value of location */
2240 ) {
2241     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2242 }
2243
2244
2245 /*******************************************************************
2246  *              GetWindowTextA (USER32.@)
2247  */
2248 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2249 {
2250     WCHAR *buffer;
2251
2252     if (!lpString) return 0;
2253
2254     if (WIN_IsCurrentProcess( hwnd ))
2255         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2256
2257     /* when window belongs to other process, don't send a message */
2258     if (nMaxCount <= 0) return 0;
2259     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2260     get_server_window_text( hwnd, buffer, nMaxCount );
2261     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2262         lpString[nMaxCount-1] = 0;
2263     HeapFree( GetProcessHeap(), 0, buffer );
2264     return strlen(lpString);
2265 }
2266
2267
2268 /*******************************************************************
2269  *              InternalGetWindowText (USER32.@)
2270  */
2271 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2272 {
2273     WND *win;
2274
2275     if (nMaxCount <= 0) return 0;
2276     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2277     if (win == WND_DESKTOP) lpString[0] = 0;
2278     else if (win != WND_OTHER_PROCESS)
2279     {
2280         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2281         else lpString[0] = 0;
2282         WIN_ReleasePtr( win );
2283     }
2284     else
2285     {
2286         get_server_window_text( hwnd, lpString, nMaxCount );
2287     }
2288     return strlenW(lpString);
2289 }
2290
2291
2292 /*******************************************************************
2293  *              GetWindowTextW (USER32.@)
2294  */
2295 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2296 {
2297     if (!lpString) return 0;
2298
2299     if (WIN_IsCurrentProcess( hwnd ))
2300         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2301
2302     /* when window belongs to other process, don't send a message */
2303     if (nMaxCount <= 0) return 0;
2304     get_server_window_text( hwnd, lpString, nMaxCount );
2305     return strlenW(lpString);
2306 }
2307
2308
2309 /*******************************************************************
2310  *              SetWindowTextA (USER32.@)
2311  *              SetWindowText  (USER32.@)
2312  */
2313 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2314 {
2315     if (is_broadcast(hwnd))
2316     {
2317         SetLastError( ERROR_INVALID_PARAMETER );
2318         return FALSE;
2319     }
2320     if (!WIN_IsCurrentProcess( hwnd ))
2321         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2322                debugstr_a(lpString), hwnd );
2323     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2324 }
2325
2326
2327 /*******************************************************************
2328  *              SetWindowTextW (USER32.@)
2329  */
2330 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2331 {
2332     if (is_broadcast(hwnd))
2333     {
2334         SetLastError( ERROR_INVALID_PARAMETER );
2335         return FALSE;
2336     }
2337     if (!WIN_IsCurrentProcess( hwnd ))
2338         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2339                debugstr_w(lpString), hwnd );
2340     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2341 }
2342
2343
2344 /*******************************************************************
2345  *              GetWindowTextLengthA (USER32.@)
2346  */
2347 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2348 {
2349     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2350 }
2351
2352 /*******************************************************************
2353  *              GetWindowTextLengthW (USER32.@)
2354  */
2355 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2356 {
2357     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2358 }
2359
2360
2361 /*******************************************************************
2362  *              IsWindow (USER32.@)
2363  */
2364 BOOL WINAPI IsWindow( HWND hwnd )
2365 {
2366     WND *ptr;
2367     BOOL ret;
2368
2369     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2370     if (ptr == WND_DESKTOP) return TRUE;
2371
2372     if (ptr != WND_OTHER_PROCESS)
2373     {
2374         WIN_ReleasePtr( ptr );
2375         return TRUE;
2376     }
2377
2378     /* check other processes */
2379     SERVER_START_REQ( get_window_info )
2380     {
2381         req->handle = hwnd;
2382         ret = !wine_server_call_err( req );
2383     }
2384     SERVER_END_REQ;
2385     return ret;
2386 }
2387
2388
2389 /***********************************************************************
2390  *              GetWindowThreadProcessId (USER32.@)
2391  */
2392 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2393 {
2394     WND *ptr;
2395     DWORD tid = 0;
2396
2397     if (!(ptr = WIN_GetPtr( hwnd )))
2398     {
2399         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2400         return 0;
2401     }
2402
2403     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2404     {
2405         /* got a valid window */
2406         tid = ptr->tid;
2407         if (process) *process = GetCurrentProcessId();
2408         WIN_ReleasePtr( ptr );
2409         return tid;
2410     }
2411
2412     /* check other processes */
2413     SERVER_START_REQ( get_window_info )
2414     {
2415         req->handle = hwnd;
2416         if (!wine_server_call_err( req ))
2417         {
2418             tid = (DWORD)reply->tid;
2419             if (process) *process = (DWORD)reply->pid;
2420         }
2421     }
2422     SERVER_END_REQ;
2423     return tid;
2424 }
2425
2426
2427 /*****************************************************************
2428  *              GetParent (USER32.@)
2429  */
2430 HWND WINAPI GetParent( HWND hwnd )
2431 {
2432     WND *wndPtr;
2433     HWND retvalue = 0;
2434
2435     if (!(wndPtr = WIN_GetPtr( hwnd )))
2436     {
2437         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2438         return 0;
2439     }
2440     if (wndPtr == WND_DESKTOP) return 0;
2441     if (wndPtr == WND_OTHER_PROCESS)
2442     {
2443         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2444         if (style & (WS_POPUP | WS_CHILD))
2445         {
2446             SERVER_START_REQ( get_window_tree )
2447             {
2448                 req->handle = hwnd;
2449                 if (!wine_server_call_err( req ))
2450                 {
2451                     if (style & WS_POPUP) retvalue = reply->owner;
2452                     else if (style & WS_CHILD) retvalue = reply->parent;
2453                 }
2454             }
2455             SERVER_END_REQ;
2456         }
2457     }
2458     else
2459     {
2460         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2461         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2462         WIN_ReleasePtr( wndPtr );
2463     }
2464     return retvalue;
2465 }
2466
2467
2468 /*****************************************************************
2469  *              GetAncestor (USER32.@)
2470  */
2471 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2472 {
2473     WND *win;
2474     HWND *list, ret = 0;
2475
2476     switch(type)
2477     {
2478     case GA_PARENT:
2479         if (!(win = WIN_GetPtr( hwnd )))
2480         {
2481             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2482             return 0;
2483         }
2484         if (win == WND_DESKTOP) return 0;
2485         if (win != WND_OTHER_PROCESS)
2486         {
2487             ret = win->parent;
2488             WIN_ReleasePtr( win );
2489         }
2490         else /* need to query the server */
2491         {
2492             SERVER_START_REQ( get_window_tree )
2493             {
2494                 req->handle = hwnd;
2495                 if (!wine_server_call_err( req )) ret = reply->parent;
2496             }
2497             SERVER_END_REQ;
2498         }
2499         break;
2500
2501     case GA_ROOT:
2502         if (!(list = list_window_parents( hwnd ))) return 0;
2503
2504         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2505         else
2506         {
2507             int count = 2;
2508             while (list[count]) count++;
2509             ret = list[count - 2];  /* get the one before the desktop */
2510         }
2511         HeapFree( GetProcessHeap(), 0, list );
2512         break;
2513
2514     case GA_ROOTOWNER:
2515         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2516         for (;;)
2517         {
2518             HWND parent = GetParent( ret );
2519             if (!parent) break;
2520             ret = parent;
2521         }
2522         break;
2523     }
2524     return ret;
2525 }
2526
2527
2528 /*****************************************************************
2529  *              SetParent (USER32.@)
2530  */
2531 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2532 {
2533     HWND full_handle;
2534     HWND old_parent = 0;
2535     BOOL was_visible;
2536     WND *wndPtr;
2537     BOOL ret;
2538
2539     if (is_broadcast(hwnd) || is_broadcast(parent))
2540     {
2541         SetLastError(ERROR_INVALID_PARAMETER);
2542         return 0;
2543     }
2544
2545     if (!parent) parent = GetDesktopWindow();
2546     else parent = WIN_GetFullHandle( parent );
2547
2548     if (!IsWindow( parent ))
2549     {
2550         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2551         return 0;
2552     }
2553
2554     /* Some applications try to set a child as a parent */
2555     if (IsChild(hwnd, parent))
2556     {
2557         SetLastError( ERROR_INVALID_PARAMETER );
2558         return 0;
2559     }
2560
2561     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2562         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2563
2564     /* Windows hides the window first, then shows it again
2565      * including the WM_SHOWWINDOW messages and all */
2566     was_visible = ShowWindow( hwnd, SW_HIDE );
2567
2568     wndPtr = WIN_GetPtr( hwnd );
2569     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2570
2571     SERVER_START_REQ( set_parent )
2572     {
2573         req->handle = hwnd;
2574         req->parent = parent;
2575         if ((ret = !wine_server_call( req )))
2576         {
2577             old_parent = reply->old_parent;
2578             wndPtr->parent = parent = reply->full_parent;
2579         }
2580
2581     }
2582     SERVER_END_REQ;
2583     WIN_ReleasePtr( wndPtr );
2584     if (!ret) return 0;
2585
2586     USER_Driver->pSetParent( full_handle, parent, old_parent );
2587
2588     /* SetParent additionally needs to make hwnd the topmost window
2589        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2590        WM_WINDOWPOSCHANGED notification messages.
2591     */
2592     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2593                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2594     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2595      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2596
2597     return old_parent;
2598 }
2599
2600
2601 /*******************************************************************
2602  *              IsChild (USER32.@)
2603  */
2604 BOOL WINAPI IsChild( HWND parent, HWND child )
2605 {
2606     HWND *list = list_window_parents( child );
2607     int i;
2608     BOOL ret;
2609
2610     if (!list) return FALSE;
2611     parent = WIN_GetFullHandle( parent );
2612     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2613     ret = (list[i] != 0);
2614     HeapFree( GetProcessHeap(), 0, list );
2615     return ret;
2616 }
2617
2618
2619 /***********************************************************************
2620  *              IsWindowVisible (USER32.@)
2621  */
2622 BOOL WINAPI IsWindowVisible( HWND hwnd )
2623 {
2624     HWND *list;
2625     BOOL retval = TRUE;
2626     int i;
2627
2628     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2629     if (!(list = list_window_parents( hwnd ))) return TRUE;
2630     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2631     {
2632         for (i = 0; list[i+1]; i++)
2633             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2634         retval = !list[i+1];
2635     }
2636     HeapFree( GetProcessHeap(), 0, list );
2637     return retval;
2638 }
2639
2640
2641 /***********************************************************************
2642  *           WIN_IsWindowDrawable
2643  *
2644  * hwnd is drawable when it is visible, all parents are not
2645  * minimized, and it is itself not minimized unless we are
2646  * trying to draw its default class icon.
2647  */
2648 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2649 {
2650     HWND *list;
2651     BOOL retval = TRUE;
2652     int i;
2653     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2654
2655     if (!(style & WS_VISIBLE)) return FALSE;
2656     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2657
2658     if (!(list = list_window_parents( hwnd ))) return TRUE;
2659     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2660     {
2661         for (i = 0; list[i+1]; i++)
2662             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2663                 break;
2664         retval = !list[i+1];
2665     }
2666     HeapFree( GetProcessHeap(), 0, list );
2667     return retval;
2668 }
2669
2670
2671 /*******************************************************************
2672  *              GetTopWindow (USER32.@)
2673  */
2674 HWND WINAPI GetTopWindow( HWND hwnd )
2675 {
2676     if (!hwnd) hwnd = GetDesktopWindow();
2677     return GetWindow( hwnd, GW_CHILD );
2678 }
2679
2680
2681 /*******************************************************************
2682  *              GetWindow (USER32.@)
2683  */
2684 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2685 {
2686     HWND retval = 0;
2687
2688     if (rel == GW_OWNER)  /* this one may be available locally */
2689     {
2690         WND *wndPtr = WIN_GetPtr( hwnd );
2691         if (!wndPtr)
2692         {
2693             SetLastError( ERROR_INVALID_HANDLE );
2694             return 0;
2695         }
2696         if (wndPtr == WND_DESKTOP) return 0;
2697         if (wndPtr != WND_OTHER_PROCESS)
2698         {
2699             retval = wndPtr->owner;
2700             WIN_ReleasePtr( wndPtr );
2701             return retval;
2702         }
2703         /* else fall through to server call */
2704     }
2705
2706     SERVER_START_REQ( get_window_tree )
2707     {
2708         req->handle = hwnd;
2709         if (!wine_server_call_err( req ))
2710         {
2711             switch(rel)
2712             {
2713             case GW_HWNDFIRST:
2714                 retval = reply->first_sibling;
2715                 break;
2716             case GW_HWNDLAST:
2717                 retval = reply->last_sibling;
2718                 break;
2719             case GW_HWNDNEXT:
2720                 retval = reply->next_sibling;
2721                 break;
2722             case GW_HWNDPREV:
2723                 retval = reply->prev_sibling;
2724                 break;
2725             case GW_OWNER:
2726                 retval = reply->owner;
2727                 break;
2728             case GW_CHILD:
2729                 retval = reply->first_child;
2730                 break;
2731             }
2732         }
2733     }
2734     SERVER_END_REQ;
2735     return retval;
2736 }
2737
2738
2739 /*******************************************************************
2740  *              ShowOwnedPopups (USER32.@)
2741  */
2742 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2743 {
2744     int count = 0;
2745     WND *pWnd;
2746     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2747
2748     if (!win_array) return TRUE;
2749
2750     while (win_array[count]) count++;
2751     while (--count >= 0)
2752     {
2753         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2754         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2755         if (pWnd == WND_OTHER_PROCESS) continue;
2756         if (fShow)
2757         {
2758             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2759             {
2760                 WIN_ReleasePtr( pWnd );
2761                 /* In Windows, ShowOwnedPopups(TRUE) generates
2762                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2763                  * regardless of the state of the owner
2764                  */
2765                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2766                 continue;
2767             }
2768         }
2769         else
2770         {
2771             if (pWnd->dwStyle & WS_VISIBLE)
2772             {
2773                 WIN_ReleasePtr( pWnd );
2774                 /* In Windows, ShowOwnedPopups(FALSE) generates
2775                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2776                  * regardless of the state of the owner
2777                  */
2778                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2779                 continue;
2780             }
2781         }
2782         WIN_ReleasePtr( pWnd );
2783     }
2784     HeapFree( GetProcessHeap(), 0, win_array );
2785     return TRUE;
2786 }
2787
2788
2789 /*******************************************************************
2790  *              GetLastActivePopup (USER32.@)
2791  */
2792 HWND WINAPI GetLastActivePopup( HWND hwnd )
2793 {
2794     HWND retval = hwnd;
2795
2796     SERVER_START_REQ( get_window_info )
2797     {
2798         req->handle = hwnd;
2799         if (!wine_server_call_err( req )) retval = reply->last_active;
2800     }
2801     SERVER_END_REQ;
2802     return retval;
2803 }
2804
2805
2806 /*******************************************************************
2807  *           WIN_ListChildren
2808  *
2809  * Build an array of the children of a given window. The array must be
2810  * freed with HeapFree. Returns NULL when no windows are found.
2811  */
2812 HWND *WIN_ListChildren( HWND hwnd )
2813 {
2814     return list_window_children( hwnd, 0, 0 );
2815 }
2816
2817
2818 /*******************************************************************
2819  *              EnumWindows (USER32.@)
2820  */
2821 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2822 {
2823     HWND *list;
2824     BOOL ret = TRUE;
2825     int i;
2826
2827     USER_CheckNotLock();
2828
2829     /* We have to build a list of all windows first, to avoid */
2830     /* unpleasant side-effects, for instance if the callback */
2831     /* function changes the Z-order of the windows.          */
2832
2833     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2834
2835     /* Now call the callback function for every window */
2836
2837     for (i = 0; list[i]; i++)
2838     {
2839         /* Make sure that the window still exists */
2840         if (!IsWindow( list[i] )) continue;
2841         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2842     }
2843     HeapFree( GetProcessHeap(), 0, list );
2844     return ret;
2845 }
2846
2847
2848 /**********************************************************************
2849  *              EnumThreadWindows (USER32.@)
2850  */
2851 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2852 {
2853     HWND *list;
2854     int i;
2855
2856     USER_CheckNotLock();
2857
2858     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2859
2860     /* Now call the callback function for every window */
2861
2862     for (i = 0; list[i]; i++)
2863         if (!func( list[i], lParam )) break;
2864     HeapFree( GetProcessHeap(), 0, list );
2865     return TRUE;
2866 }
2867
2868
2869 /**********************************************************************
2870  *           WIN_EnumChildWindows
2871  *
2872  * Helper function for EnumChildWindows().
2873  */
2874 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2875 {
2876     HWND *childList;
2877     BOOL ret = FALSE;
2878
2879     for ( ; *list; list++)
2880     {
2881         /* Make sure that the window still exists */
2882         if (!IsWindow( *list )) continue;
2883         /* Build children list first */
2884         childList = WIN_ListChildren( *list );
2885
2886         ret = func( *list, lParam );
2887
2888         if (childList)
2889         {
2890             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2891             HeapFree( GetProcessHeap(), 0, childList );
2892         }
2893         if (!ret) return FALSE;
2894     }
2895     return TRUE;
2896 }
2897
2898
2899 /**********************************************************************
2900  *              EnumChildWindows (USER32.@)
2901  */
2902 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2903 {
2904     HWND *list;
2905     BOOL ret;
2906
2907     USER_CheckNotLock();
2908
2909     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2910     ret = WIN_EnumChildWindows( list, func, lParam );
2911     HeapFree( GetProcessHeap(), 0, list );
2912     return ret;
2913 }
2914
2915
2916 /*******************************************************************
2917  *              AnyPopup (USER.52)
2918  */
2919 BOOL16 WINAPI AnyPopup16(void)
2920 {
2921     return AnyPopup();
2922 }
2923
2924
2925 /*******************************************************************
2926  *              AnyPopup (USER32.@)
2927  */
2928 BOOL WINAPI AnyPopup(void)
2929 {
2930     int i;
2931     BOOL retvalue;
2932     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2933
2934     if (!list) return FALSE;
2935     for (i = 0; list[i]; i++)
2936     {
2937         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2938     }
2939     retvalue = (list[i] != 0);
2940     HeapFree( GetProcessHeap(), 0, list );
2941     return retvalue;
2942 }
2943
2944
2945 /*******************************************************************
2946  *              FlashWindow (USER32.@)
2947  */
2948 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2949 {
2950     WND *wndPtr;
2951
2952     TRACE("%p\n", hWnd);
2953
2954     if (IsIconic( hWnd ))
2955     {
2956         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2957
2958         wndPtr = WIN_GetPtr(hWnd);
2959         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2960         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2961         {
2962             wndPtr->flags |= WIN_NCACTIVATED;
2963         }
2964         else
2965         {
2966             wndPtr->flags &= ~WIN_NCACTIVATED;
2967         }
2968         WIN_ReleasePtr( wndPtr );
2969         return TRUE;
2970     }
2971     else
2972     {
2973         WPARAM wparam;
2974
2975         wndPtr = WIN_GetPtr(hWnd);
2976         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2977         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2978
2979         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2980         else wparam = (hWnd == GetForegroundWindow());
2981
2982         WIN_ReleasePtr( wndPtr );
2983         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2984         return wparam;
2985     }
2986 }
2987
2988 /*******************************************************************
2989  *              FlashWindowEx (USER32.@)
2990  */
2991 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2992 {
2993     FIXME("%p\n", pfwi);
2994     return TRUE;
2995 }
2996
2997 /*******************************************************************
2998  *              GetWindowContextHelpId (USER32.@)
2999  */
3000 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3001 {
3002     DWORD retval;
3003     WND *wnd = WIN_GetPtr( hwnd );
3004     if (!wnd || wnd == WND_DESKTOP) return 0;
3005     if (wnd == WND_OTHER_PROCESS)
3006     {
3007         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3008         return 0;
3009     }
3010     retval = wnd->helpContext;
3011     WIN_ReleasePtr( wnd );
3012     return retval;
3013 }
3014
3015
3016 /*******************************************************************
3017  *              SetWindowContextHelpId (USER32.@)
3018  */
3019 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3020 {
3021     WND *wnd = WIN_GetPtr( hwnd );
3022     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3023     if (wnd == WND_OTHER_PROCESS)
3024     {
3025         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3026         return 0;
3027     }
3028     wnd->helpContext = id;
3029     WIN_ReleasePtr( wnd );
3030     return TRUE;
3031 }
3032
3033
3034 /*******************************************************************
3035  *              DragDetect (USER32.@)
3036  */
3037 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3038 {
3039     MSG msg;
3040     RECT rect;
3041     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3042     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3043
3044     rect.left = pt.x - wDragWidth;
3045     rect.right = pt.x + wDragWidth;
3046
3047     rect.top = pt.y - wDragHeight;
3048     rect.bottom = pt.y + wDragHeight;
3049
3050     SetCapture(hWnd);
3051
3052     while(1)
3053     {
3054         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3055         {
3056             if( msg.message == WM_LBUTTONUP )
3057             {
3058                 ReleaseCapture();
3059                 return 0;
3060             }
3061             if( msg.message == WM_MOUSEMOVE )
3062             {
3063                 POINT tmp;
3064                 tmp.x = (short)LOWORD(msg.lParam);
3065                 tmp.y = (short)HIWORD(msg.lParam);
3066                 if( !PtInRect( &rect, tmp ))
3067                 {
3068                     ReleaseCapture();
3069                     return 1;
3070                 }
3071             }
3072         }
3073         WaitMessage();
3074     }
3075     return 0;
3076 }
3077
3078 /******************************************************************************
3079  *              GetWindowModuleFileNameA (USER32.@)
3080  */
3081 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3082 {
3083     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3084           hwnd, lpszFileName, cchFileNameMax);
3085     return 0;
3086 }
3087
3088 /******************************************************************************
3089  *              GetWindowModuleFileNameW (USER32.@)
3090  */
3091 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3092 {
3093     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3094           hwnd, lpszFileName, cchFileNameMax);
3095     return 0;
3096 }
3097
3098 /******************************************************************************
3099  *              GetWindowInfo (USER32.@)
3100  *
3101  * Note: tests show that Windows doesn't check cbSize of the structure.
3102  */
3103 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3104 {
3105     if (!pwi) return FALSE;
3106     if (!IsWindow(hwnd)) return FALSE;
3107
3108     GetWindowRect(hwnd, &pwi->rcWindow);
3109     GetClientRect(hwnd, &pwi->rcClient);
3110     /* translate to screen coordinates */
3111     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3112
3113     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3114     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3115     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3116
3117     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3118     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3119
3120     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3121     pwi->wCreatorVersion = 0x0400;
3122
3123     return TRUE;
3124 }
3125
3126 /******************************************************************************
3127  *              SwitchDesktop (USER32.@)
3128  *
3129  * NOTES: Sets the current input or interactive desktop.
3130  */
3131 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3132 {
3133     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3134     return TRUE;
3135 }
3136
3137 /*****************************************************************************
3138  *              SetLayeredWindowAttributes (USER32.@)
3139  */
3140 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3141                                         BYTE bAlpha, DWORD dwFlags )
3142 {
3143     FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3144     return TRUE;
3145 }
3146
3147 /*****************************************************************************
3148  *              UpdateLayeredWindow (USER32.@)
3149  */
3150 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3151                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3152                                  DWORD dwFlags)
3153 {
3154     static int once;
3155     if (!once)
3156     {
3157         once = 1;
3158         FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3159               hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3160     }
3161     return 0;
3162 }
3163
3164 /* 64bit versions */
3165
3166 #ifdef GetWindowLongPtrW
3167 #undef GetWindowLongPtrW
3168 #endif
3169
3170 #ifdef GetWindowLongPtrA
3171 #undef GetWindowLongPtrA
3172 #endif
3173
3174 #ifdef SetWindowLongPtrW
3175 #undef SetWindowLongPtrW
3176 #endif
3177
3178 #ifdef SetWindowLongPtrA
3179 #undef SetWindowLongPtrA
3180 #endif
3181
3182 /*****************************************************************************
3183  *              GetWindowLongPtrW (USER32.@)
3184  */
3185 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3186 {
3187     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3188 }
3189
3190 /*****************************************************************************
3191  *              GetWindowLongPtrA (USER32.@)
3192  */
3193 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3194 {
3195     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3196 }
3197
3198 /*****************************************************************************
3199  *              SetWindowLongPtrW (USER32.@)
3200  */
3201 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3202 {
3203     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3204 }
3205
3206 /*****************************************************************************
3207  *              SetWindowLongPtrA (USER32.@)
3208  */
3209 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3210 {
3211     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3212 }