server: Allow to specify the class name instead of the atom to create a window.
[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 "user_private.h"
37 #include "controls.h"
38 #include "winerror.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
42
43 #define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
44 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
45
46 /**********************************************************************/
47
48 /* helper for Get/SetWindowLong */
49 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
50 {
51     if (size == sizeof(WORD))
52     {
53         WORD ret;
54         memcpy( &ret, ptr, sizeof(ret) );
55         return ret;
56     }
57     else if (size == sizeof(DWORD))
58     {
59         DWORD ret;
60         memcpy( &ret, ptr, sizeof(ret) );
61         return ret;
62     }
63     else
64     {
65         LONG_PTR ret;
66         memcpy( &ret, ptr, sizeof(ret) );
67         return ret;
68     }
69 }
70
71 /* helper for Get/SetWindowLong */
72 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
73 {
74     if (size == sizeof(WORD))
75     {
76         WORD newval = val;
77         memcpy( ptr, &newval, sizeof(newval) );
78     }
79     else if (size == sizeof(DWORD))
80     {
81         DWORD newval = val;
82         memcpy( ptr, &newval, sizeof(newval) );
83     }
84     else
85     {
86         memcpy( ptr, &val, sizeof(val) );
87     }
88 }
89
90
91 static void *user_handles[NB_USER_HANDLES];
92
93 /***********************************************************************
94  *           create_window_handle
95  *
96  * Create a window handle with the server.
97  */
98 static WND *create_window_handle( HWND parent, HWND owner, LPCWSTR name,
99                                   HINSTANCE instance, BOOL unicode )
100 {
101     WORD index;
102     WND *win;
103     HWND full_parent = 0, full_owner = 0;
104     struct tagCLASS *class = NULL;
105     user_handle_t handle = 0;
106     int extra_bytes = 0;
107
108     /* if 16-bit instance, map to module handle */
109     if (instance && !HIWORD(instance))
110         instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
111
112     SERVER_START_REQ( create_window )
113     {
114         req->parent   = parent;
115         req->owner    = owner;
116         req->instance = instance;
117         if (!(req->atom = get_int_atom_value( name )) && name)
118             wine_server_add_data( req, name, strlenW(name)*sizeof(WCHAR) );
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         if (!thread_info->desktop) thread_info->desktop = full_parent ? full_parent : handle;
153         else assert( full_parent == thread_info->desktop );
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 = ULongToHandle(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, LPCWSTR className, 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           debugstr_w(className),
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 (className != (LPCWSTR)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, className, 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     CREATESTRUCTA cs;
1140     char buffer[256];
1141
1142     /* Fix the coordinates */
1143
1144     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1145     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1146     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1147     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1148
1149     /* Create the window */
1150
1151     cs.lpCreateParams = data;
1152     cs.hInstance      = HINSTANCE_32(instance);
1153     cs.hMenu          = HMENU_32(menu);
1154     cs.hwndParent     = WIN_Handle32( parent );
1155     cs.style          = style;
1156     cs.lpszName       = windowName;
1157     cs.lpszClass      = className;
1158     cs.dwExStyle      = exStyle;
1159
1160     if (!IS_INTRESOURCE(className))
1161     {
1162         WCHAR bufferW[256];
1163
1164         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1165             return 0;
1166         return HWND_16( WIN_CreateWindowEx( &cs, bufferW, 0 ));
1167     }
1168     else
1169     {
1170         if (!GlobalGetAtomNameA( LOWORD(className), buffer, sizeof(buffer) ))
1171         {
1172             ERR( "bad atom %x\n", LOWORD(className));
1173             return 0;
1174         }
1175         cs.lpszClass = buffer;
1176         return HWND_16( WIN_CreateWindowEx( &cs, (LPCWSTR)className, 0 ));
1177     }
1178 }
1179
1180
1181 /***********************************************************************
1182  *              CreateWindowExA (USER32.@)
1183  */
1184 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1185                                  LPCSTR windowName, DWORD style, INT x,
1186                                  INT y, INT width, INT height,
1187                                  HWND parent, HMENU menu,
1188                                  HINSTANCE instance, LPVOID data )
1189 {
1190     CREATESTRUCTA cs;
1191
1192     cs.lpCreateParams = data;
1193     cs.hInstance      = instance;
1194     cs.hMenu          = menu;
1195     cs.hwndParent     = parent;
1196     cs.x              = x;
1197     cs.y              = y;
1198     cs.cx             = width;
1199     cs.cy             = height;
1200     cs.style          = style;
1201     cs.lpszName       = windowName;
1202     cs.lpszClass      = className;
1203     cs.dwExStyle      = exStyle;
1204
1205     if (!IS_INTRESOURCE(className))
1206     {
1207         WCHAR bufferW[256];
1208         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1209             return 0;
1210         return WIN_CreateWindowEx( &cs, bufferW, WIN_ISWIN32 );
1211     }
1212     return WIN_CreateWindowEx( &cs, (LPCWSTR)className, WIN_ISWIN32 );
1213 }
1214
1215
1216 /***********************************************************************
1217  *              CreateWindowExW (USER32.@)
1218  */
1219 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1220                                  LPCWSTR windowName, DWORD style, INT x,
1221                                  INT y, INT width, INT height,
1222                                  HWND parent, HMENU menu,
1223                                  HINSTANCE instance, LPVOID data )
1224 {
1225     CREATESTRUCTW cs;
1226
1227     cs.lpCreateParams = data;
1228     cs.hInstance      = instance;
1229     cs.hMenu          = menu;
1230     cs.hwndParent     = parent;
1231     cs.x              = x;
1232     cs.y              = y;
1233     cs.cx             = width;
1234     cs.cy             = height;
1235     cs.style          = style;
1236     cs.lpszName       = windowName;
1237     cs.lpszClass      = className;
1238     cs.dwExStyle      = exStyle;
1239
1240     /* Note: we rely on the fact that CREATESTRUCTA and */
1241     /* CREATESTRUCTW have the same layout. */
1242     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, className, WIN_ISWIN32 | WIN_ISUNICODE );
1243 }
1244
1245
1246 /***********************************************************************
1247  *           WIN_SendDestroyMsg
1248  */
1249 static void WIN_SendDestroyMsg( HWND hwnd )
1250 {
1251     GUITHREADINFO info;
1252
1253     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1254     {
1255         if (hwnd == info.hwndCaret) DestroyCaret();
1256         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1257     }
1258
1259     /*
1260      * Send the WM_DESTROY to the window.
1261      */
1262     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1263
1264     /*
1265      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1266      * make sure that the window still exists when we come back.
1267      */
1268     if (IsWindow(hwnd))
1269     {
1270         HWND* pWndArray;
1271         int i;
1272
1273         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1274
1275         for (i = 0; pWndArray[i]; i++)
1276         {
1277             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1278         }
1279         HeapFree( GetProcessHeap(), 0, pWndArray );
1280     }
1281     else
1282       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1283 }
1284
1285
1286 /***********************************************************************
1287  *              DestroyWindow (USER32.@)
1288  */
1289 BOOL WINAPI DestroyWindow( HWND hwnd )
1290 {
1291     BOOL is_child;
1292
1293     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1294     {
1295         SetLastError( ERROR_ACCESS_DENIED );
1296         return FALSE;
1297     }
1298
1299     TRACE("(%p)\n", hwnd);
1300
1301       /* Call hooks */
1302
1303     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1304
1305     if (MENU_IsMenuActive() == hwnd)
1306         EndMenu();
1307
1308     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1309
1310     if (is_child)
1311     {
1312         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1313             send_parent_notify( hwnd, WM_DESTROY );
1314     }
1315     else if (!GetWindow( hwnd, GW_OWNER ))
1316     {
1317         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1318         /* FIXME: clean up palette - see "Internals" p.352 */
1319     }
1320
1321     if (!IsWindow(hwnd)) return TRUE;
1322
1323       /* Hide the window */
1324     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1325     {
1326         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1327         if (is_child)
1328             ShowWindow( hwnd, SW_HIDE );
1329         else
1330             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1331                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1332     }
1333
1334     if (!IsWindow(hwnd)) return TRUE;
1335
1336       /* Recursively destroy owned windows */
1337
1338     if (!is_child)
1339     {
1340         for (;;)
1341         {
1342             int i, got_one = 0;
1343             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1344             if (list)
1345             {
1346                 for (i = 0; list[i]; i++)
1347                 {
1348                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1349                     if (WIN_IsCurrentThread( list[i] ))
1350                     {
1351                         DestroyWindow( list[i] );
1352                         got_one = 1;
1353                         continue;
1354                     }
1355                     WIN_SetOwner( list[i], 0 );
1356                 }
1357                 HeapFree( GetProcessHeap(), 0, list );
1358             }
1359             if (!got_one) break;
1360         }
1361     }
1362
1363       /* Send destroy messages */
1364
1365     WIN_SendDestroyMsg( hwnd );
1366     if (!IsWindow( hwnd )) return TRUE;
1367
1368     if (GetClipboardOwner() == hwnd)
1369         CLIPBOARD_ReleaseOwner();
1370
1371       /* Destroy the window storage */
1372
1373     WIN_DestroyWindow( hwnd );
1374     return TRUE;
1375 }
1376
1377
1378 /***********************************************************************
1379  *              CloseWindow (USER32.@)
1380  */
1381 BOOL WINAPI CloseWindow( HWND hwnd )
1382 {
1383     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1384     ShowWindow( hwnd, SW_MINIMIZE );
1385     return TRUE;
1386 }
1387
1388
1389 /***********************************************************************
1390  *              OpenIcon (USER32.@)
1391  */
1392 BOOL WINAPI OpenIcon( HWND hwnd )
1393 {
1394     if (!IsIconic( hwnd )) return FALSE;
1395     ShowWindow( hwnd, SW_SHOWNORMAL );
1396     return TRUE;
1397 }
1398
1399
1400 /***********************************************************************
1401  *           WIN_FindWindow
1402  *
1403  * Implementation of FindWindow() and FindWindowEx().
1404  */
1405 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1406 {
1407     HWND *list = NULL;
1408     HWND retvalue = 0;
1409     int i = 0, len = 0;
1410     WCHAR *buffer = NULL;
1411
1412     if (!parent) parent = GetDesktopWindow();
1413     if (title)
1414     {
1415         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1416         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1417     }
1418
1419     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1420
1421     if (child)
1422     {
1423         child = WIN_GetFullHandle( child );
1424         while (list[i] && list[i] != child) i++;
1425         if (!list[i]) goto done;
1426         i++;  /* start from next window */
1427     }
1428
1429     if (title)
1430     {
1431         while (list[i])
1432         {
1433             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1434             i++;
1435         }
1436     }
1437     retvalue = list[i];
1438
1439  done:
1440     HeapFree( GetProcessHeap(), 0, list );
1441     HeapFree( GetProcessHeap(), 0, buffer );
1442     return retvalue;
1443 }
1444
1445
1446
1447 /***********************************************************************
1448  *              FindWindowA (USER32.@)
1449  */
1450 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1451 {
1452     HWND ret = FindWindowExA( 0, 0, className, title );
1453     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1454     return ret;
1455 }
1456
1457
1458 /***********************************************************************
1459  *              FindWindowExA (USER32.@)
1460  */
1461 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1462                                LPCSTR className, LPCSTR title )
1463 {
1464     ATOM atom = 0;
1465     LPWSTR buffer;
1466     HWND hwnd;
1467     INT len;
1468
1469     if (className)
1470     {
1471         /* If the atom doesn't exist, then no class */
1472         /* with this name exists either. */
1473         if (!(atom = GlobalFindAtomA( className )))
1474         {
1475             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1476             return 0;
1477         }
1478     }
1479     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1480
1481     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1482     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1483     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1484     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1485     HeapFree( GetProcessHeap(), 0, buffer );
1486     return hwnd;
1487 }
1488
1489
1490 /***********************************************************************
1491  *              FindWindowExW (USER32.@)
1492  */
1493 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1494                                LPCWSTR className, LPCWSTR title )
1495 {
1496     ATOM atom = 0;
1497
1498     if (className)
1499     {
1500         /* If the atom doesn't exist, then no class */
1501         /* with this name exists either. */
1502         if (!(atom = GlobalFindAtomW( className )))
1503         {
1504             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1505             return 0;
1506         }
1507     }
1508     return WIN_FindWindow( parent, child, atom, title );
1509 }
1510
1511
1512 /***********************************************************************
1513  *              FindWindowW (USER32.@)
1514  */
1515 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1516 {
1517     return FindWindowExW( 0, 0, className, title );
1518 }
1519
1520
1521 /**********************************************************************
1522  *              GetDesktopWindow (USER32.@)
1523  */
1524 HWND WINAPI GetDesktopWindow(void)
1525 {
1526     struct user_thread_info *thread_info = get_user_thread_info();
1527
1528     if (thread_info->desktop) return thread_info->desktop;
1529
1530     SERVER_START_REQ( get_desktop_window )
1531     {
1532         req->force = 0;
1533         if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1534     }
1535     SERVER_END_REQ;
1536
1537     if (!thread_info->desktop)
1538     {
1539         static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1540         STARTUPINFOW si;
1541         PROCESS_INFORMATION pi;
1542         WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1543
1544         memset( &si, 0, sizeof(si) );
1545         si.cb = sizeof(si);
1546         GetSystemDirectoryW( cmdline, MAX_PATH );
1547         lstrcatW( cmdline, command_line );
1548         if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1549                             NULL, NULL, &si, &pi ))
1550         {
1551             TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1552             WaitForInputIdle( pi.hProcess, 10000 );
1553             CloseHandle( pi.hThread );
1554             CloseHandle( pi.hProcess );
1555
1556         }
1557         else WARN( "failed to start explorer, err %d\n", GetLastError() );
1558
1559         SERVER_START_REQ( get_desktop_window )
1560         {
1561             req->force = 1;
1562             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1563         }
1564         SERVER_END_REQ;
1565     }
1566
1567     if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1568         ERR( "failed to create desktop window\n" );
1569
1570     return thread_info->desktop;
1571 }
1572
1573
1574 /*******************************************************************
1575  *              EnableWindow (USER32.@)
1576  */
1577 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1578 {
1579     BOOL retvalue;
1580     HWND full_handle;
1581
1582     if (is_broadcast(hwnd))
1583     {
1584         SetLastError( ERROR_INVALID_PARAMETER );
1585         return FALSE;
1586     }
1587
1588     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1589         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1590
1591     hwnd = full_handle;
1592
1593     TRACE("( %p, %d )\n", hwnd, enable);
1594
1595     retvalue = !IsWindowEnabled( hwnd );
1596
1597     if (enable && retvalue)
1598     {
1599         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1600         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1601     }
1602     else if (!enable && !retvalue)
1603     {
1604         HWND capture_wnd;
1605
1606         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1607
1608         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1609
1610         if (hwnd == GetFocus())
1611             SetFocus( 0 );  /* A disabled window can't have the focus */
1612
1613         capture_wnd = GetCapture();
1614         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1615             ReleaseCapture();  /* A disabled window can't capture the mouse */
1616
1617         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1618     }
1619     return retvalue;
1620 }
1621
1622
1623 /***********************************************************************
1624  *              IsWindowEnabled (USER32.@)
1625  */
1626 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1627 {
1628     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1629 }
1630
1631
1632 /***********************************************************************
1633  *              IsWindowUnicode (USER32.@)
1634  */
1635 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1636 {
1637     WND * wndPtr;
1638     BOOL retvalue = FALSE;
1639
1640     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1641
1642     if (wndPtr == WND_DESKTOP) return TRUE;
1643
1644     if (wndPtr != WND_OTHER_PROCESS)
1645     {
1646         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1647         WIN_ReleasePtr( wndPtr );
1648     }
1649     else
1650     {
1651         SERVER_START_REQ( get_window_info )
1652         {
1653             req->handle = hwnd;
1654             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1655         }
1656         SERVER_END_REQ;
1657     }
1658     return retvalue;
1659 }
1660
1661
1662 /**********************************************************************
1663  *           WIN_GetWindowLong
1664  *
1665  * Helper function for GetWindowLong().
1666  */
1667 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1668 {
1669     LONG_PTR retvalue = 0;
1670     WND *wndPtr;
1671
1672     if (offset == GWLP_HWNDPARENT)
1673     {
1674         HWND parent = GetAncestor( hwnd, GA_PARENT );
1675         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1676         return (ULONG_PTR)parent;
1677     }
1678
1679     if (!(wndPtr = WIN_GetPtr( hwnd )))
1680     {
1681         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1682         return 0;
1683     }
1684
1685     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1686     {
1687         if (offset == GWLP_WNDPROC)
1688         {
1689             SetLastError( ERROR_ACCESS_DENIED );
1690             return 0;
1691         }
1692         SERVER_START_REQ( set_window_info )
1693         {
1694             req->handle = hwnd;
1695             req->flags  = 0;  /* don't set anything, just retrieve */
1696             req->extra_offset = (offset >= 0) ? offset : -1;
1697             req->extra_size = (offset >= 0) ? size : 0;
1698             if (!wine_server_call_err( req ))
1699             {
1700                 switch(offset)
1701                 {
1702                 case GWL_STYLE:      retvalue = reply->old_style; break;
1703                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1704                 case GWLP_ID:        retvalue = reply->old_id; break;
1705                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1706                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1707                 default:
1708                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1709                     else SetLastError( ERROR_INVALID_INDEX );
1710                     break;
1711                 }
1712             }
1713         }
1714         SERVER_END_REQ;
1715         return retvalue;
1716     }
1717
1718     /* now we have a valid wndPtr */
1719
1720     if (offset >= 0)
1721     {
1722         if (offset > (int)(wndPtr->cbWndExtra - size))
1723         {
1724             WARN("Invalid offset %d\n", offset );
1725             WIN_ReleasePtr( wndPtr );
1726             SetLastError( ERROR_INVALID_INDEX );
1727             return 0;
1728         }
1729         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1730
1731         /* Special case for dialog window procedure */
1732         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1733             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1734         WIN_ReleasePtr( wndPtr );
1735         return retvalue;
1736     }
1737
1738     switch(offset)
1739     {
1740     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1741     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1742     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1743     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1744     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1745     case GWLP_WNDPROC:
1746         /* This looks like a hack only for the edit control (see tests). This makes these controls
1747          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1748          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1749          */
1750         if (wndPtr->winproc == EDIT_winproc_handle && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
1751             retvalue = (ULONG_PTR)wndPtr->winproc;
1752         else
1753             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1754         break;
1755     default:
1756         WARN("Unknown offset %d\n", offset );
1757         SetLastError( ERROR_INVALID_INDEX );
1758         break;
1759     }
1760     WIN_ReleasePtr(wndPtr);
1761     return retvalue;
1762 }
1763
1764
1765 /**********************************************************************
1766  *           WIN_SetWindowLong
1767  *
1768  * Helper function for SetWindowLong().
1769  *
1770  * 0 is the failure code. However, in the case of failure SetLastError
1771  * must be set to distinguish between a 0 return value and a failure.
1772  */
1773 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1774 {
1775     STYLESTRUCT style;
1776     BOOL ok;
1777     LONG_PTR retval = 0;
1778     WND *wndPtr;
1779
1780     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1781
1782     if (is_broadcast(hwnd))
1783     {
1784         SetLastError( ERROR_INVALID_PARAMETER );
1785         return FALSE;
1786     }
1787
1788     if (!(wndPtr = WIN_GetPtr( hwnd )))
1789     {
1790         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1791         return 0;
1792     }
1793     if (wndPtr == WND_DESKTOP)
1794     {
1795         /* can't change anything on the desktop window */
1796         SetLastError( ERROR_ACCESS_DENIED );
1797         return 0;
1798     }
1799     if (wndPtr == WND_OTHER_PROCESS)
1800     {
1801         if (offset == GWLP_WNDPROC)
1802         {
1803             SetLastError( ERROR_ACCESS_DENIED );
1804             return 0;
1805         }
1806         if (offset > 32767 || offset < -32767)
1807         {
1808             SetLastError( ERROR_INVALID_INDEX );
1809             return 0;
1810         }
1811         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1812     }
1813
1814     /* first some special cases */
1815     switch( offset )
1816     {
1817     case GWL_STYLE:
1818     case GWL_EXSTYLE:
1819         style.styleOld =
1820             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1821         style.styleNew = newval;
1822         WIN_ReleasePtr( wndPtr );
1823         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1824         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1825         newval = style.styleNew;
1826         break;
1827     case GWLP_HWNDPARENT:
1828         if (wndPtr->parent == GetDesktopWindow())
1829         {
1830             WIN_ReleasePtr( wndPtr );
1831             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1832         }
1833         else
1834         {
1835             WIN_ReleasePtr( wndPtr );
1836             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1837         }
1838     case GWLP_WNDPROC:
1839     {
1840         WNDPROC proc;
1841         UINT old_flags = wndPtr->flags;
1842         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
1843         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1844         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1845         if (proc) wndPtr->winproc = proc;
1846         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1847         else wndPtr->flags &= ~WIN_ISUNICODE;
1848         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1849         {
1850             WIN_ReleasePtr( wndPtr );
1851             return retval;
1852         }
1853         /* update is_unicode flag on the server side */
1854         break;
1855     }
1856     case GWLP_ID:
1857     case GWLP_HINSTANCE:
1858     case GWLP_USERDATA:
1859         break;
1860     case DWLP_DLGPROC:
1861         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1862             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1863         {
1864             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1865             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1866             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1867             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1868             WIN_ReleasePtr( wndPtr );
1869             return retval;
1870         }
1871         /* fall through */
1872     default:
1873         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1874         {
1875             WARN("Invalid offset %d\n", offset );
1876             WIN_ReleasePtr( wndPtr );
1877             SetLastError( ERROR_INVALID_INDEX );
1878             return 0;
1879         }
1880         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1881         {
1882             /* already set to the same value */
1883             WIN_ReleasePtr( wndPtr );
1884             return newval;
1885         }
1886         break;
1887     }
1888
1889     SERVER_START_REQ( set_window_info )
1890     {
1891         req->handle = hwnd;
1892         req->extra_offset = -1;
1893         switch(offset)
1894         {
1895         case GWL_STYLE:
1896             req->flags = SET_WIN_STYLE;
1897             req->style = newval;
1898             break;
1899         case GWL_EXSTYLE:
1900             req->flags = SET_WIN_EXSTYLE;
1901             /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1902             newval = (newval & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
1903             req->ex_style = newval;
1904             break;
1905         case GWLP_ID:
1906             req->flags = SET_WIN_ID;
1907             req->id = newval;
1908             break;
1909         case GWLP_HINSTANCE:
1910             req->flags = SET_WIN_INSTANCE;
1911             req->instance = (void *)newval;
1912             break;
1913         case GWLP_WNDPROC:
1914             req->flags = SET_WIN_UNICODE;
1915             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1916             break;
1917         case GWLP_USERDATA:
1918             req->flags = SET_WIN_USERDATA;
1919             req->user_data = newval;
1920             break;
1921         default:
1922             req->flags = SET_WIN_EXTRA;
1923             req->extra_offset = offset;
1924             req->extra_size = size;
1925             set_win_data( &req->extra_value, newval, size );
1926         }
1927         if ((ok = !wine_server_call_err( req )))
1928         {
1929             switch(offset)
1930             {
1931             case GWL_STYLE:
1932                 wndPtr->dwStyle = newval;
1933                 retval = reply->old_style;
1934                 break;
1935             case GWL_EXSTYLE:
1936                 wndPtr->dwExStyle = newval;
1937                 retval = reply->old_ex_style;
1938                 break;
1939             case GWLP_ID:
1940                 wndPtr->wIDmenu = newval;
1941                 retval = reply->old_id;
1942                 break;
1943             case GWLP_HINSTANCE:
1944                 wndPtr->hInstance = (HINSTANCE)newval;
1945                 retval = (ULONG_PTR)reply->old_instance;
1946                 break;
1947             case GWLP_WNDPROC:
1948                 break;
1949             case GWLP_USERDATA:
1950                 wndPtr->userdata = newval;
1951                 retval = reply->old_user_data;
1952                 break;
1953             default:
1954                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
1955                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
1956                 break;
1957             }
1958         }
1959     }
1960     SERVER_END_REQ;
1961     WIN_ReleasePtr( wndPtr );
1962
1963     if (!ok) return 0;
1964
1965     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
1966
1967     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
1968         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
1969
1970     return retval;
1971 }
1972
1973
1974 /**********************************************************************
1975  *              GetWindowLong (USER.135)
1976  */
1977 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1978 {
1979     WND *wndPtr;
1980     LONG_PTR retvalue;
1981     BOOL is_winproc = (offset == GWLP_WNDPROC);
1982
1983     if (offset >= 0)
1984     {
1985         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
1986         {
1987             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1988             return 0;
1989         }
1990         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
1991         {
1992             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1993             {
1994                 /*
1995                  * Some programs try to access last element from 16 bit
1996                  * code using illegal offset value. Hopefully this is
1997                  * what those programs really expect.
1998                  */
1999                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2000                 {
2001                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2002                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2003                     offset = offset2;
2004                 }
2005                 else
2006                 {
2007                     WARN("Invalid offset %d\n", offset );
2008                     WIN_ReleasePtr( wndPtr );
2009                     SetLastError( ERROR_INVALID_INDEX );
2010                     return 0;
2011                 }
2012             }
2013             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2014             WIN_ReleasePtr( wndPtr );
2015         }
2016     }
2017     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2018     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2019     return retvalue;
2020 }
2021
2022
2023 /**********************************************************************
2024  *              GetWindowWord (USER32.@)
2025  */
2026 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2027 {
2028     switch(offset)
2029     {
2030     case GWLP_ID:
2031     case GWLP_HINSTANCE:
2032     case GWLP_HWNDPARENT:
2033         break;
2034     default:
2035         if (offset < 0)
2036         {
2037             WARN("Invalid offset %d\n", offset );
2038             SetLastError( ERROR_INVALID_INDEX );
2039             return 0;
2040         }
2041         break;
2042     }
2043     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2044 }
2045
2046
2047 /**********************************************************************
2048  *              GetWindowLongA (USER32.@)
2049  */
2050 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2051 {
2052     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2053 }
2054
2055
2056 /**********************************************************************
2057  *              GetWindowLongW (USER32.@)
2058  */
2059 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2060 {
2061     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2062 }
2063
2064
2065 /**********************************************************************
2066  *              SetWindowLong (USER.136)
2067  */
2068 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2069 {
2070     WND *wndPtr;
2071     BOOL is_winproc = (offset == GWLP_WNDPROC);
2072
2073     if (offset == DWLP_DLGPROC)
2074     {
2075         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2076         {
2077             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2078             return 0;
2079         }
2080         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2081         {
2082             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2083                           (wndPtr->flags & WIN_ISDIALOG));
2084             WIN_ReleasePtr( wndPtr );
2085         }
2086     }
2087
2088     if (is_winproc)
2089     {
2090         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2091         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2092         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2093     }
2094     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2095 }
2096
2097
2098 /**********************************************************************
2099  *              SetWindowWord (USER32.@)
2100  */
2101 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2102 {
2103     switch(offset)
2104     {
2105     case GWLP_ID:
2106     case GWLP_HINSTANCE:
2107     case GWLP_HWNDPARENT:
2108         break;
2109     default:
2110         if (offset < 0)
2111         {
2112             WARN("Invalid offset %d\n", offset );
2113             SetLastError( ERROR_INVALID_INDEX );
2114             return 0;
2115         }
2116         break;
2117     }
2118     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2119 }
2120
2121
2122 /**********************************************************************
2123  *              SetWindowLongA (USER32.@)
2124  *
2125  * See SetWindowLongW.
2126  */
2127 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2128 {
2129     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2130 }
2131
2132
2133 /**********************************************************************
2134  *              SetWindowLongW (USER32.@) Set window attribute
2135  *
2136  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2137  * value in a window's extra memory.
2138  *
2139  * The _hwnd_ parameter specifies the window.  is the handle to a
2140  * window that has extra memory. The _newval_ parameter contains the
2141  * new attribute or extra memory value.  If positive, the _offset_
2142  * parameter is the byte-addressed location in the window's extra
2143  * memory to set.  If negative, _offset_ specifies the window
2144  * attribute to set, and should be one of the following values:
2145  *
2146  * GWL_EXSTYLE      The window's extended window style
2147  *
2148  * GWL_STYLE        The window's window style.
2149  *
2150  * GWLP_WNDPROC     Pointer to the window's window procedure.
2151  *
2152  * GWLP_HINSTANCE   The window's pplication instance handle.
2153  *
2154  * GWLP_ID          The window's identifier.
2155  *
2156  * GWLP_USERDATA    The window's user-specified data.
2157  *
2158  * If the window is a dialog box, the _offset_ parameter can be one of
2159  * the following values:
2160  *
2161  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2162  *
2163  * DWLP_MSGRESULT   The return value of a message
2164  *                  that the dialog box procedure processed.
2165  *
2166  * DWLP_USER        Application specific information.
2167  *
2168  * RETURNS
2169  *
2170  * If successful, returns the previous value located at _offset_. Otherwise,
2171  * returns 0.
2172  *
2173  * NOTES
2174  *
2175  * Extra memory for a window class is specified by a nonzero cbWndExtra
2176  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2177  * time of class creation.
2178  *
2179  * Using GWL_WNDPROC to set a new window procedure effectively creates
2180  * a window subclass. Use CallWindowProc() in the new windows procedure
2181  * to pass messages to the superclass's window procedure.
2182  *
2183  * The user data is reserved for use by the application which created
2184  * the window.
2185  *
2186  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2187  * instead, call the EnableWindow() function to change the window's
2188  * disabled state.
2189  *
2190  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2191  * SetParent() instead.
2192  *
2193  * Win95:
2194  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2195  * it sends WM_STYLECHANGING before changing the settings
2196  * and WM_STYLECHANGED afterwards.
2197  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2198  */
2199 LONG WINAPI SetWindowLongW(
2200     HWND hwnd,  /* [in] window to alter */
2201     INT offset, /* [in] offset, in bytes, of location to alter */
2202     LONG newval /* [in] new value of location */
2203 ) {
2204     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2205 }
2206
2207
2208 /*******************************************************************
2209  *              GetWindowTextA (USER32.@)
2210  */
2211 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2212 {
2213     WCHAR *buffer;
2214
2215     if (!lpString) return 0;
2216
2217     if (WIN_IsCurrentProcess( hwnd ))
2218         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2219
2220     /* when window belongs to other process, don't send a message */
2221     if (nMaxCount <= 0) return 0;
2222     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2223     get_server_window_text( hwnd, buffer, nMaxCount );
2224     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2225         lpString[nMaxCount-1] = 0;
2226     HeapFree( GetProcessHeap(), 0, buffer );
2227     return strlen(lpString);
2228 }
2229
2230
2231 /*******************************************************************
2232  *              InternalGetWindowText (USER32.@)
2233  */
2234 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2235 {
2236     WND *win;
2237
2238     if (nMaxCount <= 0) return 0;
2239     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2240     if (win == WND_DESKTOP) lpString[0] = 0;
2241     else if (win != WND_OTHER_PROCESS)
2242     {
2243         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2244         else lpString[0] = 0;
2245         WIN_ReleasePtr( win );
2246     }
2247     else
2248     {
2249         get_server_window_text( hwnd, lpString, nMaxCount );
2250     }
2251     return strlenW(lpString);
2252 }
2253
2254
2255 /*******************************************************************
2256  *              GetWindowTextW (USER32.@)
2257  */
2258 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2259 {
2260     if (!lpString) return 0;
2261
2262     if (WIN_IsCurrentProcess( hwnd ))
2263         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2264
2265     /* when window belongs to other process, don't send a message */
2266     if (nMaxCount <= 0) return 0;
2267     get_server_window_text( hwnd, lpString, nMaxCount );
2268     return strlenW(lpString);
2269 }
2270
2271
2272 /*******************************************************************
2273  *              SetWindowTextA (USER32.@)
2274  *              SetWindowText  (USER32.@)
2275  */
2276 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2277 {
2278     if (is_broadcast(hwnd))
2279     {
2280         SetLastError( ERROR_INVALID_PARAMETER );
2281         return FALSE;
2282     }
2283     if (!WIN_IsCurrentProcess( hwnd ))
2284         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2285                debugstr_a(lpString), hwnd );
2286     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2287 }
2288
2289
2290 /*******************************************************************
2291  *              SetWindowTextW (USER32.@)
2292  */
2293 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2294 {
2295     if (is_broadcast(hwnd))
2296     {
2297         SetLastError( ERROR_INVALID_PARAMETER );
2298         return FALSE;
2299     }
2300     if (!WIN_IsCurrentProcess( hwnd ))
2301         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2302                debugstr_w(lpString), hwnd );
2303     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2304 }
2305
2306
2307 /*******************************************************************
2308  *              GetWindowTextLengthA (USER32.@)
2309  */
2310 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2311 {
2312     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2313 }
2314
2315 /*******************************************************************
2316  *              GetWindowTextLengthW (USER32.@)
2317  */
2318 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2319 {
2320     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2321 }
2322
2323
2324 /*******************************************************************
2325  *              IsWindow (USER32.@)
2326  */
2327 BOOL WINAPI IsWindow( HWND hwnd )
2328 {
2329     WND *ptr;
2330     BOOL ret;
2331
2332     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2333     if (ptr == WND_DESKTOP) return TRUE;
2334
2335     if (ptr != WND_OTHER_PROCESS)
2336     {
2337         WIN_ReleasePtr( ptr );
2338         return TRUE;
2339     }
2340
2341     /* check other processes */
2342     SERVER_START_REQ( get_window_info )
2343     {
2344         req->handle = hwnd;
2345         ret = !wine_server_call_err( req );
2346     }
2347     SERVER_END_REQ;
2348     return ret;
2349 }
2350
2351
2352 /***********************************************************************
2353  *              GetWindowThreadProcessId (USER32.@)
2354  */
2355 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2356 {
2357     WND *ptr;
2358     DWORD tid = 0;
2359
2360     if (!(ptr = WIN_GetPtr( hwnd )))
2361     {
2362         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2363         return 0;
2364     }
2365
2366     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2367     {
2368         /* got a valid window */
2369         tid = ptr->tid;
2370         if (process) *process = GetCurrentProcessId();
2371         WIN_ReleasePtr( ptr );
2372         return tid;
2373     }
2374
2375     /* check other processes */
2376     SERVER_START_REQ( get_window_info )
2377     {
2378         req->handle = hwnd;
2379         if (!wine_server_call_err( req ))
2380         {
2381             tid = (DWORD)reply->tid;
2382             if (process) *process = (DWORD)reply->pid;
2383         }
2384     }
2385     SERVER_END_REQ;
2386     return tid;
2387 }
2388
2389
2390 /*****************************************************************
2391  *              GetParent (USER32.@)
2392  */
2393 HWND WINAPI GetParent( HWND hwnd )
2394 {
2395     WND *wndPtr;
2396     HWND retvalue = 0;
2397
2398     if (!(wndPtr = WIN_GetPtr( hwnd )))
2399     {
2400         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2401         return 0;
2402     }
2403     if (wndPtr == WND_DESKTOP) return 0;
2404     if (wndPtr == WND_OTHER_PROCESS)
2405     {
2406         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2407         if (style & (WS_POPUP | WS_CHILD))
2408         {
2409             SERVER_START_REQ( get_window_tree )
2410             {
2411                 req->handle = hwnd;
2412                 if (!wine_server_call_err( req ))
2413                 {
2414                     if (style & WS_POPUP) retvalue = reply->owner;
2415                     else if (style & WS_CHILD) retvalue = reply->parent;
2416                 }
2417             }
2418             SERVER_END_REQ;
2419         }
2420     }
2421     else
2422     {
2423         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2424         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2425         WIN_ReleasePtr( wndPtr );
2426     }
2427     return retvalue;
2428 }
2429
2430
2431 /*****************************************************************
2432  *              GetAncestor (USER32.@)
2433  */
2434 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2435 {
2436     WND *win;
2437     HWND *list, ret = 0;
2438
2439     switch(type)
2440     {
2441     case GA_PARENT:
2442         if (!(win = WIN_GetPtr( hwnd )))
2443         {
2444             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2445             return 0;
2446         }
2447         if (win == WND_DESKTOP) return 0;
2448         if (win != WND_OTHER_PROCESS)
2449         {
2450             ret = win->parent;
2451             WIN_ReleasePtr( win );
2452         }
2453         else /* need to query the server */
2454         {
2455             SERVER_START_REQ( get_window_tree )
2456             {
2457                 req->handle = hwnd;
2458                 if (!wine_server_call_err( req )) ret = reply->parent;
2459             }
2460             SERVER_END_REQ;
2461         }
2462         break;
2463
2464     case GA_ROOT:
2465         if (!(list = list_window_parents( hwnd ))) return 0;
2466
2467         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2468         else
2469         {
2470             int count = 2;
2471             while (list[count]) count++;
2472             ret = list[count - 2];  /* get the one before the desktop */
2473         }
2474         HeapFree( GetProcessHeap(), 0, list );
2475         break;
2476
2477     case GA_ROOTOWNER:
2478         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2479         for (;;)
2480         {
2481             HWND parent = GetParent( ret );
2482             if (!parent) break;
2483             ret = parent;
2484         }
2485         break;
2486     }
2487     return ret;
2488 }
2489
2490
2491 /*****************************************************************
2492  *              SetParent (USER32.@)
2493  */
2494 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2495 {
2496     HWND full_handle;
2497     HWND old_parent = 0;
2498     BOOL was_visible;
2499     WND *wndPtr;
2500     BOOL ret;
2501
2502     if (is_broadcast(hwnd) || is_broadcast(parent))
2503     {
2504         SetLastError(ERROR_INVALID_PARAMETER);
2505         return 0;
2506     }
2507
2508     if (!parent) parent = GetDesktopWindow();
2509     else parent = WIN_GetFullHandle( parent );
2510
2511     if (!IsWindow( parent ))
2512     {
2513         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2514         return 0;
2515     }
2516
2517     /* Some applications try to set a child as a parent */
2518     if (IsChild(hwnd, parent))
2519     {
2520         SetLastError( ERROR_INVALID_PARAMETER );
2521         return 0;
2522     }
2523
2524     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2525         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2526
2527     /* Windows hides the window first, then shows it again
2528      * including the WM_SHOWWINDOW messages and all */
2529     was_visible = ShowWindow( hwnd, SW_HIDE );
2530
2531     wndPtr = WIN_GetPtr( hwnd );
2532     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2533
2534     SERVER_START_REQ( set_parent )
2535     {
2536         req->handle = hwnd;
2537         req->parent = parent;
2538         if ((ret = !wine_server_call( req )))
2539         {
2540             old_parent = reply->old_parent;
2541             wndPtr->parent = parent = reply->full_parent;
2542         }
2543
2544     }
2545     SERVER_END_REQ;
2546     WIN_ReleasePtr( wndPtr );
2547     if (!ret) return 0;
2548
2549     USER_Driver->pSetParent( full_handle, parent, old_parent );
2550
2551     /* SetParent additionally needs to make hwnd the topmost window
2552        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2553        WM_WINDOWPOSCHANGED notification messages.
2554     */
2555     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2556                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2557     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2558      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2559
2560     return old_parent;
2561 }
2562
2563
2564 /*******************************************************************
2565  *              IsChild (USER32.@)
2566  */
2567 BOOL WINAPI IsChild( HWND parent, HWND child )
2568 {
2569     HWND *list = list_window_parents( child );
2570     int i;
2571     BOOL ret;
2572
2573     if (!list) return FALSE;
2574     parent = WIN_GetFullHandle( parent );
2575     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2576     ret = list[i] && list[i+1];
2577     HeapFree( GetProcessHeap(), 0, list );
2578     return ret;
2579 }
2580
2581
2582 /***********************************************************************
2583  *              IsWindowVisible (USER32.@)
2584  */
2585 BOOL WINAPI IsWindowVisible( HWND hwnd )
2586 {
2587     HWND *list;
2588     BOOL retval = TRUE;
2589     int i;
2590
2591     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2592     if (!(list = list_window_parents( hwnd ))) return TRUE;
2593     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2594     {
2595         for (i = 0; list[i+1]; i++)
2596             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2597         retval = !list[i+1];
2598     }
2599     HeapFree( GetProcessHeap(), 0, list );
2600     return retval;
2601 }
2602
2603
2604 /***********************************************************************
2605  *           WIN_IsWindowDrawable
2606  *
2607  * hwnd is drawable when it is visible, all parents are not
2608  * minimized, and it is itself not minimized unless we are
2609  * trying to draw its default class icon.
2610  */
2611 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2612 {
2613     HWND *list;
2614     BOOL retval = TRUE;
2615     int i;
2616     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2617
2618     if (!(style & WS_VISIBLE)) return FALSE;
2619     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2620
2621     if (!(list = list_window_parents( hwnd ))) return TRUE;
2622     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2623     {
2624         for (i = 0; list[i+1]; i++)
2625             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2626                 break;
2627         retval = !list[i+1];
2628     }
2629     HeapFree( GetProcessHeap(), 0, list );
2630     return retval;
2631 }
2632
2633
2634 /*******************************************************************
2635  *              GetTopWindow (USER32.@)
2636  */
2637 HWND WINAPI GetTopWindow( HWND hwnd )
2638 {
2639     if (!hwnd) hwnd = GetDesktopWindow();
2640     return GetWindow( hwnd, GW_CHILD );
2641 }
2642
2643
2644 /*******************************************************************
2645  *              GetWindow (USER32.@)
2646  */
2647 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2648 {
2649     HWND retval = 0;
2650
2651     if (rel == GW_OWNER)  /* this one may be available locally */
2652     {
2653         WND *wndPtr = WIN_GetPtr( hwnd );
2654         if (!wndPtr)
2655         {
2656             SetLastError( ERROR_INVALID_HANDLE );
2657             return 0;
2658         }
2659         if (wndPtr == WND_DESKTOP) return 0;
2660         if (wndPtr != WND_OTHER_PROCESS)
2661         {
2662             retval = wndPtr->owner;
2663             WIN_ReleasePtr( wndPtr );
2664             return retval;
2665         }
2666         /* else fall through to server call */
2667     }
2668
2669     SERVER_START_REQ( get_window_tree )
2670     {
2671         req->handle = hwnd;
2672         if (!wine_server_call_err( req ))
2673         {
2674             switch(rel)
2675             {
2676             case GW_HWNDFIRST:
2677                 retval = reply->first_sibling;
2678                 break;
2679             case GW_HWNDLAST:
2680                 retval = reply->last_sibling;
2681                 break;
2682             case GW_HWNDNEXT:
2683                 retval = reply->next_sibling;
2684                 break;
2685             case GW_HWNDPREV:
2686                 retval = reply->prev_sibling;
2687                 break;
2688             case GW_OWNER:
2689                 retval = reply->owner;
2690                 break;
2691             case GW_CHILD:
2692                 retval = reply->first_child;
2693                 break;
2694             }
2695         }
2696     }
2697     SERVER_END_REQ;
2698     return retval;
2699 }
2700
2701
2702 /*******************************************************************
2703  *              ShowOwnedPopups (USER32.@)
2704  */
2705 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2706 {
2707     int count = 0;
2708     WND *pWnd;
2709     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2710
2711     if (!win_array) return TRUE;
2712
2713     while (win_array[count]) count++;
2714     while (--count >= 0)
2715     {
2716         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2717         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2718         if (pWnd == WND_OTHER_PROCESS) continue;
2719         if (fShow)
2720         {
2721             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2722             {
2723                 WIN_ReleasePtr( pWnd );
2724                 /* In Windows, ShowOwnedPopups(TRUE) generates
2725                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2726                  * regardless of the state of the owner
2727                  */
2728                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2729                 continue;
2730             }
2731         }
2732         else
2733         {
2734             if (pWnd->dwStyle & WS_VISIBLE)
2735             {
2736                 WIN_ReleasePtr( pWnd );
2737                 /* In Windows, ShowOwnedPopups(FALSE) generates
2738                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2739                  * regardless of the state of the owner
2740                  */
2741                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2742                 continue;
2743             }
2744         }
2745         WIN_ReleasePtr( pWnd );
2746     }
2747     HeapFree( GetProcessHeap(), 0, win_array );
2748     return TRUE;
2749 }
2750
2751
2752 /*******************************************************************
2753  *              GetLastActivePopup (USER32.@)
2754  */
2755 HWND WINAPI GetLastActivePopup( HWND hwnd )
2756 {
2757     HWND retval = hwnd;
2758
2759     SERVER_START_REQ( get_window_info )
2760     {
2761         req->handle = hwnd;
2762         if (!wine_server_call_err( req )) retval = reply->last_active;
2763     }
2764     SERVER_END_REQ;
2765     return retval;
2766 }
2767
2768
2769 /*******************************************************************
2770  *           WIN_ListChildren
2771  *
2772  * Build an array of the children of a given window. The array must be
2773  * freed with HeapFree. Returns NULL when no windows are found.
2774  */
2775 HWND *WIN_ListChildren( HWND hwnd )
2776 {
2777     return list_window_children( hwnd, 0, 0 );
2778 }
2779
2780
2781 /*******************************************************************
2782  *              EnumWindows (USER32.@)
2783  */
2784 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2785 {
2786     HWND *list;
2787     BOOL ret = TRUE;
2788     int i;
2789
2790     USER_CheckNotLock();
2791
2792     /* We have to build a list of all windows first, to avoid */
2793     /* unpleasant side-effects, for instance if the callback */
2794     /* function changes the Z-order of the windows.          */
2795
2796     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2797
2798     /* Now call the callback function for every window */
2799
2800     for (i = 0; list[i]; i++)
2801     {
2802         /* Make sure that the window still exists */
2803         if (!IsWindow( list[i] )) continue;
2804         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2805     }
2806     HeapFree( GetProcessHeap(), 0, list );
2807     return ret;
2808 }
2809
2810
2811 /**********************************************************************
2812  *              EnumThreadWindows (USER32.@)
2813  */
2814 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2815 {
2816     HWND *list;
2817     int i;
2818
2819     USER_CheckNotLock();
2820
2821     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2822
2823     /* Now call the callback function for every window */
2824
2825     for (i = 0; list[i]; i++)
2826         if (!func( list[i], lParam )) break;
2827     HeapFree( GetProcessHeap(), 0, list );
2828     return TRUE;
2829 }
2830
2831
2832 /**********************************************************************
2833  *           WIN_EnumChildWindows
2834  *
2835  * Helper function for EnumChildWindows().
2836  */
2837 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2838 {
2839     HWND *childList;
2840     BOOL ret = FALSE;
2841
2842     for ( ; *list; list++)
2843     {
2844         /* Make sure that the window still exists */
2845         if (!IsWindow( *list )) continue;
2846         /* Build children list first */
2847         childList = WIN_ListChildren( *list );
2848
2849         ret = func( *list, lParam );
2850
2851         if (childList)
2852         {
2853             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2854             HeapFree( GetProcessHeap(), 0, childList );
2855         }
2856         if (!ret) return FALSE;
2857     }
2858     return TRUE;
2859 }
2860
2861
2862 /**********************************************************************
2863  *              EnumChildWindows (USER32.@)
2864  */
2865 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2866 {
2867     HWND *list;
2868     BOOL ret;
2869
2870     USER_CheckNotLock();
2871
2872     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2873     ret = WIN_EnumChildWindows( list, func, lParam );
2874     HeapFree( GetProcessHeap(), 0, list );
2875     return ret;
2876 }
2877
2878
2879 /*******************************************************************
2880  *              AnyPopup (USER.52)
2881  */
2882 BOOL16 WINAPI AnyPopup16(void)
2883 {
2884     return AnyPopup();
2885 }
2886
2887
2888 /*******************************************************************
2889  *              AnyPopup (USER32.@)
2890  */
2891 BOOL WINAPI AnyPopup(void)
2892 {
2893     int i;
2894     BOOL retvalue;
2895     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2896
2897     if (!list) return FALSE;
2898     for (i = 0; list[i]; i++)
2899     {
2900         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2901     }
2902     retvalue = (list[i] != 0);
2903     HeapFree( GetProcessHeap(), 0, list );
2904     return retvalue;
2905 }
2906
2907
2908 /*******************************************************************
2909  *              FlashWindow (USER32.@)
2910  */
2911 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2912 {
2913     WND *wndPtr;
2914
2915     TRACE("%p\n", hWnd);
2916
2917     if (IsIconic( hWnd ))
2918     {
2919         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2920
2921         wndPtr = WIN_GetPtr(hWnd);
2922         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2923         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2924         {
2925             wndPtr->flags |= WIN_NCACTIVATED;
2926         }
2927         else
2928         {
2929             wndPtr->flags &= ~WIN_NCACTIVATED;
2930         }
2931         WIN_ReleasePtr( wndPtr );
2932         return TRUE;
2933     }
2934     else
2935     {
2936         WPARAM wparam;
2937
2938         wndPtr = WIN_GetPtr(hWnd);
2939         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2940         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2941
2942         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2943         else wparam = (hWnd == GetForegroundWindow());
2944
2945         WIN_ReleasePtr( wndPtr );
2946         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2947         return wparam;
2948     }
2949 }
2950
2951 /*******************************************************************
2952  *              FlashWindowEx (USER32.@)
2953  */
2954 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2955 {
2956     FIXME("%p\n", pfwi);
2957     return TRUE;
2958 }
2959
2960 /*******************************************************************
2961  *              GetWindowContextHelpId (USER32.@)
2962  */
2963 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2964 {
2965     DWORD retval;
2966     WND *wnd = WIN_GetPtr( hwnd );
2967     if (!wnd || wnd == WND_DESKTOP) return 0;
2968     if (wnd == WND_OTHER_PROCESS)
2969     {
2970         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2971         return 0;
2972     }
2973     retval = wnd->helpContext;
2974     WIN_ReleasePtr( wnd );
2975     return retval;
2976 }
2977
2978
2979 /*******************************************************************
2980  *              SetWindowContextHelpId (USER32.@)
2981  */
2982 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2983 {
2984     WND *wnd = WIN_GetPtr( hwnd );
2985     if (!wnd || wnd == WND_DESKTOP) return FALSE;
2986     if (wnd == WND_OTHER_PROCESS)
2987     {
2988         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2989         return 0;
2990     }
2991     wnd->helpContext = id;
2992     WIN_ReleasePtr( wnd );
2993     return TRUE;
2994 }
2995
2996
2997 /*******************************************************************
2998  *              DragDetect (USER32.@)
2999  */
3000 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3001 {
3002     MSG msg;
3003     RECT rect;
3004     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3005     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3006
3007     rect.left = pt.x - wDragWidth;
3008     rect.right = pt.x + wDragWidth;
3009
3010     rect.top = pt.y - wDragHeight;
3011     rect.bottom = pt.y + wDragHeight;
3012
3013     SetCapture(hWnd);
3014
3015     while(1)
3016     {
3017         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3018         {
3019             if( msg.message == WM_LBUTTONUP )
3020             {
3021                 ReleaseCapture();
3022                 return 0;
3023             }
3024             if( msg.message == WM_MOUSEMOVE )
3025             {
3026                 POINT tmp;
3027                 tmp.x = (short)LOWORD(msg.lParam);
3028                 tmp.y = (short)HIWORD(msg.lParam);
3029                 if( !PtInRect( &rect, tmp ))
3030                 {
3031                     ReleaseCapture();
3032                     return 1;
3033                 }
3034             }
3035         }
3036         WaitMessage();
3037     }
3038     return 0;
3039 }
3040
3041 /******************************************************************************
3042  *              GetWindowModuleFileNameA (USER32.@)
3043  */
3044 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3045 {
3046     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3047           hwnd, lpszFileName, cchFileNameMax);
3048     return 0;
3049 }
3050
3051 /******************************************************************************
3052  *              GetWindowModuleFileNameW (USER32.@)
3053  */
3054 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3055 {
3056     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3057           hwnd, lpszFileName, cchFileNameMax);
3058     return 0;
3059 }
3060
3061 /******************************************************************************
3062  *              GetWindowInfo (USER32.@)
3063  *
3064  * Note: tests show that Windows doesn't check cbSize of the structure.
3065  */
3066 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3067 {
3068     if (!pwi) return FALSE;
3069     if (!IsWindow(hwnd)) return FALSE;
3070
3071     GetWindowRect(hwnd, &pwi->rcWindow);
3072     GetClientRect(hwnd, &pwi->rcClient);
3073     /* translate to screen coordinates */
3074     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3075
3076     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3077     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3078     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3079
3080     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3081     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3082
3083     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3084     pwi->wCreatorVersion = 0x0400;
3085
3086     return TRUE;
3087 }
3088
3089 /******************************************************************************
3090  *              SwitchDesktop (USER32.@)
3091  *
3092  * NOTES: Sets the current input or interactive desktop.
3093  */
3094 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3095 {
3096     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3097     return TRUE;
3098 }
3099
3100 /*****************************************************************************
3101  *              SetLayeredWindowAttributes (USER32.@)
3102  */
3103 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3104                                         BYTE bAlpha, DWORD dwFlags )
3105 {
3106     FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3107     return TRUE;
3108 }
3109
3110 /*****************************************************************************
3111  *              UpdateLayeredWindow (USER32.@)
3112  */
3113 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3114                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3115                                  DWORD dwFlags)
3116 {
3117     static int once;
3118     if (!once)
3119     {
3120         once = 1;
3121         FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3122               hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3123     }
3124     return 0;
3125 }
3126
3127 /* 64bit versions */
3128
3129 #ifdef GetWindowLongPtrW
3130 #undef GetWindowLongPtrW
3131 #endif
3132
3133 #ifdef GetWindowLongPtrA
3134 #undef GetWindowLongPtrA
3135 #endif
3136
3137 #ifdef SetWindowLongPtrW
3138 #undef SetWindowLongPtrW
3139 #endif
3140
3141 #ifdef SetWindowLongPtrA
3142 #undef SetWindowLongPtrA
3143 #endif
3144
3145 /*****************************************************************************
3146  *              GetWindowLongPtrW (USER32.@)
3147  */
3148 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3149 {
3150     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3151 }
3152
3153 /*****************************************************************************
3154  *              GetWindowLongPtrA (USER32.@)
3155  */
3156 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3157 {
3158     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3159 }
3160
3161 /*****************************************************************************
3162  *              SetWindowLongPtrW (USER32.@)
3163  */
3164 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3165 {
3166     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3167 }
3168
3169 /*****************************************************************************
3170  *              SetWindowLongPtrA (USER32.@)
3171  */
3172 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3173 {
3174     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3175 }