Fixes for -Wmissing-declaration and -Wwrite-string warnings.
[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 (!lpString) return 0;
2227
2228     if (WIN_IsCurrentProcess( hwnd ))
2229         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2230
2231     /* when window belongs to other process, don't send a message */
2232     if (nMaxCount <= 0) return 0;
2233     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2234     get_server_window_text( hwnd, buffer, nMaxCount );
2235     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2236         lpString[nMaxCount-1] = 0;
2237     HeapFree( GetProcessHeap(), 0, buffer );
2238     return strlen(lpString);
2239 }
2240
2241
2242 /*******************************************************************
2243  *              InternalGetWindowText (USER32.@)
2244  */
2245 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2246 {
2247     WND *win;
2248
2249     if (nMaxCount <= 0) return 0;
2250     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2251     if (win == WND_DESKTOP) lpString[0] = 0;
2252     else if (win != WND_OTHER_PROCESS)
2253     {
2254         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2255         else lpString[0] = 0;
2256         WIN_ReleasePtr( win );
2257     }
2258     else
2259     {
2260         get_server_window_text( hwnd, lpString, nMaxCount );
2261     }
2262     return strlenW(lpString);
2263 }
2264
2265
2266 /*******************************************************************
2267  *              GetWindowTextW (USER32.@)
2268  */
2269 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2270 {
2271     if (!lpString) return 0;
2272
2273     if (WIN_IsCurrentProcess( hwnd ))
2274         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2275
2276     /* when window belongs to other process, don't send a message */
2277     if (nMaxCount <= 0) return 0;
2278     get_server_window_text( hwnd, lpString, nMaxCount );
2279     return strlenW(lpString);
2280 }
2281
2282
2283 /*******************************************************************
2284  *              SetWindowText  (USER32.@)
2285  *              SetWindowTextA (USER32.@)
2286  */
2287 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2288 {
2289     if (is_broadcast(hwnd))
2290     {
2291         SetLastError( ERROR_INVALID_PARAMETER );
2292         return FALSE;
2293     }
2294     if (!WIN_IsCurrentProcess( hwnd ))
2295         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2296                debugstr_a(lpString), hwnd );
2297     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2298 }
2299
2300
2301 /*******************************************************************
2302  *              SetWindowTextW (USER32.@)
2303  */
2304 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2305 {
2306     if (is_broadcast(hwnd))
2307     {
2308         SetLastError( ERROR_INVALID_PARAMETER );
2309         return FALSE;
2310     }
2311     if (!WIN_IsCurrentProcess( hwnd ))
2312         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2313                debugstr_w(lpString), hwnd );
2314     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2315 }
2316
2317
2318 /*******************************************************************
2319  *              GetWindowTextLengthA (USER32.@)
2320  */
2321 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2322 {
2323     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2324 }
2325
2326 /*******************************************************************
2327  *              GetWindowTextLengthW (USER32.@)
2328  */
2329 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2330 {
2331     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2332 }
2333
2334
2335 /*******************************************************************
2336  *              IsWindow (USER32.@)
2337  */
2338 BOOL WINAPI IsWindow( HWND hwnd )
2339 {
2340     WND *ptr;
2341     BOOL ret;
2342
2343     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2344     if (ptr == WND_DESKTOP) return TRUE;
2345
2346     if (ptr != WND_OTHER_PROCESS)
2347     {
2348         WIN_ReleasePtr( ptr );
2349         return TRUE;
2350     }
2351
2352     /* check other processes */
2353     SERVER_START_REQ( get_window_info )
2354     {
2355         req->handle = hwnd;
2356         ret = !wine_server_call_err( req );
2357     }
2358     SERVER_END_REQ;
2359     return ret;
2360 }
2361
2362
2363 /***********************************************************************
2364  *              GetWindowThreadProcessId (USER32.@)
2365  */
2366 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2367 {
2368     WND *ptr;
2369     DWORD tid = 0;
2370
2371     if (!(ptr = WIN_GetPtr( hwnd )))
2372     {
2373         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2374         return 0;
2375     }
2376
2377     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2378     {
2379         /* got a valid window */
2380         tid = ptr->tid;
2381         if (process) *process = GetCurrentProcessId();
2382         WIN_ReleasePtr( ptr );
2383         return tid;
2384     }
2385
2386     /* check other processes */
2387     SERVER_START_REQ( get_window_info )
2388     {
2389         req->handle = hwnd;
2390         if (!wine_server_call_err( req ))
2391         {
2392             tid = (DWORD)reply->tid;
2393             if (process) *process = (DWORD)reply->pid;
2394         }
2395     }
2396     SERVER_END_REQ;
2397     return tid;
2398 }
2399
2400
2401 /*****************************************************************
2402  *              GetParent (USER32.@)
2403  */
2404 HWND WINAPI GetParent( HWND hwnd )
2405 {
2406     WND *wndPtr;
2407     HWND retvalue = 0;
2408
2409     if (!(wndPtr = WIN_GetPtr( hwnd )))
2410     {
2411         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2412         return 0;
2413     }
2414     if (wndPtr == WND_DESKTOP) return 0;
2415     if (wndPtr == WND_OTHER_PROCESS)
2416     {
2417         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2418         if (style & (WS_POPUP | WS_CHILD))
2419         {
2420             SERVER_START_REQ( get_window_tree )
2421             {
2422                 req->handle = hwnd;
2423                 if (!wine_server_call_err( req ))
2424                 {
2425                     if (style & WS_POPUP) retvalue = reply->owner;
2426                     else if (style & WS_CHILD) retvalue = reply->parent;
2427                 }
2428             }
2429             SERVER_END_REQ;
2430         }
2431     }
2432     else
2433     {
2434         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2435         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2436         WIN_ReleasePtr( wndPtr );
2437     }
2438     return retvalue;
2439 }
2440
2441
2442 /*****************************************************************
2443  *              GetAncestor (USER32.@)
2444  */
2445 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2446 {
2447     WND *win;
2448     HWND *list, ret = 0;
2449
2450     switch(type)
2451     {
2452     case GA_PARENT:
2453         if (!(win = WIN_GetPtr( hwnd )))
2454         {
2455             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2456             return 0;
2457         }
2458         if (win == WND_DESKTOP) return 0;
2459         if (win != WND_OTHER_PROCESS)
2460         {
2461             ret = win->parent;
2462             WIN_ReleasePtr( win );
2463         }
2464         else /* need to query the server */
2465         {
2466             SERVER_START_REQ( get_window_tree )
2467             {
2468                 req->handle = hwnd;
2469                 if (!wine_server_call_err( req )) ret = reply->parent;
2470             }
2471             SERVER_END_REQ;
2472         }
2473         break;
2474
2475     case GA_ROOT:
2476         if (!(list = list_window_parents( hwnd ))) return 0;
2477
2478         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2479         else
2480         {
2481             int count = 2;
2482             while (list[count]) count++;
2483             ret = list[count - 2];  /* get the one before the desktop */
2484         }
2485         HeapFree( GetProcessHeap(), 0, list );
2486         break;
2487
2488     case GA_ROOTOWNER:
2489         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2490         for (;;)
2491         {
2492             HWND parent = GetParent( ret );
2493             if (!parent) break;
2494             ret = parent;
2495         }
2496         break;
2497     }
2498     return ret;
2499 }
2500
2501
2502 /*****************************************************************
2503  *              SetParent (USER32.@)
2504  */
2505 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2506 {
2507     HWND full_handle;
2508
2509     if (is_broadcast(hwnd) || is_broadcast(parent))
2510     {
2511         SetLastError(ERROR_INVALID_PARAMETER);
2512         return 0;
2513     }
2514
2515     if (!parent) parent = GetDesktopWindow();
2516     else parent = WIN_GetFullHandle( parent );
2517
2518     if (!IsWindow( parent ))
2519     {
2520         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2521         return 0;
2522     }
2523
2524     /* Some applications try to set a child as a parent */
2525     if (IsChild(hwnd, parent))
2526     {
2527         SetLastError( ERROR_INVALID_PARAMETER );
2528         return 0;
2529     }
2530
2531     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2532         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2533
2534     if (USER_Driver.pSetParent)
2535         return USER_Driver.pSetParent( full_handle, parent );
2536
2537     return 0;
2538 }
2539
2540
2541 /*******************************************************************
2542  *              IsChild (USER32.@)
2543  */
2544 BOOL WINAPI IsChild( HWND parent, HWND child )
2545 {
2546     HWND *list = list_window_parents( child );
2547     int i;
2548     BOOL ret;
2549
2550     if (!list) return FALSE;
2551     parent = WIN_GetFullHandle( parent );
2552     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2553     ret = (list[i] != 0);
2554     HeapFree( GetProcessHeap(), 0, list );
2555     return ret;
2556 }
2557
2558
2559 /***********************************************************************
2560  *              IsWindowVisible (USER32.@)
2561  */
2562 BOOL WINAPI IsWindowVisible( HWND hwnd )
2563 {
2564     HWND *list;
2565     BOOL retval;
2566     int i;
2567
2568     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2569     if (!(list = list_window_parents( hwnd ))) return TRUE;
2570     for (i = 0; list[i]; i++)
2571         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2572     retval = !list[i];
2573     HeapFree( GetProcessHeap(), 0, list );
2574     return retval;
2575 }
2576
2577
2578 /***********************************************************************
2579  *           WIN_IsWindowDrawable
2580  *
2581  * hwnd is drawable when it is visible, all parents are not
2582  * minimized, and it is itself not minimized unless we are
2583  * trying to draw its default class icon.
2584  */
2585 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2586 {
2587     HWND *list;
2588     BOOL retval;
2589     int i;
2590     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2591
2592     if (!(style & WS_VISIBLE)) return FALSE;
2593     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2594
2595     if (!(list = list_window_parents( hwnd ))) return TRUE;
2596     for (i = 0; list[i]; i++)
2597         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2598             break;
2599     retval = !list[i];
2600     HeapFree( GetProcessHeap(), 0, list );
2601     return retval;
2602 }
2603
2604
2605 /*******************************************************************
2606  *              GetTopWindow (USER32.@)
2607  */
2608 HWND WINAPI GetTopWindow( HWND hwnd )
2609 {
2610     if (!hwnd) hwnd = GetDesktopWindow();
2611     return GetWindow( hwnd, GW_CHILD );
2612 }
2613
2614
2615 /*******************************************************************
2616  *              GetWindow (USER32.@)
2617  */
2618 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2619 {
2620     HWND retval = 0;
2621
2622     if (rel == GW_OWNER)  /* this one may be available locally */
2623     {
2624         WND *wndPtr = WIN_GetPtr( hwnd );
2625         if (!wndPtr)
2626         {
2627             SetLastError( ERROR_INVALID_HANDLE );
2628             return 0;
2629         }
2630         if (wndPtr == WND_DESKTOP) return 0;
2631         if (wndPtr != WND_OTHER_PROCESS)
2632         {
2633             retval = wndPtr->owner;
2634             WIN_ReleasePtr( wndPtr );
2635             return retval;
2636         }
2637         /* else fall through to server call */
2638     }
2639
2640     SERVER_START_REQ( get_window_tree )
2641     {
2642         req->handle = hwnd;
2643         if (!wine_server_call_err( req ))
2644         {
2645             switch(rel)
2646             {
2647             case GW_HWNDFIRST:
2648                 retval = reply->first_sibling;
2649                 break;
2650             case GW_HWNDLAST:
2651                 retval = reply->last_sibling;
2652                 break;
2653             case GW_HWNDNEXT:
2654                 retval = reply->next_sibling;
2655                 break;
2656             case GW_HWNDPREV:
2657                 retval = reply->prev_sibling;
2658                 break;
2659             case GW_OWNER:
2660                 retval = reply->owner;
2661                 break;
2662             case GW_CHILD:
2663                 retval = reply->first_child;
2664                 break;
2665             }
2666         }
2667     }
2668     SERVER_END_REQ;
2669     return retval;
2670 }
2671
2672
2673 /*******************************************************************
2674  *              ShowOwnedPopups (USER32.@)
2675  */
2676 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2677 {
2678     int count = 0;
2679     WND *pWnd;
2680     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2681
2682     if (!win_array) return TRUE;
2683
2684     while (win_array[count]) count++;
2685     while (--count >= 0)
2686     {
2687         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2688         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2689         if (pWnd == WND_OTHER_PROCESS) continue;
2690
2691         if (pWnd->dwStyle & WS_POPUP)
2692         {
2693             if (fShow)
2694             {
2695                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2696                 {
2697                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2698                     WIN_ReleasePtr( pWnd );
2699                     /* In Windows, ShowOwnedPopups(TRUE) generates
2700                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2701                      * regardless of the state of the owner
2702                      */
2703                     SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2704                     continue;
2705                 }
2706             }
2707             else
2708             {
2709                 if (pWnd->dwStyle & WS_VISIBLE)
2710                 {
2711                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2712                     WIN_ReleasePtr( pWnd );
2713                     /* In Windows, ShowOwnedPopups(FALSE) generates
2714                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2715                      * regardless of the state of the owner
2716                      */
2717                     SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2718                     continue;
2719                 }
2720             }
2721         }
2722         WIN_ReleasePtr( pWnd );
2723     }
2724     HeapFree( GetProcessHeap(), 0, win_array );
2725     return TRUE;
2726 }
2727
2728
2729 /*******************************************************************
2730  *              GetLastActivePopup (USER32.@)
2731  */
2732 HWND WINAPI GetLastActivePopup( HWND hwnd )
2733 {
2734     HWND retval = hwnd;
2735
2736     SERVER_START_REQ( get_window_info )
2737     {
2738         req->handle = hwnd;
2739         if (!wine_server_call_err( req )) retval = reply->last_active;
2740     }
2741     SERVER_END_REQ;
2742     return retval;
2743 }
2744
2745
2746 /*******************************************************************
2747  *           WIN_ListChildren
2748  *
2749  * Build an array of the children of a given window. The array must be
2750  * freed with HeapFree. Returns NULL when no windows are found.
2751  */
2752 HWND *WIN_ListChildren( HWND hwnd )
2753 {
2754     return list_window_children( hwnd, 0, 0 );
2755 }
2756
2757
2758 /*******************************************************************
2759  *              EnumWindows (USER32.@)
2760  */
2761 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2762 {
2763     HWND *list;
2764     BOOL ret = TRUE;
2765     int i;
2766
2767     USER_CheckNotLock();
2768
2769     /* We have to build a list of all windows first, to avoid */
2770     /* unpleasant side-effects, for instance if the callback */
2771     /* function changes the Z-order of the windows.          */
2772
2773     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2774
2775     /* Now call the callback function for every window */
2776
2777     for (i = 0; list[i]; i++)
2778     {
2779         /* Make sure that the window still exists */
2780         if (!IsWindow( list[i] )) continue;
2781         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2782     }
2783     HeapFree( GetProcessHeap(), 0, list );
2784     return ret;
2785 }
2786
2787
2788 /**********************************************************************
2789  *              EnumThreadWindows (USER32.@)
2790  */
2791 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2792 {
2793     HWND *list;
2794     int i;
2795
2796     USER_CheckNotLock();
2797
2798     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2799
2800     /* Now call the callback function for every window */
2801
2802     for (i = 0; list[i]; i++)
2803         if (!func( list[i], lParam )) break;
2804     HeapFree( GetProcessHeap(), 0, list );
2805     return TRUE;
2806 }
2807
2808
2809 /**********************************************************************
2810  *           WIN_EnumChildWindows
2811  *
2812  * Helper function for EnumChildWindows().
2813  */
2814 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2815 {
2816     HWND *childList;
2817     BOOL ret = FALSE;
2818
2819     for ( ; *list; list++)
2820     {
2821         /* Make sure that the window still exists */
2822         if (!IsWindow( *list )) continue;
2823         /* skip owned windows */
2824         if (GetWindow( *list, GW_OWNER )) continue;
2825         /* Build children list first */
2826         childList = WIN_ListChildren( *list );
2827
2828         ret = func( *list, lParam );
2829
2830         if (childList)
2831         {
2832             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2833             HeapFree( GetProcessHeap(), 0, childList );
2834         }
2835         if (!ret) return FALSE;
2836     }
2837     return TRUE;
2838 }
2839
2840
2841 /**********************************************************************
2842  *              EnumChildWindows (USER32.@)
2843  */
2844 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2845 {
2846     HWND *list;
2847
2848     USER_CheckNotLock();
2849
2850     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2851     WIN_EnumChildWindows( list, func, lParam );
2852     HeapFree( GetProcessHeap(), 0, list );
2853     return TRUE;
2854 }
2855
2856
2857 /*******************************************************************
2858  *              AnyPopup (USER.52)
2859  */
2860 BOOL16 WINAPI AnyPopup16(void)
2861 {
2862     return AnyPopup();
2863 }
2864
2865
2866 /*******************************************************************
2867  *              AnyPopup (USER32.@)
2868  */
2869 BOOL WINAPI AnyPopup(void)
2870 {
2871     int i;
2872     BOOL retvalue;
2873     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2874
2875     if (!list) return FALSE;
2876     for (i = 0; list[i]; i++)
2877     {
2878         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2879     }
2880     retvalue = (list[i] != 0);
2881     HeapFree( GetProcessHeap(), 0, list );
2882     return retvalue;
2883 }
2884
2885
2886 /*******************************************************************
2887  *              FlashWindow (USER32.@)
2888  */
2889 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2890 {
2891     WND *wndPtr;
2892
2893     TRACE("%p\n", hWnd);
2894
2895     if (IsIconic( hWnd ))
2896     {
2897         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2898
2899         wndPtr = WIN_GetPtr(hWnd);
2900         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2901         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2902         {
2903             wndPtr->flags |= WIN_NCACTIVATED;
2904         }
2905         else
2906         {
2907             wndPtr->flags &= ~WIN_NCACTIVATED;
2908         }
2909         WIN_ReleasePtr( wndPtr );
2910         return TRUE;
2911     }
2912     else
2913     {
2914         WPARAM wparam;
2915
2916         wndPtr = WIN_GetPtr(hWnd);
2917         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2918         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2919
2920         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2921         else wparam = (hWnd == GetForegroundWindow());
2922
2923         WIN_ReleasePtr( wndPtr );
2924         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2925         return wparam;
2926     }
2927 }
2928
2929 /*******************************************************************
2930  *              FlashWindowEx (USER32.@)
2931  */
2932 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2933 {
2934     FIXME("%p\n", pfwi);
2935     return TRUE;
2936 }
2937
2938 /*******************************************************************
2939  *              GetWindowContextHelpId (USER32.@)
2940  */
2941 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2942 {
2943     DWORD retval;
2944     WND *wnd = WIN_GetPtr( hwnd );
2945     if (!wnd || wnd == WND_DESKTOP) return 0;
2946     if (wnd == WND_OTHER_PROCESS)
2947     {
2948         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2949         return 0;
2950     }
2951     retval = wnd->helpContext;
2952     WIN_ReleasePtr( wnd );
2953     return retval;
2954 }
2955
2956
2957 /*******************************************************************
2958  *              SetWindowContextHelpId (USER32.@)
2959  */
2960 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2961 {
2962     WND *wnd = WIN_GetPtr( hwnd );
2963     if (!wnd || wnd == WND_DESKTOP) return FALSE;
2964     if (wnd == WND_OTHER_PROCESS)
2965     {
2966         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2967         return 0;
2968     }
2969     wnd->helpContext = id;
2970     WIN_ReleasePtr( wnd );
2971     return TRUE;
2972 }
2973
2974
2975 /*******************************************************************
2976  *              DragDetect (USER32.@)
2977  */
2978 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2979 {
2980     MSG msg;
2981     RECT rect;
2982
2983     rect.left = pt.x - wDragWidth;
2984     rect.right = pt.x + wDragWidth;
2985
2986     rect.top = pt.y - wDragHeight;
2987     rect.bottom = pt.y + wDragHeight;
2988
2989     SetCapture(hWnd);
2990
2991     while(1)
2992     {
2993         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
2994         {
2995             if( msg.message == WM_LBUTTONUP )
2996             {
2997                 ReleaseCapture();
2998                 return 0;
2999             }
3000             if( msg.message == WM_MOUSEMOVE )
3001             {
3002                 POINT tmp;
3003                 tmp.x = LOWORD(msg.lParam);
3004                 tmp.y = HIWORD(msg.lParam);
3005                 if( !PtInRect( &rect, tmp ))
3006                 {
3007                     ReleaseCapture();
3008                     return 1;
3009                 }
3010             }
3011         }
3012         WaitMessage();
3013     }
3014     return 0;
3015 }
3016
3017 /******************************************************************************
3018  *              GetWindowModuleFileNameA (USER32.@)
3019  */
3020 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3021 {
3022     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3023           hwnd, lpszFileName, cchFileNameMax);
3024     return 0;
3025 }
3026
3027 /******************************************************************************
3028  *              GetWindowModuleFileNameW (USER32.@)
3029  */
3030 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3031 {
3032     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3033           hwnd, lpszFileName, cchFileNameMax);
3034     return 0;
3035 }
3036
3037 /******************************************************************************
3038  *              GetWindowInfo (USER32.@)
3039  *
3040  * Note: tests show that Windows doesn't check cbSize of the structure.
3041  */
3042 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3043 {
3044     if (!pwi) return FALSE;
3045     if (!IsWindow(hwnd)) return FALSE;
3046
3047     GetWindowRect(hwnd, &pwi->rcWindow);
3048     GetClientRect(hwnd, &pwi->rcClient);
3049     /* translate to screen coordinates */
3050     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3051
3052     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3053     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3054     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3055
3056     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3057     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3058
3059     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3060     pwi->wCreatorVersion = 0x0400;
3061
3062     return TRUE;
3063 }
3064
3065 /******************************************************************************
3066  *              SwitchDesktop (USER32.@)
3067  *
3068  * NOTES: Sets the current input or interactive desktop.
3069  */
3070 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3071 {
3072     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3073     return TRUE;
3074 }