user32: Generate WM_APPCOMMAND messages for browser and multimedia keys.
[wine] / dlls / user32 / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "winproc.h"
37 #include "user_private.h"
38 #include "controls.h"
39 #include "winerror.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(win);
43
44 #define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
45 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
46
47 /**********************************************************************/
48
49 /* helper for Get/SetWindowLong */
50 static inline LONG_PTR get_win_data( const void *ptr, UINT size )
51 {
52     if (size == sizeof(WORD))
53     {
54         WORD ret;
55         memcpy( &ret, ptr, sizeof(ret) );
56         return ret;
57     }
58     else if (size == sizeof(DWORD))
59     {
60         DWORD ret;
61         memcpy( &ret, ptr, sizeof(ret) );
62         return ret;
63     }
64     else
65     {
66         LONG_PTR ret;
67         memcpy( &ret, ptr, sizeof(ret) );
68         return ret;
69     }
70 }
71
72 /* helper for Get/SetWindowLong */
73 static inline void set_win_data( void *ptr, LONG_PTR val, UINT size )
74 {
75     if (size == sizeof(WORD))
76     {
77         WORD newval = val;
78         memcpy( ptr, &newval, sizeof(newval) );
79     }
80     else if (size == sizeof(DWORD))
81     {
82         DWORD newval = val;
83         memcpy( ptr, &newval, sizeof(newval) );
84     }
85     else
86     {
87         memcpy( ptr, &val, sizeof(val) );
88     }
89 }
90
91
92 static void *user_handles[NB_USER_HANDLES];
93
94 /***********************************************************************
95  *           create_window_handle
96  *
97  * Create a window handle with the server.
98  */
99 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
100                                   HINSTANCE instance, BOOL unicode )
101 {
102     WORD index;
103     WND *win;
104     HWND full_parent = 0, full_owner = 0;
105     struct tagCLASS *class = NULL;
106     user_handle_t handle = 0;
107     int extra_bytes = 0;
108
109     /* if 16-bit instance, map to module handle */
110     if (instance && !HIWORD(instance))
111         instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
112
113     SERVER_START_REQ( create_window )
114     {
115         req->parent   = parent;
116         req->owner    = owner;
117         req->atom     = atom;
118         req->instance = instance;
119         if (!wine_server_call_err( req ))
120         {
121             handle = reply->handle;
122             full_parent = reply->parent;
123             full_owner  = reply->owner;
124             extra_bytes = reply->extra;
125             class = reply->class_ptr;
126         }
127     }
128     SERVER_END_REQ;
129
130     if (!handle)
131     {
132         WARN( "error %d creating window\n", GetLastError() );
133         return NULL;
134     }
135
136     if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
137     {
138         SERVER_START_REQ( destroy_window )
139         {
140             req->handle = handle;
141             wine_server_call( req );
142         }
143         SERVER_END_REQ;
144         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
145         return NULL;
146     }
147
148     if (!parent)  /* if parent is 0 we don't have a desktop window yet */
149     {
150         struct user_thread_info *thread_info = get_user_thread_info();
151
152         assert( !thread_info->desktop );
153         thread_info->desktop = full_parent ? full_parent : handle;
154         if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
155             ERR( "failed to create desktop window\n" );
156     }
157
158     USER_Lock();
159
160     index = USER_HANDLE_TO_INDEX(handle);
161     assert( index < NB_USER_HANDLES );
162     user_handles[index] = win;
163     win->hwndSelf   = handle;
164     win->parent     = full_parent;
165     win->owner      = full_owner;
166     win->dwMagic    = WND_MAGIC;
167     win->flags      = 0;
168     win->cbWndExtra = extra_bytes;
169     memset( win->wExtra, 0, extra_bytes );
170     CLASS_AddWindow( class, win, unicode );
171     return win;
172 }
173
174
175 /***********************************************************************
176  *           free_window_handle
177  *
178  * Free a window handle.
179  */
180 static WND *free_window_handle( HWND hwnd )
181 {
182     WND *ptr;
183     WORD index = USER_HANDLE_TO_INDEX(hwnd);
184
185     if (index >= NB_USER_HANDLES) return NULL;
186     USER_Lock();
187     if ((ptr = user_handles[index]))
188     {
189         SERVER_START_REQ( destroy_window )
190         {
191             req->handle = hwnd;
192             if (!wine_server_call_err( req ))
193             {
194                 user_handles[index] = NULL;
195                 ptr->dwMagic = 0;
196             }
197             else
198                 ptr = NULL;
199         }
200         SERVER_END_REQ;
201     }
202     USER_Unlock();
203     HeapFree( GetProcessHeap(), 0, ptr );
204     return ptr;
205 }
206
207
208 /*******************************************************************
209  *           list_window_children
210  *
211  * Build an array of the children of a given window. The array must be
212  * freed with HeapFree. Returns NULL when no windows are found.
213  */
214 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
215 {
216     HWND *list;
217     int size = 32;
218
219     for (;;)
220     {
221         int count = 0;
222
223         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
224
225         SERVER_START_REQ( get_window_children )
226         {
227             req->parent = hwnd;
228             req->atom = atom;
229             req->tid = tid;
230             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
231             if (!wine_server_call( req )) count = reply->count;
232         }
233         SERVER_END_REQ;
234         if (count && count < size)
235         {
236             list[count] = 0;
237             return list;
238         }
239         HeapFree( GetProcessHeap(), 0, list );
240         if (!count) break;
241         size = count + 1;  /* restart with a large enough buffer */
242     }
243     return NULL;
244 }
245
246
247 /*******************************************************************
248  *           list_window_parents
249  *
250  * Build an array of all parents of a given window, starting with
251  * the immediate parent. The array must be freed with HeapFree.
252  */
253 static HWND *list_window_parents( HWND hwnd )
254 {
255     WND *win;
256     HWND current, *list;
257     int pos = 0, size = 16, count = 0;
258
259     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
260
261     current = hwnd;
262     for (;;)
263     {
264         if (!(win = WIN_GetPtr( current ))) goto empty;
265         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
266         if (win == WND_DESKTOP)
267         {
268             if (!pos) goto empty;
269             list[pos] = 0;
270             return list;
271         }
272         list[pos] = current = win->parent;
273         WIN_ReleasePtr( win );
274         if (++pos == size - 1)
275         {
276             /* need to grow the list */
277             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
278             if (!new_list) goto empty;
279             list = new_list;
280             size += 16;
281         }
282     }
283
284     /* at least one parent belongs to another process, have to query the server */
285
286     for (;;)
287     {
288         count = 0;
289         SERVER_START_REQ( get_window_parents )
290         {
291             req->handle = hwnd;
292             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
293             if (!wine_server_call( req )) count = reply->count;
294         }
295         SERVER_END_REQ;
296         if (!count) goto empty;
297         if (size > count)
298         {
299             list[count] = 0;
300             return list;
301         }
302         HeapFree( GetProcessHeap(), 0, list );
303         size = count + 1;
304         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
305     }
306
307  empty:
308     HeapFree( GetProcessHeap(), 0, list );
309     return NULL;
310 }
311
312
313 /*******************************************************************
314  *           send_parent_notify
315  */
316 static void send_parent_notify( HWND hwnd, UINT msg )
317 {
318     if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
319         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
320     {
321         HWND parent = GetParent(hwnd);
322         if (parent && parent != GetDesktopWindow())
323             SendMessageW( parent, WM_PARENTNOTIFY,
324                           MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
325     }
326 }
327
328
329 /*******************************************************************
330  *              get_server_window_text
331  *
332  * Retrieve the window text from the server.
333  */
334 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
335 {
336     size_t len = 0;
337
338     SERVER_START_REQ( get_window_text )
339     {
340         req->handle = hwnd;
341         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
342         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
343     }
344     SERVER_END_REQ;
345     text[len / sizeof(WCHAR)] = 0;
346 }
347
348
349 /***********************************************************************
350  *           WIN_GetPtr
351  *
352  * Return a pointer to the WND structure if local to the process,
353  * or WND_OTHER_PROCESS if handle may be valid in other process.
354  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
355  */
356 WND *WIN_GetPtr( HWND hwnd )
357 {
358     WND * ptr;
359     WORD index = USER_HANDLE_TO_INDEX(hwnd);
360
361     if (index >= NB_USER_HANDLES) return NULL;
362
363     USER_Lock();
364     if ((ptr = user_handles[index]))
365     {
366         if (ptr->dwMagic == WND_MAGIC &&
367             (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
368             return ptr;
369         ptr = NULL;
370     }
371     else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
372     {
373         if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
374         else ptr = NULL;
375     }
376     else ptr = WND_OTHER_PROCESS;
377     USER_Unlock();
378     return ptr;
379 }
380
381
382 /***********************************************************************
383  *           WIN_IsCurrentProcess
384  *
385  * Check whether a given window belongs to the current process (and return the full handle).
386  */
387 HWND WIN_IsCurrentProcess( HWND hwnd )
388 {
389     WND *ptr;
390     HWND ret;
391
392     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
393     ret = ptr->hwndSelf;
394     WIN_ReleasePtr( ptr );
395     return ret;
396 }
397
398
399 /***********************************************************************
400  *           WIN_IsCurrentThread
401  *
402  * Check whether a given window belongs to the current thread (and return the full handle).
403  */
404 HWND WIN_IsCurrentThread( HWND hwnd )
405 {
406     WND *ptr;
407     HWND ret = 0;
408
409     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
410     if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
411     WIN_ReleasePtr( ptr );
412     return ret;
413 }
414
415
416 /***********************************************************************
417  *           WIN_Handle32
418  *
419  * Convert a 16-bit window handle to a full 32-bit handle.
420  */
421 HWND WIN_Handle32( HWND16 hwnd16 )
422 {
423     WND *ptr;
424     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
425
426     if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
427     /* do sign extension for -2 and -3 */
428     if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
429
430     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
431
432     if (ptr == WND_DESKTOP) return GetDesktopWindow();
433
434     if (ptr != WND_OTHER_PROCESS)
435     {
436         hwnd = ptr->hwndSelf;
437         WIN_ReleasePtr( ptr );
438     }
439     else  /* may belong to another process */
440     {
441         SERVER_START_REQ( get_window_info )
442         {
443             req->handle = hwnd;
444             if (!wine_server_call_err( req )) hwnd = reply->full_handle;
445         }
446         SERVER_END_REQ;
447     }
448     return hwnd;
449 }
450
451
452 /***********************************************************************
453  *           WIN_SetOwner
454  *
455  * Change the owner of a window.
456  */
457 HWND WIN_SetOwner( HWND hwnd, HWND owner )
458 {
459     WND *win = WIN_GetPtr( hwnd );
460     HWND ret = 0;
461
462     if (!win || win == WND_DESKTOP) return 0;
463     if (win == WND_OTHER_PROCESS)
464     {
465         if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
466         return 0;
467     }
468     SERVER_START_REQ( set_window_owner )
469     {
470         req->handle = hwnd;
471         req->owner  = owner;
472         if (!wine_server_call( req ))
473         {
474             win->owner = reply->full_owner;
475             ret = reply->prev_owner;
476         }
477     }
478     SERVER_END_REQ;
479     WIN_ReleasePtr( win );
480     return ret;
481 }
482
483
484 /***********************************************************************
485  *           WIN_SetStyle
486  *
487  * Change the style of a window.
488  */
489 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
490 {
491     BOOL ok;
492     ULONG new_style, old_style = 0;
493     WND *win = WIN_GetPtr( hwnd );
494
495     if (!win || win == WND_DESKTOP) return 0;
496     if (win == WND_OTHER_PROCESS)
497     {
498         if (IsWindow(hwnd))
499             ERR( "cannot set style %x/%x on other process window %p\n",
500                  set_bits, clear_bits, hwnd );
501         return 0;
502     }
503     new_style = (win->dwStyle | set_bits) & ~clear_bits;
504     if (new_style == win->dwStyle)
505     {
506         WIN_ReleasePtr( win );
507         return new_style;
508     }
509     SERVER_START_REQ( set_window_info )
510     {
511         req->handle = hwnd;
512         req->flags  = SET_WIN_STYLE;
513         req->style  = new_style;
514         req->extra_offset = -1;
515         if ((ok = !wine_server_call( req )))
516         {
517             old_style = reply->old_style;
518             win->dwStyle = new_style;
519         }
520     }
521     SERVER_END_REQ;
522     WIN_ReleasePtr( win );
523     if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
524     return old_style;
525 }
526
527
528 /***********************************************************************
529  *           WIN_GetRectangles
530  *
531  * Get the window and client rectangles.
532  */
533 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
534 {
535     WND *win = WIN_GetPtr( hwnd );
536     BOOL ret = TRUE;
537
538     if (!win) return FALSE;
539     if (win == WND_DESKTOP)
540     {
541         RECT rect;
542         rect.left = rect.top = 0;
543         rect.right  = GetSystemMetrics(SM_CXSCREEN);
544         rect.bottom = GetSystemMetrics(SM_CYSCREEN);
545         if (rectWindow) *rectWindow = rect;
546         if (rectClient) *rectClient = rect;
547     }
548     else if (win == WND_OTHER_PROCESS)
549     {
550         SERVER_START_REQ( get_window_rectangles )
551         {
552             req->handle = hwnd;
553             if ((ret = !wine_server_call( req )))
554             {
555                 if (rectWindow)
556                 {
557                     rectWindow->left   = reply->window.left;
558                     rectWindow->top    = reply->window.top;
559                     rectWindow->right  = reply->window.right;
560                     rectWindow->bottom = reply->window.bottom;
561                 }
562                 if (rectClient)
563                 {
564                     rectClient->left   = reply->client.left;
565                     rectClient->top    = reply->client.top;
566                     rectClient->right  = reply->client.right;
567                     rectClient->bottom = reply->client.bottom;
568                 }
569             }
570         }
571         SERVER_END_REQ;
572     }
573     else
574     {
575         if (rectWindow) *rectWindow = win->rectWindow;
576         if (rectClient) *rectClient = win->rectClient;
577         WIN_ReleasePtr( win );
578     }
579     return ret;
580 }
581
582
583 /***********************************************************************
584  *           WIN_DestroyWindow
585  *
586  * Destroy storage associated to a window. "Internals" p.358
587  */
588 LRESULT WIN_DestroyWindow( HWND hwnd )
589 {
590     WND *wndPtr;
591     HWND *list;
592     HMENU menu = 0, sys_menu;
593
594     TRACE("%p\n", hwnd );
595
596     /* free child windows */
597     if ((list = WIN_ListChildren( hwnd )))
598     {
599         int i;
600         for (i = 0; list[i]; i++)
601         {
602             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
603             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
604         }
605         HeapFree( GetProcessHeap(), 0, list );
606     }
607
608     /* Unlink now so we won't bother with the children later on */
609     SERVER_START_REQ( set_parent )
610     {
611         req->handle = hwnd;
612         req->parent = 0;
613         wine_server_call( req );
614     }
615     SERVER_END_REQ;
616
617     /*
618      * Send the WM_NCDESTROY to the window being destroyed.
619      */
620     SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
621
622     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
623
624     WINPOS_CheckInternalPos( hwnd );
625
626     /* free resources associated with the window */
627
628     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
629     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
630         menu = (HMENU)wndPtr->wIDmenu;
631     sys_menu = wndPtr->hSysMenu;
632     WIN_ReleasePtr( wndPtr );
633
634     if (menu) DestroyMenu( menu );
635     if (sys_menu) DestroyMenu( sys_menu );
636
637     USER_Driver->pDestroyWindow( hwnd );
638
639     free_window_handle( hwnd );
640     return 0;
641 }
642
643 /***********************************************************************
644  *           WIN_DestroyThreadWindows
645  *
646  * Destroy all children of 'wnd' owned by the current thread.
647  */
648 void WIN_DestroyThreadWindows( HWND hwnd )
649 {
650     HWND *list;
651     int i;
652
653     if (!(list = WIN_ListChildren( hwnd ))) return;
654     for (i = 0; list[i]; i++)
655     {
656         if (WIN_IsCurrentThread( list[i] ))
657             DestroyWindow( list[i] );
658         else
659             WIN_DestroyThreadWindows( list[i] );
660     }
661     HeapFree( GetProcessHeap(), 0, list );
662 }
663
664
665 /***********************************************************************
666  *           WIN_FixCoordinates
667  *
668  * Fix the coordinates - Helper for WIN_CreateWindowEx.
669  * returns default show mode in sw.
670  */
671 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
672 {
673 #define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == CW_USEDEFAULT16)
674     POINT pos[2];
675
676     if (cs->dwExStyle & WS_EX_MDICHILD)
677     {
678         UINT id = 0;
679
680         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
681         if (!(cs->style & WS_POPUP)) cs->hMenu = (HMENU)id;
682
683         TRACE("MDI child id %04x\n", id);
684     }
685
686     if (cs->style & (WS_CHILD | WS_POPUP))
687     {
688         if (cs->dwExStyle & WS_EX_MDICHILD)
689         {
690             if (IS_DEFAULT(cs->x))
691             {
692                 cs->x = pos[0].x;
693                 cs->y = pos[0].y;
694             }
695             if (IS_DEFAULT(cs->cx) || !cs->cx) cs->cx = pos[1].x;
696             if (IS_DEFAULT(cs->cy) || !cs->cy) cs->cy = pos[1].y;
697         }
698         else
699         {
700             if (IS_DEFAULT(cs->x)) cs->x = cs->y = 0;
701             if (IS_DEFAULT(cs->cx)) cs->cx = cs->cy = 0;
702         }
703     }
704     else  /* overlapped window */
705     {
706         HMONITOR monitor;
707         MONITORINFO mon_info;
708         STARTUPINFOW info;
709
710         if (!IS_DEFAULT(cs->x) && !IS_DEFAULT(cs->cx) && !IS_DEFAULT(cs->cy)) return;
711
712         monitor = MonitorFromWindow( cs->hwndParent, MONITOR_DEFAULTTOPRIMARY );
713         mon_info.cbSize = sizeof(mon_info);
714         GetMonitorInfoW( monitor, &mon_info );
715         GetStartupInfoW( &info );
716
717         if (IS_DEFAULT(cs->x))
718         {
719             if (!IS_DEFAULT(cs->y)) *sw = cs->y;
720             cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : mon_info.rcWork.left;
721             cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : mon_info.rcWork.top;
722         }
723
724         if (IS_DEFAULT(cs->cx))
725         {
726             if (info.dwFlags & STARTF_USESIZE)
727             {
728                 cs->cx = info.dwXSize;
729                 cs->cy = info.dwYSize;
730             }
731             else
732             {
733                 cs->cx = (mon_info.rcWork.right - mon_info.rcWork.left) * 3 / 4 - cs->x;
734                 cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
735             }
736         }
737         /* neither x nor cx are default. Check the y values .
738          * In the trace we see Outlook and Outlook Express using
739          * cy set to CW_USEDEFAULT when opening the address book.
740          */
741         else if (IS_DEFAULT(cs->cy))
742         {
743             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
744             cs->cy = (mon_info.rcWork.bottom - mon_info.rcWork.top) * 3 / 4 - cs->y;
745         }
746     }
747 #undef IS_DEFAULT
748 }
749
750 /***********************************************************************
751  *           dump_window_styles
752  */
753 static void dump_window_styles( DWORD style, DWORD exstyle )
754 {
755     TRACE( "style:" );
756     if(style & WS_POPUP) TRACE(" WS_POPUP");
757     if(style & WS_CHILD) TRACE(" WS_CHILD");
758     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
759     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
760     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
761     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
762     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
763     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
764     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
765     else
766     {
767         if(style & WS_BORDER) TRACE(" WS_BORDER");
768         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
769     }
770     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
771     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
772     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
773     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
774     if (style & WS_CHILD)
775     {
776         if(style & WS_GROUP) TRACE(" WS_GROUP");
777         if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
778     }
779     else
780     {
781         if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
782         if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
783     }
784
785     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
786 #define DUMPED_STYLES \
787     (WS_POPUP | \
788      WS_CHILD | \
789      WS_MINIMIZE | \
790      WS_VISIBLE | \
791      WS_DISABLED | \
792      WS_CLIPSIBLINGS | \
793      WS_CLIPCHILDREN | \
794      WS_MAXIMIZE | \
795      WS_BORDER | \
796      WS_DLGFRAME | \
797      WS_VSCROLL | \
798      WS_HSCROLL | \
799      WS_SYSMENU | \
800      WS_THICKFRAME | \
801      WS_GROUP | \
802      WS_TABSTOP | \
803      WS_MINIMIZEBOX | \
804      WS_MAXIMIZEBOX)
805
806     if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
807     TRACE("\n");
808 #undef DUMPED_STYLES
809
810     TRACE( "exstyle:" );
811     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
812     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
813     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
814     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
815     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
816     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
817     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
818     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
819     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
820     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
821     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
822     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
823     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
824     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
825     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
826     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
827     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
828     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
829
830 #define DUMPED_EX_STYLES \
831     (WS_EX_DLGMODALFRAME | \
832      WS_EX_DRAGDETECT | \
833      WS_EX_NOPARENTNOTIFY | \
834      WS_EX_TOPMOST | \
835      WS_EX_ACCEPTFILES | \
836      WS_EX_TRANSPARENT | \
837      WS_EX_MDICHILD | \
838      WS_EX_TOOLWINDOW | \
839      WS_EX_WINDOWEDGE | \
840      WS_EX_CLIENTEDGE | \
841      WS_EX_CONTEXTHELP | \
842      WS_EX_RIGHT | \
843      WS_EX_RTLREADING | \
844      WS_EX_LEFTSCROLLBAR | \
845      WS_EX_CONTROLPARENT | \
846      WS_EX_STATICEDGE | \
847      WS_EX_APPWINDOW | \
848      WS_EX_LAYERED)
849
850     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
851     TRACE("\n");
852 #undef DUMPED_EX_STYLES
853 }
854
855
856 /***********************************************************************
857  *           WIN_CreateWindowEx
858  *
859  * Implementation of CreateWindowEx().
860  */
861 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, UINT flags )
862 {
863     INT sw = SW_SHOW;
864     WND *wndPtr;
865     HWND hwnd, parent, owner, top_child = 0;
866     BOOL unicode = (flags & WIN_ISUNICODE) != 0;
867     MDICREATESTRUCTA mdi_cs;
868
869     TRACE("%s %s ex=%08x style=%08x %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
870           unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
871           unicode ? debugstr_w((LPCWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
872           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
873           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
874     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
875
876     /* Fix the styles for MDI children */
877     if (cs->dwExStyle & WS_EX_MDICHILD)
878     {
879         UINT flags = 0;
880
881         wndPtr = WIN_GetPtr(cs->hwndParent);
882         if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
883         {
884             flags = wndPtr->flags;
885             WIN_ReleasePtr(wndPtr);
886         }
887
888         if (!(flags & WIN_ISMDICLIENT))
889         {
890             WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
891             return 0;
892         }
893
894         /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
895          * MDICREATESTRUCT members have the originally passed values.
896          *
897          * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
898          * have the same layout.
899          */
900         mdi_cs.szClass = cs->lpszClass;
901         mdi_cs.szTitle = cs->lpszName;
902         mdi_cs.hOwner = cs->hInstance;
903         mdi_cs.x = cs->x;
904         mdi_cs.y = cs->y;
905         mdi_cs.cx = cs->cx;
906         mdi_cs.cy = cs->cy;
907         mdi_cs.style = cs->style;
908         mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
909
910         cs->lpCreateParams = (LPVOID)&mdi_cs;
911
912         if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
913         {
914             if (cs->style & WS_POPUP)
915             {
916                 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
917                 return 0;
918             }
919             cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
920         }
921         else
922         {
923             cs->style &= ~WS_POPUP;
924             cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
925                 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
926         }
927
928         top_child = GetWindow(cs->hwndParent, GW_CHILD);
929
930         if (top_child)
931         {
932             /* Restore current maximized child */
933             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
934             {
935                 TRACE("Restoring current maximized child %p\n", top_child);
936                 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
937                 ShowWindow(top_child, SW_RESTORE);
938                 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
939             }
940         }
941     }
942
943     /* Find the parent window */
944
945     parent = cs->hwndParent;
946     owner = 0;
947
948     if (cs->hwndParent == HWND_MESSAGE)
949     {
950       /* native ole32.OleInitialize uses HWND_MESSAGE to create the
951        * message window (style: WS_POPUP|WS_DISABLED)
952        */
953       FIXME("Parent is HWND_MESSAGE\n");
954       parent = GetDesktopWindow();
955     }
956     else if (cs->hwndParent)
957     {
958         if ((cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
959         {
960             parent = GetDesktopWindow();
961             owner = cs->hwndParent;
962         }
963     }
964     else
965     {
966         if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
967         {
968             WARN("No parent for child window\n" );
969             SetLastError(ERROR_TLW_WITH_WSCHILD);
970             return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
971         }
972         if (classAtom != LOWORD(DESKTOP_CLASS_ATOM))  /* are we creating the desktop itself? */
973             parent = GetDesktopWindow();
974     }
975
976     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
977
978     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
979         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
980           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
981         cs->dwExStyle |= WS_EX_WINDOWEDGE;
982     else
983         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
984
985     /* Create the window structure */
986
987     if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, unicode )))
988         return 0;
989     hwnd = wndPtr->hwndSelf;
990
991     /* Fill the window structure */
992
993     wndPtr->tid            = GetCurrentThreadId();
994     wndPtr->hInstance      = cs->hInstance;
995     wndPtr->text           = NULL;
996     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
997     wndPtr->dwExStyle      = cs->dwExStyle;
998     wndPtr->wIDmenu        = 0;
999     wndPtr->helpContext    = 0;
1000     wndPtr->pVScroll       = NULL;
1001     wndPtr->pHScroll       = NULL;
1002     wndPtr->userdata       = 0;
1003     wndPtr->hIcon          = 0;
1004     wndPtr->hIconSmall     = 0;
1005     wndPtr->hSysMenu       = 0;
1006     wndPtr->flags         |= (flags & WIN_ISWIN32);
1007
1008     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
1009
1010     /*
1011      * Correct the window styles.
1012      *
1013      * It affects only the style loaded into the WIN structure.
1014      */
1015
1016     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1017     {
1018         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1019         if (!(wndPtr->dwStyle & WS_POPUP))
1020             wndPtr->dwStyle |= WS_CAPTION;
1021     }
1022
1023     /*
1024      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1025      * why does the user get to set it?
1026      */
1027
1028     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1029           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1030         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1031     else
1032         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1033
1034     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1035         wndPtr->flags |= WIN_NEED_SIZE;
1036
1037     SERVER_START_REQ( set_window_info )
1038     {
1039         req->handle    = hwnd;
1040         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1041         req->style     = wndPtr->dwStyle;
1042         req->ex_style  = wndPtr->dwExStyle;
1043         req->instance  = (void *)wndPtr->hInstance;
1044         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1045         req->extra_offset = -1;
1046         wine_server_call( req );
1047     }
1048     SERVER_END_REQ;
1049
1050     /* Set the window menu */
1051
1052     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1053     {
1054         if (cs->hMenu)
1055         {
1056             if (!MENU_SetMenu(hwnd, cs->hMenu))
1057             {
1058                 WIN_ReleasePtr( wndPtr );
1059                 free_window_handle( hwnd );
1060                 return 0;
1061             }
1062         }
1063         else
1064         {
1065             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1066             if (menuName)
1067             {
1068                 if (!cs->hInstance || HIWORD(cs->hInstance))
1069                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1070                 else
1071                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1072
1073                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1074             }
1075         }
1076     }
1077     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1078     WIN_ReleasePtr( wndPtr );
1079
1080     if (!USER_Driver->pCreateWindow( hwnd, cs, unicode))
1081     {
1082         WIN_DestroyWindow( hwnd );
1083         return 0;
1084     }
1085
1086     /* Notify the parent window only */
1087
1088     send_parent_notify( hwnd, WM_CREATE );
1089     if (!IsWindow( hwnd )) return 0;
1090
1091     if (cs->style & WS_VISIBLE)
1092     {
1093         if (cs->style & WS_MAXIMIZE)
1094             sw = SW_SHOW;
1095         else if (cs->style & WS_MINIMIZE)
1096             sw = SW_SHOWMINIMIZED;
1097
1098         ShowWindow( hwnd, sw );
1099         if (cs->dwExStyle & WS_EX_MDICHILD)
1100         {
1101             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1102             /* ShowWindow won't activate child windows */
1103             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1104         }
1105     }
1106
1107     /* Call WH_SHELL hook */
1108
1109     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1110         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1111
1112     TRACE("created window %p\n", hwnd);
1113     return hwnd;
1114 }
1115
1116
1117 /***********************************************************************
1118  *              CreateWindow (USER.41)
1119  */
1120 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1121                               DWORD style, INT16 x, INT16 y, INT16 width,
1122                               INT16 height, HWND16 parent, HMENU16 menu,
1123                               HINSTANCE16 instance, LPVOID data )
1124 {
1125     return CreateWindowEx16( 0, className, windowName, style,
1126                              x, y, width, height, parent, menu, instance, data );
1127 }
1128
1129
1130 /***********************************************************************
1131  *              CreateWindowEx (USER.452)
1132  */
1133 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1134                                 LPCSTR windowName, DWORD style, INT16 x,
1135                                 INT16 y, INT16 width, INT16 height,
1136                                 HWND16 parent, HMENU16 menu,
1137                                 HINSTANCE16 instance, LPVOID data )
1138 {
1139     ATOM classAtom;
1140     CREATESTRUCTA cs;
1141     char buffer[256];
1142
1143     /* Find the class atom */
1144
1145     if (HIWORD(className))
1146     {
1147         if (!(classAtom = GlobalFindAtomA( className )))
1148         {
1149             ERR( "bad class name %s\n", debugstr_a(className) );
1150             return 0;
1151         }
1152     }
1153     else
1154     {
1155         classAtom = LOWORD(className);
1156         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1157         {
1158             ERR( "bad atom %x\n", classAtom);
1159             return 0;
1160         }
1161         className = buffer;
1162     }
1163
1164     /* Fix the coordinates */
1165
1166     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1167     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1168     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1169     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1170
1171     /* Create the window */
1172
1173     cs.lpCreateParams = data;
1174     cs.hInstance      = HINSTANCE_32(instance);
1175     cs.hMenu          = HMENU_32(menu);
1176     cs.hwndParent     = WIN_Handle32( parent );
1177     cs.style          = style;
1178     cs.lpszName       = windowName;
1179     cs.lpszClass      = className;
1180     cs.dwExStyle      = exStyle;
1181
1182     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, 0 ));
1183 }
1184
1185
1186 /***********************************************************************
1187  *              CreateWindowExA (USER32.@)
1188  */
1189 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1190                                  LPCSTR windowName, DWORD style, INT x,
1191                                  INT y, INT width, INT height,
1192                                  HWND parent, HMENU menu,
1193                                  HINSTANCE instance, LPVOID data )
1194 {
1195     ATOM classAtom;
1196     CREATESTRUCTA cs;
1197     char buffer[256];
1198
1199     /* Find the class atom */
1200
1201     if (HIWORD(className))
1202     {
1203         if (!(classAtom = GlobalFindAtomA( className )))
1204         {
1205             ERR( "bad class name %s\n", debugstr_a(className) );
1206             return 0;
1207         }
1208     }
1209     else
1210     {
1211         classAtom = LOWORD(className);
1212         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1213         {
1214             ERR( "bad atom %x\n", classAtom);
1215             return 0;
1216         }
1217         className = buffer;
1218     }
1219
1220     /* Create the window */
1221
1222     cs.lpCreateParams = data;
1223     cs.hInstance      = instance;
1224     cs.hMenu          = menu;
1225     cs.hwndParent     = parent;
1226     cs.x              = x;
1227     cs.y              = y;
1228     cs.cx             = width;
1229     cs.cy             = height;
1230     cs.style          = style;
1231     cs.lpszName       = windowName;
1232     cs.lpszClass      = className;
1233     cs.dwExStyle      = exStyle;
1234
1235     return WIN_CreateWindowEx( &cs, classAtom, WIN_ISWIN32 );
1236 }
1237
1238
1239 /***********************************************************************
1240  *              CreateWindowExW (USER32.@)
1241  */
1242 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1243                                  LPCWSTR windowName, DWORD style, INT x,
1244                                  INT y, INT width, INT height,
1245                                  HWND parent, HMENU menu,
1246                                  HINSTANCE instance, LPVOID data )
1247 {
1248     ATOM classAtom;
1249     CREATESTRUCTW cs;
1250     WCHAR buffer[256];
1251
1252     /* Find the class atom */
1253
1254     if (HIWORD(className))
1255     {
1256         if (!(classAtom = GlobalFindAtomW( className )))
1257         {
1258             ERR( "bad class name %s\n", debugstr_w(className) );
1259             return 0;
1260         }
1261     }
1262     else
1263     {
1264         classAtom = LOWORD(className);
1265         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1266         {
1267             ERR( "bad atom %x\n", classAtom);
1268             return 0;
1269         }
1270         className = buffer;
1271     }
1272
1273     /* Create the window */
1274
1275     cs.lpCreateParams = data;
1276     cs.hInstance      = instance;
1277     cs.hMenu          = menu;
1278     cs.hwndParent     = parent;
1279     cs.x              = x;
1280     cs.y              = y;
1281     cs.cx             = width;
1282     cs.cy             = height;
1283     cs.style          = style;
1284     cs.lpszName       = windowName;
1285     cs.lpszClass      = className;
1286     cs.dwExStyle      = exStyle;
1287
1288     /* Note: we rely on the fact that CREATESTRUCTA and */
1289     /* CREATESTRUCTW have the same layout. */
1290     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_ISWIN32 | WIN_ISUNICODE );
1291 }
1292
1293
1294 /***********************************************************************
1295  *           WIN_SendDestroyMsg
1296  */
1297 static void WIN_SendDestroyMsg( HWND hwnd )
1298 {
1299     GUITHREADINFO info;
1300
1301     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1302     {
1303         if (hwnd == info.hwndCaret) DestroyCaret();
1304         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1305     }
1306
1307     /*
1308      * Send the WM_DESTROY to the window.
1309      */
1310     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1311
1312     /*
1313      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1314      * make sure that the window still exists when we come back.
1315      */
1316     if (IsWindow(hwnd))
1317     {
1318         HWND* pWndArray;
1319         int i;
1320
1321         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1322
1323         for (i = 0; pWndArray[i]; i++)
1324         {
1325             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1326         }
1327         HeapFree( GetProcessHeap(), 0, pWndArray );
1328     }
1329     else
1330       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1331 }
1332
1333
1334 /***********************************************************************
1335  *              DestroyWindow (USER32.@)
1336  */
1337 BOOL WINAPI DestroyWindow( HWND hwnd )
1338 {
1339     BOOL is_child;
1340
1341     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1342     {
1343         SetLastError( ERROR_ACCESS_DENIED );
1344         return FALSE;
1345     }
1346
1347     TRACE("(%p)\n", hwnd);
1348
1349       /* Call hooks */
1350
1351     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1352
1353     if (MENU_IsMenuActive() == hwnd)
1354         EndMenu();
1355
1356     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1357
1358     if (is_child)
1359     {
1360         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1361             send_parent_notify( hwnd, WM_DESTROY );
1362     }
1363     else if (!GetWindow( hwnd, GW_OWNER ))
1364     {
1365         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1366         /* FIXME: clean up palette - see "Internals" p.352 */
1367     }
1368
1369     if (!IsWindow(hwnd)) return TRUE;
1370
1371       /* Hide the window */
1372     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1373     {
1374         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1375         if (is_child)
1376             ShowWindow( hwnd, SW_HIDE );
1377         else
1378             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1379                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1380     }
1381
1382     if (!IsWindow(hwnd)) return TRUE;
1383
1384       /* Recursively destroy owned windows */
1385
1386     if (!is_child)
1387     {
1388         for (;;)
1389         {
1390             int i, got_one = 0;
1391             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1392             if (list)
1393             {
1394                 for (i = 0; list[i]; i++)
1395                 {
1396                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1397                     if (WIN_IsCurrentThread( list[i] ))
1398                     {
1399                         DestroyWindow( list[i] );
1400                         got_one = 1;
1401                         continue;
1402                     }
1403                     WIN_SetOwner( list[i], 0 );
1404                 }
1405                 HeapFree( GetProcessHeap(), 0, list );
1406             }
1407             if (!got_one) break;
1408         }
1409     }
1410
1411       /* Send destroy messages */
1412
1413     WIN_SendDestroyMsg( hwnd );
1414     if (!IsWindow( hwnd )) return TRUE;
1415
1416     if (GetClipboardOwner() == hwnd)
1417         CLIPBOARD_ReleaseOwner();
1418
1419       /* Destroy the window storage */
1420
1421     WIN_DestroyWindow( hwnd );
1422     return TRUE;
1423 }
1424
1425
1426 /***********************************************************************
1427  *              CloseWindow (USER32.@)
1428  */
1429 BOOL WINAPI CloseWindow( HWND hwnd )
1430 {
1431     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1432     ShowWindow( hwnd, SW_MINIMIZE );
1433     return TRUE;
1434 }
1435
1436
1437 /***********************************************************************
1438  *              OpenIcon (USER32.@)
1439  */
1440 BOOL WINAPI OpenIcon( HWND hwnd )
1441 {
1442     if (!IsIconic( hwnd )) return FALSE;
1443     ShowWindow( hwnd, SW_SHOWNORMAL );
1444     return TRUE;
1445 }
1446
1447
1448 /***********************************************************************
1449  *           WIN_FindWindow
1450  *
1451  * Implementation of FindWindow() and FindWindowEx().
1452  */
1453 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1454 {
1455     HWND *list = NULL;
1456     HWND retvalue = 0;
1457     int i = 0, len = 0;
1458     WCHAR *buffer = NULL;
1459
1460     if (!parent) parent = GetDesktopWindow();
1461     if (title)
1462     {
1463         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1464         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1465     }
1466
1467     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1468
1469     if (child)
1470     {
1471         child = WIN_GetFullHandle( child );
1472         while (list[i] && list[i] != child) i++;
1473         if (!list[i]) goto done;
1474         i++;  /* start from next window */
1475     }
1476
1477     if (title)
1478     {
1479         while (list[i])
1480         {
1481             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1482             i++;
1483         }
1484     }
1485     retvalue = list[i];
1486
1487  done:
1488     HeapFree( GetProcessHeap(), 0, list );
1489     HeapFree( GetProcessHeap(), 0, buffer );
1490     return retvalue;
1491 }
1492
1493
1494
1495 /***********************************************************************
1496  *              FindWindowA (USER32.@)
1497  */
1498 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1499 {
1500     HWND ret = FindWindowExA( 0, 0, className, title );
1501     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1502     return ret;
1503 }
1504
1505
1506 /***********************************************************************
1507  *              FindWindowExA (USER32.@)
1508  */
1509 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1510                                LPCSTR className, LPCSTR title )
1511 {
1512     ATOM atom = 0;
1513     LPWSTR buffer;
1514     HWND hwnd;
1515     INT len;
1516
1517     if (className)
1518     {
1519         /* If the atom doesn't exist, then no class */
1520         /* with this name exists either. */
1521         if (!(atom = GlobalFindAtomA( className )))
1522         {
1523             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1524             return 0;
1525         }
1526     }
1527     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1528
1529     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1530     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1531     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1532     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1533     HeapFree( GetProcessHeap(), 0, buffer );
1534     return hwnd;
1535 }
1536
1537
1538 /***********************************************************************
1539  *              FindWindowExW (USER32.@)
1540  */
1541 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1542                                LPCWSTR className, LPCWSTR title )
1543 {
1544     ATOM atom = 0;
1545
1546     if (className)
1547     {
1548         /* If the atom doesn't exist, then no class */
1549         /* with this name exists either. */
1550         if (!(atom = GlobalFindAtomW( className )))
1551         {
1552             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1553             return 0;
1554         }
1555     }
1556     return WIN_FindWindow( parent, child, atom, title );
1557 }
1558
1559
1560 /***********************************************************************
1561  *              FindWindowW (USER32.@)
1562  */
1563 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1564 {
1565     return FindWindowExW( 0, 0, className, title );
1566 }
1567
1568
1569 /**********************************************************************
1570  *              GetDesktopWindow (USER32.@)
1571  */
1572 HWND WINAPI GetDesktopWindow(void)
1573 {
1574     struct user_thread_info *thread_info = get_user_thread_info();
1575
1576     if (thread_info->desktop) return thread_info->desktop;
1577
1578     SERVER_START_REQ( get_desktop_window )
1579     {
1580         req->force = 0;
1581         if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1582     }
1583     SERVER_END_REQ;
1584
1585     if (!thread_info->desktop)
1586     {
1587         static const WCHAR command_line[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1588         STARTUPINFOW si;
1589         PROCESS_INFORMATION pi;
1590         WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
1591
1592         memset( &si, 0, sizeof(si) );
1593         si.cb = sizeof(si);
1594         GetSystemDirectoryW( cmdline, MAX_PATH );
1595         lstrcatW( cmdline, command_line );
1596         if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1597                             NULL, NULL, &si, &pi ))
1598         {
1599             TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1600             WaitForInputIdle( pi.hProcess, 10000 );
1601             CloseHandle( pi.hThread );
1602             CloseHandle( pi.hProcess );
1603
1604         }
1605         else WARN( "failed to start explorer, err %d\n", GetLastError() );
1606
1607         SERVER_START_REQ( get_desktop_window )
1608         {
1609             req->force = 1;
1610             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1611         }
1612         SERVER_END_REQ;
1613     }
1614
1615     if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1616         ERR( "failed to create desktop window\n" );
1617
1618     return thread_info->desktop;
1619 }
1620
1621
1622 /*******************************************************************
1623  *              EnableWindow (USER32.@)
1624  */
1625 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1626 {
1627     BOOL retvalue;
1628     HWND full_handle;
1629
1630     if (is_broadcast(hwnd))
1631     {
1632         SetLastError( ERROR_INVALID_PARAMETER );
1633         return FALSE;
1634     }
1635
1636     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1637         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1638
1639     hwnd = full_handle;
1640
1641     TRACE("( %p, %d )\n", hwnd, enable);
1642
1643     retvalue = !IsWindowEnabled( hwnd );
1644
1645     if (enable && retvalue)
1646     {
1647         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1648         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1649     }
1650     else if (!enable && !retvalue)
1651     {
1652         HWND capture_wnd;
1653
1654         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1655
1656         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1657
1658         if (hwnd == GetFocus())
1659             SetFocus( 0 );  /* A disabled window can't have the focus */
1660
1661         capture_wnd = GetCapture();
1662         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1663             ReleaseCapture();  /* A disabled window can't capture the mouse */
1664
1665         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1666     }
1667     return retvalue;
1668 }
1669
1670
1671 /***********************************************************************
1672  *              IsWindowEnabled (USER32.@)
1673  */
1674 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1675 {
1676     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1677 }
1678
1679
1680 /***********************************************************************
1681  *              IsWindowUnicode (USER32.@)
1682  */
1683 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1684 {
1685     WND * wndPtr;
1686     BOOL retvalue = FALSE;
1687
1688     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1689
1690     if (wndPtr == WND_DESKTOP) return TRUE;
1691
1692     if (wndPtr != WND_OTHER_PROCESS)
1693     {
1694         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1695         WIN_ReleasePtr( wndPtr );
1696     }
1697     else
1698     {
1699         SERVER_START_REQ( get_window_info )
1700         {
1701             req->handle = hwnd;
1702             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1703         }
1704         SERVER_END_REQ;
1705     }
1706     return retvalue;
1707 }
1708
1709
1710 /**********************************************************************
1711  *           WIN_GetWindowLong
1712  *
1713  * Helper function for GetWindowLong().
1714  */
1715 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1716 {
1717     LONG_PTR retvalue = 0;
1718     WND *wndPtr;
1719
1720     if (offset == GWLP_HWNDPARENT)
1721     {
1722         HWND parent = GetAncestor( hwnd, GA_PARENT );
1723         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1724         return (ULONG_PTR)parent;
1725     }
1726
1727     if (!(wndPtr = WIN_GetPtr( hwnd )))
1728     {
1729         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1730         return 0;
1731     }
1732
1733     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1734     {
1735         if (offset == GWLP_WNDPROC)
1736         {
1737             SetLastError( ERROR_ACCESS_DENIED );
1738             return 0;
1739         }
1740         SERVER_START_REQ( set_window_info )
1741         {
1742             req->handle = hwnd;
1743             req->flags  = 0;  /* don't set anything, just retrieve */
1744             req->extra_offset = (offset >= 0) ? offset : -1;
1745             req->extra_size = (offset >= 0) ? size : 0;
1746             if (!wine_server_call_err( req ))
1747             {
1748                 switch(offset)
1749                 {
1750                 case GWL_STYLE:      retvalue = reply->old_style; break;
1751                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1752                 case GWLP_ID:        retvalue = reply->old_id; break;
1753                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1754                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
1755                 default:
1756                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1757                     else SetLastError( ERROR_INVALID_INDEX );
1758                     break;
1759                 }
1760             }
1761         }
1762         SERVER_END_REQ;
1763         return retvalue;
1764     }
1765
1766     /* now we have a valid wndPtr */
1767
1768     if (offset >= 0)
1769     {
1770         if (offset > (int)(wndPtr->cbWndExtra - size))
1771         {
1772             WARN("Invalid offset %d\n", offset );
1773             WIN_ReleasePtr( wndPtr );
1774             SetLastError( ERROR_INVALID_INDEX );
1775             return 0;
1776         }
1777         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1778
1779         /* Special case for dialog window procedure */
1780         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1781             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1782         WIN_ReleasePtr( wndPtr );
1783         return retvalue;
1784     }
1785
1786     switch(offset)
1787     {
1788     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1789     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1790     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1791     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1792     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break;
1793     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1794     default:
1795         WARN("Unknown offset %d\n", offset );
1796         SetLastError( ERROR_INVALID_INDEX );
1797         break;
1798     }
1799     WIN_ReleasePtr(wndPtr);
1800     return retvalue;
1801 }
1802
1803
1804 /**********************************************************************
1805  *           WIN_SetWindowLong
1806  *
1807  * Helper function for SetWindowLong().
1808  *
1809  * 0 is the failure code. However, in the case of failure SetLastError
1810  * must be set to distinguish between a 0 return value and a failure.
1811  */
1812 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1813 {
1814     STYLESTRUCT style;
1815     BOOL ok;
1816     LONG_PTR retval = 0;
1817     WND *wndPtr;
1818
1819     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1820
1821     if (is_broadcast(hwnd))
1822     {
1823         SetLastError( ERROR_INVALID_PARAMETER );
1824         return FALSE;
1825     }
1826
1827     if (!(wndPtr = WIN_GetPtr( hwnd )))
1828     {
1829         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1830         return 0;
1831     }
1832     if (wndPtr == WND_DESKTOP)
1833     {
1834         /* can't change anything on the desktop window */
1835         SetLastError( ERROR_ACCESS_DENIED );
1836         return 0;
1837     }
1838     if (wndPtr == WND_OTHER_PROCESS)
1839     {
1840         if (offset == GWLP_WNDPROC)
1841         {
1842             SetLastError( ERROR_ACCESS_DENIED );
1843             return 0;
1844         }
1845         if (offset > 32767 || offset < -32767)
1846         {
1847             SetLastError( ERROR_INVALID_INDEX );
1848             return 0;
1849         }
1850         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1851     }
1852
1853     /* first some special cases */
1854     switch( offset )
1855     {
1856     case GWL_STYLE:
1857     case GWL_EXSTYLE:
1858         style.styleOld =
1859             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1860         style.styleNew = newval;
1861         WIN_ReleasePtr( wndPtr );
1862         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1863         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1864         newval = style.styleNew;
1865         break;
1866     case GWLP_HWNDPARENT:
1867         if (wndPtr->parent == GetDesktopWindow())
1868         {
1869             WIN_ReleasePtr( wndPtr );
1870             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1871         }
1872         else
1873         {
1874             WIN_ReleasePtr( wndPtr );
1875             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1876         }
1877     case GWLP_WNDPROC:
1878     {
1879         WNDPROC proc;
1880         UINT old_flags = wndPtr->flags;
1881         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1882         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1883         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1884         if (proc) wndPtr->winproc = proc;
1885         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1886         else wndPtr->flags &= ~WIN_ISUNICODE;
1887         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1888         {
1889             WIN_ReleasePtr( wndPtr );
1890             return retval;
1891         }
1892         /* update is_unicode flag on the server side */
1893         break;
1894     }
1895     case GWLP_ID:
1896     case GWLP_HINSTANCE:
1897     case GWLP_USERDATA:
1898         break;
1899     case DWLP_DLGPROC:
1900         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1901             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1902         {
1903             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1904             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1905             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1906             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1907             WIN_ReleasePtr( wndPtr );
1908             return retval;
1909         }
1910         /* fall through */
1911     default:
1912         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1913         {
1914             WARN("Invalid offset %d\n", offset );
1915             WIN_ReleasePtr( wndPtr );
1916             SetLastError( ERROR_INVALID_INDEX );
1917             return 0;
1918         }
1919         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1920         {
1921             /* already set to the same value */
1922             WIN_ReleasePtr( wndPtr );
1923             return newval;
1924         }
1925         break;
1926     }
1927
1928     SERVER_START_REQ( set_window_info )
1929     {
1930         req->handle = hwnd;
1931         req->extra_offset = -1;
1932         switch(offset)
1933         {
1934         case GWL_STYLE:
1935             req->flags = SET_WIN_STYLE;
1936             req->style = newval;
1937             break;
1938         case GWL_EXSTYLE:
1939             req->flags = SET_WIN_EXSTYLE;
1940             req->ex_style = newval;
1941             break;
1942         case GWLP_ID:
1943             req->flags = SET_WIN_ID;
1944             req->id = newval;
1945             break;
1946         case GWLP_HINSTANCE:
1947             req->flags = SET_WIN_INSTANCE;
1948             req->instance = (void *)newval;
1949             break;
1950         case GWLP_WNDPROC:
1951             req->flags = SET_WIN_UNICODE;
1952             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1953             break;
1954         case GWLP_USERDATA:
1955             req->flags = SET_WIN_USERDATA;
1956             req->user_data = newval;
1957             break;
1958         default:
1959             req->flags = SET_WIN_EXTRA;
1960             req->extra_offset = offset;
1961             req->extra_size = size;
1962             set_win_data( &req->extra_value, newval, size );
1963         }
1964         if ((ok = !wine_server_call_err( req )))
1965         {
1966             switch(offset)
1967             {
1968             case GWL_STYLE:
1969                 wndPtr->dwStyle = newval;
1970                 retval = reply->old_style;
1971                 break;
1972             case GWL_EXSTYLE:
1973                 wndPtr->dwExStyle = newval;
1974                 retval = reply->old_ex_style;
1975                 break;
1976             case GWLP_ID:
1977                 wndPtr->wIDmenu = newval;
1978                 retval = reply->old_id;
1979                 break;
1980             case GWLP_HINSTANCE:
1981                 wndPtr->hInstance = (HINSTANCE)newval;
1982                 retval = (ULONG_PTR)reply->old_instance;
1983                 break;
1984             case GWLP_WNDPROC:
1985                 break;
1986             case GWLP_USERDATA:
1987                 wndPtr->userdata = newval;
1988                 retval = reply->old_user_data;
1989                 break;
1990             default:
1991                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
1992                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
1993                 break;
1994             }
1995         }
1996     }
1997     SERVER_END_REQ;
1998     WIN_ReleasePtr( wndPtr );
1999
2000     if (!ok) return 0;
2001
2002     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2003
2004     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2005         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2006
2007     return retval;
2008 }
2009
2010
2011 /**********************************************************************
2012  *              GetWindowLong (USER.135)
2013  */
2014 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2015 {
2016     WND *wndPtr;
2017     LONG_PTR retvalue;
2018     BOOL is_winproc = (offset == GWLP_WNDPROC);
2019
2020     if (offset >= 0)
2021     {
2022         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2023         {
2024             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2025             return 0;
2026         }
2027         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2028         {
2029             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2030             {
2031                 /*
2032                  * Some programs try to access last element from 16 bit
2033                  * code using illegal offset value. Hopefully this is
2034                  * what those programs really expect.
2035                  */
2036                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2037                 {
2038                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2039                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2040                     offset = offset2;
2041                 }
2042                 else
2043                 {
2044                     WARN("Invalid offset %d\n", offset );
2045                     WIN_ReleasePtr( wndPtr );
2046                     SetLastError( ERROR_INVALID_INDEX );
2047                     return 0;
2048                 }
2049             }
2050             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2051             WIN_ReleasePtr( wndPtr );
2052         }
2053     }
2054     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2055     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2056     return retvalue;
2057 }
2058
2059
2060 /**********************************************************************
2061  *              GetWindowWord (USER32.@)
2062  */
2063 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2064 {
2065     switch(offset)
2066     {
2067     case GWLP_ID:
2068     case GWLP_HINSTANCE:
2069     case GWLP_HWNDPARENT:
2070         break;
2071     default:
2072         if (offset < 0)
2073         {
2074             WARN("Invalid offset %d\n", offset );
2075             SetLastError( ERROR_INVALID_INDEX );
2076             return 0;
2077         }
2078         break;
2079     }
2080     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2081 }
2082
2083
2084 /**********************************************************************
2085  *              GetWindowLongA (USER32.@)
2086  */
2087 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2088 {
2089     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2090 }
2091
2092
2093 /**********************************************************************
2094  *              GetWindowLongW (USER32.@)
2095  */
2096 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2097 {
2098     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2099 }
2100
2101
2102 /**********************************************************************
2103  *              SetWindowLong (USER.136)
2104  */
2105 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2106 {
2107     WND *wndPtr;
2108     BOOL is_winproc = (offset == GWLP_WNDPROC);
2109
2110     if (offset == DWLP_DLGPROC)
2111     {
2112         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2113         {
2114             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2115             return 0;
2116         }
2117         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2118         {
2119             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2120                           (wndPtr->flags & WIN_ISDIALOG));
2121             WIN_ReleasePtr( wndPtr );
2122         }
2123     }
2124
2125     if (is_winproc)
2126     {
2127         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2128         WNDPROC old_proc = (WNDPROC)SetWindowLongA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2129         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2130     }
2131     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2132 }
2133
2134
2135 /**********************************************************************
2136  *              SetWindowWord (USER32.@)
2137  */
2138 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2139 {
2140     switch(offset)
2141     {
2142     case GWLP_ID:
2143     case GWLP_HINSTANCE:
2144     case GWLP_HWNDPARENT:
2145         break;
2146     default:
2147         if (offset < 0)
2148         {
2149             WARN("Invalid offset %d\n", offset );
2150             SetLastError( ERROR_INVALID_INDEX );
2151             return 0;
2152         }
2153         break;
2154     }
2155     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2156 }
2157
2158
2159 /**********************************************************************
2160  *              SetWindowLongA (USER32.@)
2161  *
2162  * See SetWindowLongW.
2163  */
2164 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2165 {
2166     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2167 }
2168
2169
2170 /**********************************************************************
2171  *              SetWindowLongW (USER32.@) Set window attribute
2172  *
2173  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2174  * value in a window's extra memory.
2175  *
2176  * The _hwnd_ parameter specifies the window.  is the handle to a
2177  * window that has extra memory. The _newval_ parameter contains the
2178  * new attribute or extra memory value.  If positive, the _offset_
2179  * parameter is the byte-addressed location in the window's extra
2180  * memory to set.  If negative, _offset_ specifies the window
2181  * attribute to set, and should be one of the following values:
2182  *
2183  * GWL_EXSTYLE      The window's extended window style
2184  *
2185  * GWL_STYLE        The window's window style.
2186  *
2187  * GWLP_WNDPROC     Pointer to the window's window procedure.
2188  *
2189  * GWLP_HINSTANCE   The window's pplication instance handle.
2190  *
2191  * GWLP_ID          The window's identifier.
2192  *
2193  * GWLP_USERDATA    The window's user-specified data.
2194  *
2195  * If the window is a dialog box, the _offset_ parameter can be one of
2196  * the following values:
2197  *
2198  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2199  *
2200  * DWLP_MSGRESULT   The return value of a message
2201  *                  that the dialog box procedure processed.
2202  *
2203  * DWLP_USER        Application specific information.
2204  *
2205  * RETURNS
2206  *
2207  * If successful, returns the previous value located at _offset_. Otherwise,
2208  * returns 0.
2209  *
2210  * NOTES
2211  *
2212  * Extra memory for a window class is specified by a nonzero cbWndExtra
2213  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2214  * time of class creation.
2215  *
2216  * Using GWL_WNDPROC to set a new window procedure effectively creates
2217  * a window subclass. Use CallWindowProc() in the new windows procedure
2218  * to pass messages to the superclass's window procedure.
2219  *
2220  * The user data is reserved for use by the application which created
2221  * the window.
2222  *
2223  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2224  * instead, call the EnableWindow() function to change the window's
2225  * disabled state.
2226  *
2227  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2228  * SetParent() instead.
2229  *
2230  * Win95:
2231  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2232  * it sends WM_STYLECHANGING before changing the settings
2233  * and WM_STYLECHANGED afterwards.
2234  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2235  */
2236 LONG WINAPI SetWindowLongW(
2237     HWND hwnd,  /* [in] window to alter */
2238     INT offset, /* [in] offset, in bytes, of location to alter */
2239     LONG newval /* [in] new value of location */
2240 ) {
2241     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2242 }
2243
2244
2245 /*******************************************************************
2246  *              GetWindowTextA (USER32.@)
2247  */
2248 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2249 {
2250     WCHAR *buffer;
2251
2252     if (!lpString) return 0;
2253
2254     if (WIN_IsCurrentProcess( hwnd ))
2255         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2256
2257     /* when window belongs to other process, don't send a message */
2258     if (nMaxCount <= 0) return 0;
2259     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2260     get_server_window_text( hwnd, buffer, nMaxCount );
2261     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2262         lpString[nMaxCount-1] = 0;
2263     HeapFree( GetProcessHeap(), 0, buffer );
2264     return strlen(lpString);
2265 }
2266
2267
2268 /*******************************************************************
2269  *              InternalGetWindowText (USER32.@)
2270  */
2271 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2272 {
2273     WND *win;
2274
2275     if (nMaxCount <= 0) return 0;
2276     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2277     if (win == WND_DESKTOP) lpString[0] = 0;
2278     else if (win != WND_OTHER_PROCESS)
2279     {
2280         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2281         else lpString[0] = 0;
2282         WIN_ReleasePtr( win );
2283     }
2284     else
2285     {
2286         get_server_window_text( hwnd, lpString, nMaxCount );
2287     }
2288     return strlenW(lpString);
2289 }
2290
2291
2292 /*******************************************************************
2293  *              GetWindowTextW (USER32.@)
2294  */
2295 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2296 {
2297     if (!lpString) return 0;
2298
2299     if (WIN_IsCurrentProcess( hwnd ))
2300         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2301
2302     /* when window belongs to other process, don't send a message */
2303     if (nMaxCount <= 0) return 0;
2304     get_server_window_text( hwnd, lpString, nMaxCount );
2305     return strlenW(lpString);
2306 }
2307
2308
2309 /*******************************************************************
2310  *              SetWindowTextA (USER32.@)
2311  *              SetWindowText  (USER32.@)
2312  */
2313 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2314 {
2315     if (is_broadcast(hwnd))
2316     {
2317         SetLastError( ERROR_INVALID_PARAMETER );
2318         return FALSE;
2319     }
2320     if (!WIN_IsCurrentProcess( hwnd ))
2321         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2322                debugstr_a(lpString), hwnd );
2323     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2324 }
2325
2326
2327 /*******************************************************************
2328  *              SetWindowTextW (USER32.@)
2329  */
2330 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2331 {
2332     if (is_broadcast(hwnd))
2333     {
2334         SetLastError( ERROR_INVALID_PARAMETER );
2335         return FALSE;
2336     }
2337     if (!WIN_IsCurrentProcess( hwnd ))
2338         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2339                debugstr_w(lpString), hwnd );
2340     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2341 }
2342
2343
2344 /*******************************************************************
2345  *              GetWindowTextLengthA (USER32.@)
2346  */
2347 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2348 {
2349     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2350 }
2351
2352 /*******************************************************************
2353  *              GetWindowTextLengthW (USER32.@)
2354  */
2355 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2356 {
2357     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2358 }
2359
2360
2361 /*******************************************************************
2362  *              IsWindow (USER32.@)
2363  */
2364 BOOL WINAPI IsWindow( HWND hwnd )
2365 {
2366     WND *ptr;
2367     BOOL ret;
2368
2369     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2370     if (ptr == WND_DESKTOP) return TRUE;
2371
2372     if (ptr != WND_OTHER_PROCESS)
2373     {
2374         WIN_ReleasePtr( ptr );
2375         return TRUE;
2376     }
2377
2378     /* check other processes */
2379     SERVER_START_REQ( get_window_info )
2380     {
2381         req->handle = hwnd;
2382         ret = !wine_server_call_err( req );
2383     }
2384     SERVER_END_REQ;
2385     return ret;
2386 }
2387
2388
2389 /***********************************************************************
2390  *              GetWindowThreadProcessId (USER32.@)
2391  */
2392 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2393 {
2394     WND *ptr;
2395     DWORD tid = 0;
2396
2397     if (!(ptr = WIN_GetPtr( hwnd )))
2398     {
2399         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2400         return 0;
2401     }
2402
2403     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2404     {
2405         /* got a valid window */
2406         tid = ptr->tid;
2407         if (process) *process = GetCurrentProcessId();
2408         WIN_ReleasePtr( ptr );
2409         return tid;
2410     }
2411
2412     /* check other processes */
2413     SERVER_START_REQ( get_window_info )
2414     {
2415         req->handle = hwnd;
2416         if (!wine_server_call_err( req ))
2417         {
2418             tid = (DWORD)reply->tid;
2419             if (process) *process = (DWORD)reply->pid;
2420         }
2421     }
2422     SERVER_END_REQ;
2423     return tid;
2424 }
2425
2426
2427 /*****************************************************************
2428  *              GetParent (USER32.@)
2429  */
2430 HWND WINAPI GetParent( HWND hwnd )
2431 {
2432     WND *wndPtr;
2433     HWND retvalue = 0;
2434
2435     if (!(wndPtr = WIN_GetPtr( hwnd )))
2436     {
2437         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2438         return 0;
2439     }
2440     if (wndPtr == WND_DESKTOP) return 0;
2441     if (wndPtr == WND_OTHER_PROCESS)
2442     {
2443         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2444         if (style & (WS_POPUP | WS_CHILD))
2445         {
2446             SERVER_START_REQ( get_window_tree )
2447             {
2448                 req->handle = hwnd;
2449                 if (!wine_server_call_err( req ))
2450                 {
2451                     if (style & WS_POPUP) retvalue = reply->owner;
2452                     else if (style & WS_CHILD) retvalue = reply->parent;
2453                 }
2454             }
2455             SERVER_END_REQ;
2456         }
2457     }
2458     else
2459     {
2460         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2461         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2462         WIN_ReleasePtr( wndPtr );
2463     }
2464     return retvalue;
2465 }
2466
2467
2468 /*****************************************************************
2469  *              GetAncestor (USER32.@)
2470  */
2471 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2472 {
2473     WND *win;
2474     HWND *list, ret = 0;
2475
2476     switch(type)
2477     {
2478     case GA_PARENT:
2479         if (!(win = WIN_GetPtr( hwnd )))
2480         {
2481             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2482             return 0;
2483         }
2484         if (win == WND_DESKTOP) return 0;
2485         if (win != WND_OTHER_PROCESS)
2486         {
2487             ret = win->parent;
2488             WIN_ReleasePtr( win );
2489         }
2490         else /* need to query the server */
2491         {
2492             SERVER_START_REQ( get_window_tree )
2493             {
2494                 req->handle = hwnd;
2495                 if (!wine_server_call_err( req )) ret = reply->parent;
2496             }
2497             SERVER_END_REQ;
2498         }
2499         break;
2500
2501     case GA_ROOT:
2502         if (!(list = list_window_parents( hwnd ))) return 0;
2503
2504         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2505         else
2506         {
2507             int count = 2;
2508             while (list[count]) count++;
2509             ret = list[count - 2];  /* get the one before the desktop */
2510         }
2511         HeapFree( GetProcessHeap(), 0, list );
2512         break;
2513
2514     case GA_ROOTOWNER:
2515         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2516         for (;;)
2517         {
2518             HWND parent = GetParent( ret );
2519             if (!parent) break;
2520             ret = parent;
2521         }
2522         break;
2523     }
2524     return ret;
2525 }
2526
2527
2528 /*****************************************************************
2529  *              SetParent (USER32.@)
2530  */
2531 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2532 {
2533     HWND full_handle;
2534
2535     if (is_broadcast(hwnd) || is_broadcast(parent))
2536     {
2537         SetLastError(ERROR_INVALID_PARAMETER);
2538         return 0;
2539     }
2540
2541     if (!parent) parent = GetDesktopWindow();
2542     else parent = WIN_GetFullHandle( parent );
2543
2544     if (!IsWindow( parent ))
2545     {
2546         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2547         return 0;
2548     }
2549
2550     /* Some applications try to set a child as a parent */
2551     if (IsChild(hwnd, parent))
2552     {
2553         SetLastError( ERROR_INVALID_PARAMETER );
2554         return 0;
2555     }
2556
2557     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2558         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2559
2560     return USER_Driver->pSetParent( full_handle, 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] != 0);
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 }