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