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