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