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