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