Use Get/SetClassLongPtr to access the module handle.
[wine] / dlls / user / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "controls.h"
38 #include "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( 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     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       = 0;
980
981     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
982
983     /*
984      * Correct the window styles.
985      *
986      * It affects only the style loaded into the WIN structure.
987      */
988
989     if (!(wndPtr->dwStyle & WS_CHILD))
990     {
991         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
992         if (!(wndPtr->dwStyle & WS_POPUP))
993             wndPtr->dwStyle |= WS_CAPTION;
994     }
995
996     /*
997      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
998      * why does the user get to set it?
999      */
1000
1001     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1002           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1003         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1004     else
1005         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1006
1007     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1008         wndPtr->flags |= WIN_NEED_SIZE;
1009
1010     SERVER_START_REQ( set_window_info )
1011     {
1012         req->handle    = hwnd;
1013         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1014         req->style     = wndPtr->dwStyle;
1015         req->ex_style  = wndPtr->dwExStyle;
1016         req->instance  = (void *)wndPtr->hInstance;
1017         req->is_unicode = (type == WIN_PROC_32W);
1018         req->extra_offset = -1;
1019         wine_server_call( req );
1020     }
1021     SERVER_END_REQ;
1022
1023     /* Set the window menu */
1024
1025     if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1026         (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1027     {
1028         if (cs->hMenu)
1029         {
1030             if (!MENU_SetMenu(hwnd, cs->hMenu))
1031             {
1032                 WIN_ReleasePtr( wndPtr );
1033                 free_window_handle( hwnd );
1034                 return 0;
1035             }
1036         }
1037         else
1038         {
1039             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1040             if (menuName)
1041             {
1042                 if (!cs->hInstance || HIWORD(cs->hInstance))
1043                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1044                 else
1045                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1046
1047                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1048             }
1049         }
1050     }
1051     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1052     WIN_ReleasePtr( wndPtr );
1053
1054     if (!USER_Driver->pCreateWindow( hwnd, cs, unicode))
1055     {
1056         WIN_DestroyWindow( hwnd );
1057         return 0;
1058     }
1059
1060     /* Notify the parent window only */
1061
1062     send_parent_notify( hwnd, WM_CREATE );
1063     if (!IsWindow( hwnd )) return 0;
1064
1065     if (cs->style & WS_VISIBLE)
1066     {
1067         if (cs->style & WS_MAXIMIZE)
1068             sw = SW_SHOWMAXIMIZED;
1069         else if (cs->style & WS_MINIMIZE)
1070             sw = SW_SHOWMINIMIZED;
1071
1072         ShowWindow( hwnd, sw );
1073         if (cs->dwExStyle & WS_EX_MDICHILD)
1074         {
1075             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1076             /* ShowWindow won't activate child windows */
1077             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1078         }
1079     }
1080
1081     /* Call WH_SHELL hook */
1082
1083     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1084         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1085
1086     TRACE("created window %p\n", hwnd);
1087     return hwnd;
1088 }
1089
1090
1091 /***********************************************************************
1092  *              CreateWindow (USER.41)
1093  */
1094 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1095                               DWORD style, INT16 x, INT16 y, INT16 width,
1096                               INT16 height, HWND16 parent, HMENU16 menu,
1097                               HINSTANCE16 instance, LPVOID data )
1098 {
1099     return CreateWindowEx16( 0, className, windowName, style,
1100                              x, y, width, height, parent, menu, instance, data );
1101 }
1102
1103
1104 /***********************************************************************
1105  *              CreateWindowEx (USER.452)
1106  */
1107 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1108                                 LPCSTR windowName, DWORD style, INT16 x,
1109                                 INT16 y, INT16 width, INT16 height,
1110                                 HWND16 parent, HMENU16 menu,
1111                                 HINSTANCE16 instance, LPVOID data )
1112 {
1113     ATOM classAtom;
1114     CREATESTRUCTA cs;
1115     char buffer[256];
1116
1117     /* Find the class atom */
1118
1119     if (HIWORD(className))
1120     {
1121         if (!(classAtom = GlobalFindAtomA( className )))
1122         {
1123             ERR( "bad class name %s\n", debugstr_a(className) );
1124             return 0;
1125         }
1126     }
1127     else
1128     {
1129         classAtom = LOWORD(className);
1130         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1131         {
1132             ERR( "bad atom %x\n", classAtom);
1133             return 0;
1134         }
1135         className = buffer;
1136     }
1137
1138     /* Fix the coordinates */
1139
1140     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1141     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1142     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1143     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1144
1145     /* Create the window */
1146
1147     cs.lpCreateParams = data;
1148     cs.hInstance      = HINSTANCE_32(instance);
1149     cs.hMenu          = HMENU_32(menu);
1150     cs.hwndParent     = WIN_Handle32( parent );
1151     cs.style          = style;
1152     cs.lpszName       = windowName;
1153     cs.lpszClass      = className;
1154     cs.dwExStyle      = exStyle;
1155
1156     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1157 }
1158
1159
1160 /***********************************************************************
1161  *              CreateWindowExA (USER32.@)
1162  */
1163 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1164                                  LPCSTR windowName, DWORD style, INT x,
1165                                  INT y, INT width, INT height,
1166                                  HWND parent, HMENU menu,
1167                                  HINSTANCE instance, LPVOID data )
1168 {
1169     ATOM classAtom;
1170     CREATESTRUCTA cs;
1171     char buffer[256];
1172
1173     /* Find the class atom */
1174
1175     if (HIWORD(className))
1176     {
1177         if (!(classAtom = GlobalFindAtomA( className )))
1178         {
1179             ERR( "bad class name %s\n", debugstr_a(className) );
1180             return 0;
1181         }
1182     }
1183     else
1184     {
1185         classAtom = LOWORD(className);
1186         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1187         {
1188             ERR( "bad atom %x\n", classAtom);
1189             return 0;
1190         }
1191         className = buffer;
1192     }
1193
1194     /* Create the window */
1195
1196     cs.lpCreateParams = data;
1197     cs.hInstance      = instance;
1198     cs.hMenu          = menu;
1199     cs.hwndParent     = parent;
1200     cs.x              = x;
1201     cs.y              = y;
1202     cs.cx             = width;
1203     cs.cy             = height;
1204     cs.style          = style;
1205     cs.lpszName       = windowName;
1206     cs.lpszClass      = className;
1207     cs.dwExStyle      = exStyle;
1208
1209     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1210 }
1211
1212
1213 /***********************************************************************
1214  *              CreateWindowExW (USER32.@)
1215  */
1216 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1217                                  LPCWSTR windowName, DWORD style, INT x,
1218                                  INT y, INT width, INT height,
1219                                  HWND parent, HMENU menu,
1220                                  HINSTANCE instance, LPVOID data )
1221 {
1222     ATOM classAtom;
1223     CREATESTRUCTW cs;
1224     WCHAR buffer[256];
1225
1226     /* Find the class atom */
1227
1228     if (HIWORD(className))
1229     {
1230         if (!(classAtom = GlobalFindAtomW( className )))
1231         {
1232             ERR( "bad class name %s\n", debugstr_w(className) );
1233             return 0;
1234         }
1235     }
1236     else
1237     {
1238         classAtom = LOWORD(className);
1239         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1240         {
1241             ERR( "bad atom %x\n", classAtom);
1242             return 0;
1243         }
1244         className = buffer;
1245     }
1246
1247     /* Create the window */
1248
1249     cs.lpCreateParams = data;
1250     cs.hInstance      = instance;
1251     cs.hMenu          = menu;
1252     cs.hwndParent     = parent;
1253     cs.x              = x;
1254     cs.y              = y;
1255     cs.cx             = width;
1256     cs.cy             = height;
1257     cs.style          = style;
1258     cs.lpszName       = windowName;
1259     cs.lpszClass      = className;
1260     cs.dwExStyle      = exStyle;
1261
1262     /* Note: we rely on the fact that CREATESTRUCTA and */
1263     /* CREATESTRUCTW have the same layout. */
1264     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1265 }
1266
1267
1268 /***********************************************************************
1269  *           WIN_SendDestroyMsg
1270  */
1271 static void WIN_SendDestroyMsg( HWND hwnd )
1272 {
1273     GUITHREADINFO info;
1274
1275     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1276     {
1277         if (hwnd == info.hwndCaret) DestroyCaret();
1278         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1279     }
1280     USER_Driver->pResetSelectionOwner( hwnd, TRUE );
1281
1282     /*
1283      * Send the WM_DESTROY to the window.
1284      */
1285     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1286
1287     /*
1288      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1289      * make sure that the window still exists when we come back.
1290      */
1291     if (IsWindow(hwnd))
1292     {
1293         HWND* pWndArray;
1294         int i;
1295
1296         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1297
1298         for (i = 0; pWndArray[i]; i++)
1299         {
1300             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1301         }
1302         HeapFree( GetProcessHeap(), 0, pWndArray );
1303     }
1304     else
1305       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1306 }
1307
1308
1309 /***********************************************************************
1310  *              DestroyWindow (USER32.@)
1311  */
1312 BOOL WINAPI DestroyWindow( HWND hwnd )
1313 {
1314     BOOL is_child;
1315
1316     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1317     {
1318         SetLastError( ERROR_ACCESS_DENIED );
1319         return FALSE;
1320     }
1321
1322     TRACE("(%p)\n", hwnd);
1323
1324       /* Call hooks */
1325
1326     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1327
1328     if (MENU_IsMenuActive() == hwnd)
1329         EndMenu();
1330
1331     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1332
1333     if (is_child)
1334     {
1335         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1336             send_parent_notify( hwnd, WM_DESTROY );
1337     }
1338     else if (!GetWindow( hwnd, GW_OWNER ))
1339     {
1340         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1341         /* FIXME: clean up palette - see "Internals" p.352 */
1342     }
1343
1344     if (!IsWindow(hwnd)) return TRUE;
1345
1346     USER_Driver->pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1347
1348       /* Hide the window */
1349     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1350     {
1351         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1352         if (is_child)
1353             ShowWindow( hwnd, SW_HIDE );
1354         else
1355             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1356                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1357     }
1358
1359     if (!IsWindow(hwnd)) return TRUE;
1360
1361       /* Recursively destroy owned windows */
1362
1363     if (!is_child)
1364     {
1365         for (;;)
1366         {
1367             int i, got_one = 0;
1368             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1369             if (list)
1370             {
1371                 for (i = 0; list[i]; i++)
1372                 {
1373                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1374                     if (WIN_IsCurrentThread( list[i] ))
1375                     {
1376                         DestroyWindow( list[i] );
1377                         got_one = 1;
1378                         continue;
1379                     }
1380                     WIN_SetOwner( list[i], 0 );
1381                 }
1382                 HeapFree( GetProcessHeap(), 0, list );
1383             }
1384             if (!got_one) break;
1385         }
1386     }
1387
1388       /* Send destroy messages */
1389
1390     WIN_SendDestroyMsg( hwnd );
1391     if (!IsWindow( hwnd )) return TRUE;
1392
1393     if (GetClipboardOwner() == hwnd)
1394         CLIPBOARD_ReleaseOwner();
1395
1396       /* Destroy the window storage */
1397
1398     WIN_DestroyWindow( hwnd );
1399     return TRUE;
1400 }
1401
1402
1403 /***********************************************************************
1404  *              CloseWindow (USER32.@)
1405  */
1406 BOOL WINAPI CloseWindow( HWND hwnd )
1407 {
1408     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1409     ShowWindow( hwnd, SW_MINIMIZE );
1410     return TRUE;
1411 }
1412
1413
1414 /***********************************************************************
1415  *              OpenIcon (USER32.@)
1416  */
1417 BOOL WINAPI OpenIcon( HWND hwnd )
1418 {
1419     if (!IsIconic( hwnd )) return FALSE;
1420     ShowWindow( hwnd, SW_SHOWNORMAL );
1421     return TRUE;
1422 }
1423
1424
1425 /***********************************************************************
1426  *           WIN_FindWindow
1427  *
1428  * Implementation of FindWindow() and FindWindowEx().
1429  */
1430 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1431 {
1432     HWND *list = NULL;
1433     HWND retvalue = 0;
1434     int i = 0, len = 0;
1435     WCHAR *buffer = NULL;
1436
1437     if (!parent) parent = GetDesktopWindow();
1438     if (title)
1439     {
1440         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1441         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1442     }
1443
1444     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1445
1446     if (child)
1447     {
1448         child = WIN_GetFullHandle( child );
1449         while (list[i] && list[i] != child) i++;
1450         if (!list[i]) goto done;
1451         i++;  /* start from next window */
1452     }
1453
1454     if (title)
1455     {
1456         while (list[i])
1457         {
1458             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1459             i++;
1460         }
1461     }
1462     retvalue = list[i];
1463
1464  done:
1465     HeapFree( GetProcessHeap(), 0, list );
1466     HeapFree( GetProcessHeap(), 0, buffer );
1467     return retvalue;
1468 }
1469
1470
1471
1472 /***********************************************************************
1473  *              FindWindowA (USER32.@)
1474  */
1475 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1476 {
1477     HWND ret = FindWindowExA( 0, 0, className, title );
1478     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1479     return ret;
1480 }
1481
1482
1483 /***********************************************************************
1484  *              FindWindowExA (USER32.@)
1485  */
1486 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1487                                LPCSTR className, LPCSTR title )
1488 {
1489     ATOM atom = 0;
1490     LPWSTR buffer;
1491     HWND hwnd;
1492     INT len;
1493
1494     if (className)
1495     {
1496         /* If the atom doesn't exist, then no class */
1497         /* with this name exists either. */
1498         if (!(atom = GlobalFindAtomA( className )))
1499         {
1500             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1501             return 0;
1502         }
1503     }
1504     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1505
1506     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1507     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1508     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1509     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1510     HeapFree( GetProcessHeap(), 0, buffer );
1511     return hwnd;
1512 }
1513
1514
1515 /***********************************************************************
1516  *              FindWindowExW (USER32.@)
1517  */
1518 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1519                                LPCWSTR className, LPCWSTR title )
1520 {
1521     ATOM atom = 0;
1522
1523     if (className)
1524     {
1525         /* If the atom doesn't exist, then no class */
1526         /* with this name exists either. */
1527         if (!(atom = GlobalFindAtomW( className )))
1528         {
1529             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1530             return 0;
1531         }
1532     }
1533     return WIN_FindWindow( parent, child, atom, title );
1534 }
1535
1536
1537 /***********************************************************************
1538  *              FindWindowW (USER32.@)
1539  */
1540 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1541 {
1542     return FindWindowExW( 0, 0, className, title );
1543 }
1544
1545
1546 /**********************************************************************
1547  *              GetDesktopWindow (USER32.@)
1548  */
1549 HWND WINAPI GetDesktopWindow(void)
1550 {
1551     struct user_thread_info *thread_info = get_user_thread_info();
1552
1553     if (!thread_info->desktop)
1554     {
1555         SERVER_START_REQ( get_desktop_window )
1556         {
1557             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1558         }
1559         SERVER_END_REQ;
1560         if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1561             ERR( "failed to create desktop window\n" );
1562     }
1563     return thread_info->desktop;
1564 }
1565
1566
1567 /*******************************************************************
1568  *              EnableWindow (USER32.@)
1569  */
1570 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1571 {
1572     BOOL retvalue;
1573     HWND full_handle;
1574
1575     if (is_broadcast(hwnd))
1576     {
1577         SetLastError( ERROR_INVALID_PARAMETER );
1578         return FALSE;
1579     }
1580
1581     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1582         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1583
1584     hwnd = full_handle;
1585
1586     TRACE("( %p, %d )\n", hwnd, enable);
1587
1588     retvalue = !IsWindowEnabled( hwnd );
1589
1590     if (enable && retvalue)
1591     {
1592         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1593         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1594     }
1595     else if (!enable && !retvalue)
1596     {
1597         HWND capture_wnd;
1598
1599         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1600
1601         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1602
1603         if (hwnd == GetFocus())
1604             SetFocus( 0 );  /* A disabled window can't have the focus */
1605
1606         capture_wnd = GetCapture();
1607         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1608             ReleaseCapture();  /* A disabled window can't capture the mouse */
1609
1610         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1611     }
1612     return retvalue;
1613 }
1614
1615
1616 /***********************************************************************
1617  *              IsWindowEnabled (USER32.@)
1618  */
1619 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1620 {
1621     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1622 }
1623
1624
1625 /***********************************************************************
1626  *              IsWindowUnicode (USER32.@)
1627  */
1628 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1629 {
1630     WND * wndPtr;
1631     BOOL retvalue = FALSE;
1632
1633     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1634
1635     if (wndPtr == WND_DESKTOP) return TRUE;
1636
1637     if (wndPtr != WND_OTHER_PROCESS)
1638     {
1639         retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1640         WIN_ReleasePtr( wndPtr );
1641     }
1642     else
1643     {
1644         SERVER_START_REQ( get_window_info )
1645         {
1646             req->handle = hwnd;
1647             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1648         }
1649         SERVER_END_REQ;
1650     }
1651     return retvalue;
1652 }
1653
1654
1655 /**********************************************************************
1656  *              GetWindowWord (USER32.@)
1657  */
1658 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1659 {
1660     if (offset >= 0)
1661     {
1662         WORD retvalue = 0;
1663         WND *wndPtr = WIN_GetPtr( hwnd );
1664         if (!wndPtr)
1665         {
1666             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1667             return 0;
1668         }
1669         if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1670         {
1671             SERVER_START_REQ( set_window_info )
1672             {
1673                 req->handle = hwnd;
1674                 req->flags  = 0;  /* don't set anything, just retrieve */
1675                 req->extra_offset = offset;
1676                 req->extra_size = sizeof(retvalue);
1677                 if (!wine_server_call_err( req ))
1678                     memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1679             }
1680             SERVER_END_REQ;
1681             return retvalue;
1682         }
1683         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1684         {
1685             WARN("Invalid offset %d\n", offset );
1686             SetLastError( ERROR_INVALID_INDEX );
1687         }
1688         else memcpy( &retvalue,  (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1689         WIN_ReleasePtr( wndPtr );
1690         return retvalue;
1691     }
1692
1693     switch(offset)
1694     {
1695     case GWLP_HWNDPARENT:
1696         return GetWindowLongPtrW( hwnd, offset );
1697     case GWLP_ID:
1698     case GWLP_HINSTANCE:
1699         {
1700             LONG_PTR ret = GetWindowLongPtrW( hwnd, offset );
1701             if (HIWORD(ret))
1702                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1703             return LOWORD(ret);
1704         }
1705     default:
1706         WARN("Invalid offset %d\n", offset );
1707         return 0;
1708     }
1709 }
1710
1711
1712 /**********************************************************************
1713  *              SetWindowWord (USER32.@)
1714  */
1715 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1716 {
1717     WORD retval = 0;
1718     WND * wndPtr;
1719
1720     switch(offset)
1721     {
1722     case GWLP_ID:
1723     case GWLP_HINSTANCE:
1724     case GWLP_HWNDPARENT:
1725         return SetWindowLongPtrW( hwnd, offset, (ULONG_PTR)newval );
1726     default:
1727         if (offset < 0)
1728         {
1729             WARN("Invalid offset %d\n", offset );
1730             SetLastError( ERROR_INVALID_INDEX );
1731             return 0;
1732         }
1733     }
1734
1735     wndPtr = WIN_GetPtr( hwnd );
1736     if (wndPtr == WND_DESKTOP)
1737     {
1738         SetLastError( ERROR_ACCESS_DENIED );
1739         return 0;
1740     }
1741     if (wndPtr == WND_OTHER_PROCESS)
1742     {
1743         if (IsWindow(hwnd))
1744             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1745                    offset, newval, hwnd );
1746         wndPtr = NULL;
1747     }
1748     if (!wndPtr)
1749     {
1750        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1751        return 0;
1752     }
1753
1754     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1755     {
1756         WARN("Invalid offset %d\n", offset );
1757         WIN_ReleasePtr(wndPtr);
1758         SetLastError( ERROR_INVALID_INDEX );
1759         return 0;
1760     }
1761
1762     SERVER_START_REQ( set_window_info )
1763     {
1764         req->handle = hwnd;
1765         req->flags = SET_WIN_EXTRA;
1766         req->extra_offset = offset;
1767         req->extra_size = sizeof(newval);
1768         memcpy( &req->extra_value, &newval, sizeof(newval) );
1769         if (!wine_server_call_err( req ))
1770         {
1771             void *ptr = (char *)wndPtr->wExtra + offset;
1772             memcpy( &retval, ptr, sizeof(retval) );
1773             memcpy( ptr, &newval, sizeof(newval) );
1774         }
1775     }
1776     SERVER_END_REQ;
1777     WIN_ReleasePtr( wndPtr );
1778     return retval;
1779 }
1780
1781
1782 /**********************************************************************
1783  *           WIN_GetWindowLong
1784  *
1785  * Helper function for GetWindowLong().
1786  */
1787 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1788 {
1789     LONG_PTR retvalue = 0;
1790     WND *wndPtr;
1791
1792     if (offset == GWLP_HWNDPARENT)
1793     {
1794         HWND parent = GetAncestor( hwnd, GA_PARENT );
1795         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1796         return (ULONG_PTR)parent;
1797     }
1798
1799     if (!(wndPtr = WIN_GetPtr( hwnd )))
1800     {
1801         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1802         return 0;
1803     }
1804
1805     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1806     {
1807         if (offset == GWLP_WNDPROC)
1808         {
1809             SetLastError( ERROR_ACCESS_DENIED );
1810             return 0;
1811         }
1812         SERVER_START_REQ( set_window_info )
1813         {
1814             req->handle = hwnd;
1815             req->flags  = 0;  /* don't set anything, just retrieve */
1816             req->extra_offset = (offset >= 0) ? offset : -1;
1817             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1818             if (!wine_server_call_err( req ))
1819             {
1820                 switch(offset)
1821                 {
1822                 case GWL_STYLE:      retvalue = reply->old_style; break;
1823                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1824                 case GWLP_ID:        retvalue = reply->old_id; break;
1825                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1826                 case GWLP_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1827                 default:
1828                     if (offset >= 0) retvalue = reply->old_extra_value;
1829                     else SetLastError( ERROR_INVALID_INDEX );
1830                     break;
1831                 }
1832             }
1833         }
1834         SERVER_END_REQ;
1835         return retvalue;
1836     }
1837
1838     /* now we have a valid wndPtr */
1839
1840     if (offset >= 0)
1841     {
1842         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1843         {
1844           /*
1845             * Some programs try to access last element from 16 bit
1846             * code using illegal offset value. Hopefully this is
1847             * what those programs really expect.
1848             */
1849            if (type == WIN_PROC_16 &&
1850                wndPtr->cbWndExtra >= 4 &&
1851                offset == wndPtr->cbWndExtra - sizeof(WORD))
1852            {
1853                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1854
1855                ERR( "- replaced invalid offset %d with %d\n",
1856                     offset, offset2 );
1857
1858                 retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset2);
1859                 WIN_ReleasePtr( wndPtr );
1860                 return retvalue;
1861             }
1862             WARN("Invalid offset %d\n", offset );
1863             WIN_ReleasePtr( wndPtr );
1864             SetLastError( ERROR_INVALID_INDEX );
1865             return 0;
1866         }
1867         retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset);
1868         /* Special case for dialog window procedure */
1869         if ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1870             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, type );
1871         WIN_ReleasePtr( wndPtr );
1872         return retvalue;
1873     }
1874
1875     switch(offset)
1876     {
1877     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1878     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1879     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1880     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1881     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type ); break;
1882     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1883     default:
1884         WARN("Unknown offset %d\n", offset );
1885         SetLastError( ERROR_INVALID_INDEX );
1886         break;
1887     }
1888     WIN_ReleasePtr(wndPtr);
1889     return retvalue;
1890 }
1891
1892
1893 /**********************************************************************
1894  *           WIN_SetWindowLong
1895  *
1896  * Helper function for SetWindowLong().
1897  *
1898  * 0 is the failure code. However, in the case of failure SetLastError
1899  * must be set to distinguish between a 0 return value and a failure.
1900  */
1901 static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval,
1902                                    WINDOWPROCTYPE type )
1903 {
1904     STYLESTRUCT style;
1905     BOOL ok;
1906     LONG_PTR retval = 0;
1907     WND *wndPtr;
1908
1909     TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
1910
1911     if (is_broadcast(hwnd))
1912     {
1913         SetLastError( ERROR_INVALID_PARAMETER );
1914         return FALSE;
1915     }
1916
1917     if (!(wndPtr = WIN_GetPtr( hwnd )))
1918     {
1919         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1920         return 0;
1921     }
1922     if (wndPtr == WND_DESKTOP)
1923     {
1924         /* can't change anything on the desktop window */
1925         SetLastError( ERROR_ACCESS_DENIED );
1926         return 0;
1927     }
1928     if (wndPtr == WND_OTHER_PROCESS)
1929     {
1930         if (offset == GWLP_WNDPROC)
1931         {
1932             SetLastError( ERROR_ACCESS_DENIED );
1933             return 0;
1934         }
1935         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1936     }
1937
1938     /* first some special cases */
1939     switch( offset )
1940     {
1941     case GWL_STYLE:
1942     case GWL_EXSTYLE:
1943         style.styleOld =
1944             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1945         style.styleNew = newval;
1946         WIN_ReleasePtr( wndPtr );
1947         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1948         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1949         newval = style.styleNew;
1950         break;
1951     case GWLP_HWNDPARENT:
1952         if (wndPtr->parent == GetDesktopWindow())
1953         {
1954             WIN_ReleasePtr( wndPtr );
1955             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1956         }
1957         else
1958         {
1959             WIN_ReleasePtr( wndPtr );
1960             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1961         }
1962     case GWLP_WNDPROC:
1963     {
1964         WINDOWPROCTYPE old_type = WINPROC_GetProcType( wndPtr->winproc );
1965         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type );
1966         wndPtr->winproc = WINPROC_AllocProc( (WNDPROC)newval, type );
1967         if (old_type == type)
1968         {
1969             WIN_ReleasePtr( wndPtr );
1970             return retval;
1971         }
1972         /* update is_unicode flag on the server side */
1973         break;
1974     }
1975     case GWLP_ID:
1976     case GWLP_HINSTANCE:
1977     case GWLP_USERDATA:
1978         break;
1979     case DWLP_DLGPROC:
1980         if ((wndPtr->cbWndExtra + sizeof(LONG_PTR) >= DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1981         {
1982             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1983             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, type );
1984             *ptr = WINPROC_AllocProc( (WNDPROC)newval, type );
1985             WIN_ReleasePtr( wndPtr );
1986             return retval;
1987         }
1988         /* fall through */
1989     default:
1990         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG_PTR)))
1991         {
1992             WARN("Invalid offset %d\n", offset );
1993             WIN_ReleasePtr( wndPtr );
1994             SetLastError( ERROR_INVALID_INDEX );
1995             return 0;
1996         }
1997         else
1998         {
1999             LONG_PTR *ptr = (LONG_PTR *)((char *)wndPtr->wExtra + offset);
2000             if (*ptr == newval)  /* already set to the same value */
2001             {
2002                 WIN_ReleasePtr( wndPtr );
2003                 return newval;
2004             }
2005         }
2006         break;
2007     }
2008
2009     SERVER_START_REQ( set_window_info )
2010     {
2011         req->handle = hwnd;
2012         req->extra_offset = -1;
2013         switch(offset)
2014         {
2015         case GWL_STYLE:
2016             req->flags = SET_WIN_STYLE;
2017             req->style = newval;
2018             break;
2019         case GWL_EXSTYLE:
2020             req->flags = SET_WIN_EXSTYLE;
2021             req->ex_style = newval;
2022             break;
2023         case GWLP_ID:
2024             req->flags = SET_WIN_ID;
2025             req->id = newval;
2026             break;
2027         case GWLP_HINSTANCE:
2028             req->flags = SET_WIN_INSTANCE;
2029             req->instance = (void *)newval;
2030             break;
2031         case GWLP_WNDPROC:
2032             req->flags = SET_WIN_UNICODE;
2033             req->is_unicode = (type == WIN_PROC_32W);
2034             break;
2035         case GWLP_USERDATA:
2036             req->flags = SET_WIN_USERDATA;
2037             req->user_data = (void *)newval;
2038             break;
2039         default:
2040             req->flags = SET_WIN_EXTRA;
2041             req->extra_offset = offset;
2042             req->extra_size = sizeof(newval);
2043             memcpy( &req->extra_value, &newval, sizeof(newval) );
2044         }
2045         if ((ok = !wine_server_call_err( req )))
2046         {
2047             switch(offset)
2048             {
2049             case GWL_STYLE:
2050                 wndPtr->dwStyle = newval;
2051                 retval = reply->old_style;
2052                 break;
2053             case GWL_EXSTYLE:
2054                 wndPtr->dwExStyle = newval;
2055                 retval = reply->old_ex_style;
2056                 break;
2057             case GWLP_ID:
2058                 wndPtr->wIDmenu = newval;
2059                 retval = reply->old_id;
2060                 break;
2061             case GWLP_HINSTANCE:
2062                 wndPtr->hInstance = (HINSTANCE)newval;
2063                 retval = (ULONG_PTR)reply->old_instance;
2064                 break;
2065             case GWLP_WNDPROC:
2066                 break;
2067             case GWLP_USERDATA:
2068                 wndPtr->userdata = newval;
2069                 retval = (ULONG_PTR)reply->old_user_data;
2070                 break;
2071             default:
2072                 {
2073                     void *ptr = (char *)wndPtr->wExtra + offset;
2074                     memcpy( &retval, ptr, sizeof(retval) );
2075                     memcpy( ptr, &newval, sizeof(newval) );
2076                 }
2077                 break;
2078             }
2079         }
2080     }
2081     SERVER_END_REQ;
2082     WIN_ReleasePtr( wndPtr );
2083
2084     if (!ok) return 0;
2085
2086     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2087
2088     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2089         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2090
2091     return retval;
2092 }
2093
2094
2095 /**********************************************************************
2096  *              GetWindowLong (USER.135)
2097  */
2098 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2099 {
2100     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2101 }
2102
2103
2104 /**********************************************************************
2105  *              GetWindowLongA (USER32.@)
2106  */
2107 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2108 {
2109     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2110 }
2111
2112
2113 /**********************************************************************
2114  *              GetWindowLongW (USER32.@)
2115  */
2116 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2117 {
2118     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2119 }
2120
2121
2122 /**********************************************************************
2123  *              SetWindowLong (USER.136)
2124  */
2125 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2126 {
2127     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2128 }
2129
2130
2131 /**********************************************************************
2132  *              SetWindowLongA (USER32.@)
2133  */
2134 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2135 {
2136     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2137 }
2138
2139
2140 /**********************************************************************
2141  *              SetWindowLongW (USER32.@) Set window attribute
2142  *
2143  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2144  * value in a window's extra memory.
2145  *
2146  * The _hwnd_ parameter specifies the window.  is the handle to a
2147  * window that has extra memory. The _newval_ parameter contains the
2148  * new attribute or extra memory value.  If positive, the _offset_
2149  * parameter is the byte-addressed location in the window's extra
2150  * memory to set.  If negative, _offset_ specifies the window
2151  * attribute to set, and should be one of the following values:
2152  *
2153  * GWL_EXSTYLE      The window's extended window style
2154  *
2155  * GWL_STYLE        The window's window style.
2156  *
2157  * GWLP_WNDPROC     Pointer to the window's window procedure.
2158  *
2159  * GWLP_HINSTANCE   The window's pplication instance handle.
2160  *
2161  * GWLP_ID          The window's identifier.
2162  *
2163  * GWLP_USERDATA    The window's user-specified data.
2164  *
2165  * If the window is a dialog box, the _offset_ parameter can be one of
2166  * the following values:
2167  *
2168  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2169  *
2170  * DWLP_MSGRESULT   The return value of a message
2171  *                  that the dialog box procedure processed.
2172  *
2173  * DWLP_USER        Application specific information.
2174  *
2175  * RETURNS
2176  *
2177  * If successful, returns the previous value located at _offset_. Otherwise,
2178  * returns 0.
2179  *
2180  * NOTES
2181  *
2182  * Extra memory for a window class is specified by a nonzero cbWndExtra
2183  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2184  * time of class creation.
2185  *
2186  * Using GWL_WNDPROC to set a new window procedure effectively creates
2187  * a window subclass. Use CallWindowProc() in the new windows procedure
2188  * to pass messages to the superclass's window procedure.
2189  *
2190  * The user data is reserved for use by the application which created
2191  * the window.
2192  *
2193  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2194  * instead, call the EnableWindow() function to change the window's
2195  * disabled state.
2196  *
2197  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2198  * SetParent() instead.
2199  *
2200  * Win95:
2201  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2202  * it sends WM_STYLECHANGING before changing the settings
2203  * and WM_STYLECHANGED afterwards.
2204  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2205  */
2206 LONG WINAPI SetWindowLongW(
2207     HWND hwnd,  /* [in] window to alter */
2208     INT offset, /* [in] offset, in bytes, of location to alter */
2209     LONG newval /* [in] new value of location */
2210 ) {
2211     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2212 }
2213
2214
2215 /*******************************************************************
2216  *              GetWindowTextA (USER32.@)
2217  */
2218 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2219 {
2220     WCHAR *buffer;
2221
2222     if (!lpString) return 0;
2223
2224     if (WIN_IsCurrentProcess( hwnd ))
2225         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2226
2227     /* when window belongs to other process, don't send a message */
2228     if (nMaxCount <= 0) return 0;
2229     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2230     get_server_window_text( hwnd, buffer, nMaxCount );
2231     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2232         lpString[nMaxCount-1] = 0;
2233     HeapFree( GetProcessHeap(), 0, buffer );
2234     return strlen(lpString);
2235 }
2236
2237
2238 /*******************************************************************
2239  *              InternalGetWindowText (USER32.@)
2240  */
2241 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2242 {
2243     WND *win;
2244
2245     if (nMaxCount <= 0) return 0;
2246     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2247     if (win == WND_DESKTOP) lpString[0] = 0;
2248     else if (win != WND_OTHER_PROCESS)
2249     {
2250         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2251         else lpString[0] = 0;
2252         WIN_ReleasePtr( win );
2253     }
2254     else
2255     {
2256         get_server_window_text( hwnd, lpString, nMaxCount );
2257     }
2258     return strlenW(lpString);
2259 }
2260
2261
2262 /*******************************************************************
2263  *              GetWindowTextW (USER32.@)
2264  */
2265 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2266 {
2267     if (!lpString) return 0;
2268
2269     if (WIN_IsCurrentProcess( hwnd ))
2270         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2271
2272     /* when window belongs to other process, don't send a message */
2273     if (nMaxCount <= 0) return 0;
2274     get_server_window_text( hwnd, lpString, nMaxCount );
2275     return strlenW(lpString);
2276 }
2277
2278
2279 /*******************************************************************
2280  *              SetWindowText  (USER32.@)
2281  *              SetWindowTextA (USER32.@)
2282  */
2283 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2284 {
2285     if (is_broadcast(hwnd))
2286     {
2287         SetLastError( ERROR_INVALID_PARAMETER );
2288         return FALSE;
2289     }
2290     if (!WIN_IsCurrentProcess( hwnd ))
2291         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2292                debugstr_a(lpString), hwnd );
2293     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2294 }
2295
2296
2297 /*******************************************************************
2298  *              SetWindowTextW (USER32.@)
2299  */
2300 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2301 {
2302     if (is_broadcast(hwnd))
2303     {
2304         SetLastError( ERROR_INVALID_PARAMETER );
2305         return FALSE;
2306     }
2307     if (!WIN_IsCurrentProcess( hwnd ))
2308         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2309                debugstr_w(lpString), hwnd );
2310     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2311 }
2312
2313
2314 /*******************************************************************
2315  *              GetWindowTextLengthA (USER32.@)
2316  */
2317 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2318 {
2319     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2320 }
2321
2322 /*******************************************************************
2323  *              GetWindowTextLengthW (USER32.@)
2324  */
2325 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2326 {
2327     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2328 }
2329
2330
2331 /*******************************************************************
2332  *              IsWindow (USER32.@)
2333  */
2334 BOOL WINAPI IsWindow( HWND hwnd )
2335 {
2336     WND *ptr;
2337     BOOL ret;
2338
2339     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2340     if (ptr == WND_DESKTOP) return TRUE;
2341
2342     if (ptr != WND_OTHER_PROCESS)
2343     {
2344         WIN_ReleasePtr( ptr );
2345         return TRUE;
2346     }
2347
2348     /* check other processes */
2349     SERVER_START_REQ( get_window_info )
2350     {
2351         req->handle = hwnd;
2352         ret = !wine_server_call_err( req );
2353     }
2354     SERVER_END_REQ;
2355     return ret;
2356 }
2357
2358
2359 /***********************************************************************
2360  *              GetWindowThreadProcessId (USER32.@)
2361  */
2362 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2363 {
2364     WND *ptr;
2365     DWORD tid = 0;
2366
2367     if (!(ptr = WIN_GetPtr( hwnd )))
2368     {
2369         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2370         return 0;
2371     }
2372
2373     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2374     {
2375         /* got a valid window */
2376         tid = ptr->tid;
2377         if (process) *process = GetCurrentProcessId();
2378         WIN_ReleasePtr( ptr );
2379         return tid;
2380     }
2381
2382     /* check other processes */
2383     SERVER_START_REQ( get_window_info )
2384     {
2385         req->handle = hwnd;
2386         if (!wine_server_call_err( req ))
2387         {
2388             tid = (DWORD)reply->tid;
2389             if (process) *process = (DWORD)reply->pid;
2390         }
2391     }
2392     SERVER_END_REQ;
2393     return tid;
2394 }
2395
2396
2397 /*****************************************************************
2398  *              GetParent (USER32.@)
2399  */
2400 HWND WINAPI GetParent( HWND hwnd )
2401 {
2402     WND *wndPtr;
2403     HWND retvalue = 0;
2404
2405     if (!(wndPtr = WIN_GetPtr( hwnd )))
2406     {
2407         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2408         return 0;
2409     }
2410     if (wndPtr == WND_DESKTOP) return 0;
2411     if (wndPtr == WND_OTHER_PROCESS)
2412     {
2413         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2414         if (style & (WS_POPUP | WS_CHILD))
2415         {
2416             SERVER_START_REQ( get_window_tree )
2417             {
2418                 req->handle = hwnd;
2419                 if (!wine_server_call_err( req ))
2420                 {
2421                     if (style & WS_POPUP) retvalue = reply->owner;
2422                     else if (style & WS_CHILD) retvalue = reply->parent;
2423                 }
2424             }
2425             SERVER_END_REQ;
2426         }
2427     }
2428     else
2429     {
2430         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2431         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2432         WIN_ReleasePtr( wndPtr );
2433     }
2434     return retvalue;
2435 }
2436
2437
2438 /*****************************************************************
2439  *              GetAncestor (USER32.@)
2440  */
2441 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2442 {
2443     WND *win;
2444     HWND *list, ret = 0;
2445
2446     switch(type)
2447     {
2448     case GA_PARENT:
2449         if (!(win = WIN_GetPtr( hwnd )))
2450         {
2451             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2452             return 0;
2453         }
2454         if (win == WND_DESKTOP) return 0;
2455         if (win != WND_OTHER_PROCESS)
2456         {
2457             ret = win->parent;
2458             WIN_ReleasePtr( win );
2459         }
2460         else /* need to query the server */
2461         {
2462             SERVER_START_REQ( get_window_tree )
2463             {
2464                 req->handle = hwnd;
2465                 if (!wine_server_call_err( req )) ret = reply->parent;
2466             }
2467             SERVER_END_REQ;
2468         }
2469         break;
2470
2471     case GA_ROOT:
2472         if (!(list = list_window_parents( hwnd ))) return 0;
2473
2474         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2475         else
2476         {
2477             int count = 2;
2478             while (list[count]) count++;
2479             ret = list[count - 2];  /* get the one before the desktop */
2480         }
2481         HeapFree( GetProcessHeap(), 0, list );
2482         break;
2483
2484     case GA_ROOTOWNER:
2485         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2486         for (;;)
2487         {
2488             HWND parent = GetParent( ret );
2489             if (!parent) break;
2490             ret = parent;
2491         }
2492         break;
2493     }
2494     return ret;
2495 }
2496
2497
2498 /*****************************************************************
2499  *              SetParent (USER32.@)
2500  */
2501 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2502 {
2503     HWND full_handle;
2504
2505     if (is_broadcast(hwnd) || is_broadcast(parent))
2506     {
2507         SetLastError(ERROR_INVALID_PARAMETER);
2508         return 0;
2509     }
2510
2511     if (!parent) parent = GetDesktopWindow();
2512     else parent = WIN_GetFullHandle( parent );
2513
2514     if (!IsWindow( parent ))
2515     {
2516         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2517         return 0;
2518     }
2519
2520     /* Some applications try to set a child as a parent */
2521     if (IsChild(hwnd, parent))
2522     {
2523         SetLastError( ERROR_INVALID_PARAMETER );
2524         return 0;
2525     }
2526
2527     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2528         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2529
2530     return USER_Driver->pSetParent( full_handle, parent );
2531 }
2532
2533
2534 /*******************************************************************
2535  *              IsChild (USER32.@)
2536  */
2537 BOOL WINAPI IsChild( HWND parent, HWND child )
2538 {
2539     HWND *list = list_window_parents( child );
2540     int i;
2541     BOOL ret;
2542
2543     if (!list) return FALSE;
2544     parent = WIN_GetFullHandle( parent );
2545     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2546     ret = (list[i] != 0);
2547     HeapFree( GetProcessHeap(), 0, list );
2548     return ret;
2549 }
2550
2551
2552 /***********************************************************************
2553  *              IsWindowVisible (USER32.@)
2554  */
2555 BOOL WINAPI IsWindowVisible( HWND hwnd )
2556 {
2557     HWND *list;
2558     BOOL retval;
2559     int i;
2560
2561     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2562     if (!(list = list_window_parents( hwnd ))) return TRUE;
2563     for (i = 0; list[i]; i++)
2564         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2565     retval = !list[i];
2566     HeapFree( GetProcessHeap(), 0, list );
2567     return retval;
2568 }
2569
2570
2571 /***********************************************************************
2572  *           WIN_IsWindowDrawable
2573  *
2574  * hwnd is drawable when it is visible, all parents are not
2575  * minimized, and it is itself not minimized unless we are
2576  * trying to draw its default class icon.
2577  */
2578 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2579 {
2580     HWND *list;
2581     BOOL retval;
2582     int i;
2583     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2584
2585     if (!(style & WS_VISIBLE)) return FALSE;
2586     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2587
2588     if (!(list = list_window_parents( hwnd ))) return TRUE;
2589     for (i = 0; list[i]; i++)
2590         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2591             break;
2592     retval = !list[i];
2593     HeapFree( GetProcessHeap(), 0, list );
2594     return retval;
2595 }
2596
2597
2598 /*******************************************************************
2599  *              GetTopWindow (USER32.@)
2600  */
2601 HWND WINAPI GetTopWindow( HWND hwnd )
2602 {
2603     if (!hwnd) hwnd = GetDesktopWindow();
2604     return GetWindow( hwnd, GW_CHILD );
2605 }
2606
2607
2608 /*******************************************************************
2609  *              GetWindow (USER32.@)
2610  */
2611 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2612 {
2613     HWND retval = 0;
2614
2615     if (rel == GW_OWNER)  /* this one may be available locally */
2616     {
2617         WND *wndPtr = WIN_GetPtr( hwnd );
2618         if (!wndPtr)
2619         {
2620             SetLastError( ERROR_INVALID_HANDLE );
2621             return 0;
2622         }
2623         if (wndPtr == WND_DESKTOP) return 0;
2624         if (wndPtr != WND_OTHER_PROCESS)
2625         {
2626             retval = wndPtr->owner;
2627             WIN_ReleasePtr( wndPtr );
2628             return retval;
2629         }
2630         /* else fall through to server call */
2631     }
2632
2633     SERVER_START_REQ( get_window_tree )
2634     {
2635         req->handle = hwnd;
2636         if (!wine_server_call_err( req ))
2637         {
2638             switch(rel)
2639             {
2640             case GW_HWNDFIRST:
2641                 retval = reply->first_sibling;
2642                 break;
2643             case GW_HWNDLAST:
2644                 retval = reply->last_sibling;
2645                 break;
2646             case GW_HWNDNEXT:
2647                 retval = reply->next_sibling;
2648                 break;
2649             case GW_HWNDPREV:
2650                 retval = reply->prev_sibling;
2651                 break;
2652             case GW_OWNER:
2653                 retval = reply->owner;
2654                 break;
2655             case GW_CHILD:
2656                 retval = reply->first_child;
2657                 break;
2658             }
2659         }
2660     }
2661     SERVER_END_REQ;
2662     return retval;
2663 }
2664
2665
2666 /*******************************************************************
2667  *              ShowOwnedPopups (USER32.@)
2668  */
2669 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2670 {
2671     int count = 0;
2672     WND *pWnd;
2673     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2674
2675     if (!win_array) return TRUE;
2676
2677     while (win_array[count]) count++;
2678     while (--count >= 0)
2679     {
2680         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2681         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2682         if (pWnd == WND_OTHER_PROCESS) continue;
2683         if (fShow)
2684         {
2685             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2686             {
2687                 WIN_ReleasePtr( pWnd );
2688                 /* In Windows, ShowOwnedPopups(TRUE) generates
2689                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2690                  * regardless of the state of the owner
2691                  */
2692                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2693                 continue;
2694             }
2695         }
2696         else
2697         {
2698             if (pWnd->dwStyle & WS_VISIBLE)
2699             {
2700                 WIN_ReleasePtr( pWnd );
2701                 /* In Windows, ShowOwnedPopups(FALSE) generates
2702                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2703                  * regardless of the state of the owner
2704                  */
2705                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2706                 continue;
2707             }
2708         }
2709         WIN_ReleasePtr( pWnd );
2710     }
2711     HeapFree( GetProcessHeap(), 0, win_array );
2712     return TRUE;
2713 }
2714
2715
2716 /*******************************************************************
2717  *              GetLastActivePopup (USER32.@)
2718  */
2719 HWND WINAPI GetLastActivePopup( HWND hwnd )
2720 {
2721     HWND retval = hwnd;
2722
2723     SERVER_START_REQ( get_window_info )
2724     {
2725         req->handle = hwnd;
2726         if (!wine_server_call_err( req )) retval = reply->last_active;
2727     }
2728     SERVER_END_REQ;
2729     return retval;
2730 }
2731
2732
2733 /*******************************************************************
2734  *           WIN_ListChildren
2735  *
2736  * Build an array of the children of a given window. The array must be
2737  * freed with HeapFree. Returns NULL when no windows are found.
2738  */
2739 HWND *WIN_ListChildren( HWND hwnd )
2740 {
2741     return list_window_children( hwnd, 0, 0 );
2742 }
2743
2744
2745 /*******************************************************************
2746  *              EnumWindows (USER32.@)
2747  */
2748 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2749 {
2750     HWND *list;
2751     BOOL ret = TRUE;
2752     int i;
2753
2754     USER_CheckNotLock();
2755
2756     /* We have to build a list of all windows first, to avoid */
2757     /* unpleasant side-effects, for instance if the callback */
2758     /* function changes the Z-order of the windows.          */
2759
2760     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2761
2762     /* Now call the callback function for every window */
2763
2764     for (i = 0; list[i]; i++)
2765     {
2766         /* Make sure that the window still exists */
2767         if (!IsWindow( list[i] )) continue;
2768         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2769     }
2770     HeapFree( GetProcessHeap(), 0, list );
2771     return ret;
2772 }
2773
2774
2775 /**********************************************************************
2776  *              EnumThreadWindows (USER32.@)
2777  */
2778 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2779 {
2780     HWND *list;
2781     int i;
2782
2783     USER_CheckNotLock();
2784
2785     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2786
2787     /* Now call the callback function for every window */
2788
2789     for (i = 0; list[i]; i++)
2790         if (!func( list[i], lParam )) break;
2791     HeapFree( GetProcessHeap(), 0, list );
2792     return TRUE;
2793 }
2794
2795
2796 /**********************************************************************
2797  *           WIN_EnumChildWindows
2798  *
2799  * Helper function for EnumChildWindows().
2800  */
2801 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2802 {
2803     HWND *childList;
2804     BOOL ret = FALSE;
2805
2806     for ( ; *list; list++)
2807     {
2808         /* Make sure that the window still exists */
2809         if (!IsWindow( *list )) continue;
2810         /* skip owned windows */
2811         if (GetWindow( *list, GW_OWNER )) continue;
2812         /* Build children list first */
2813         childList = WIN_ListChildren( *list );
2814
2815         ret = func( *list, lParam );
2816
2817         if (childList)
2818         {
2819             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2820             HeapFree( GetProcessHeap(), 0, childList );
2821         }
2822         if (!ret) return FALSE;
2823     }
2824     return TRUE;
2825 }
2826
2827
2828 /**********************************************************************
2829  *              EnumChildWindows (USER32.@)
2830  */
2831 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2832 {
2833     HWND *list;
2834
2835     USER_CheckNotLock();
2836
2837     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2838     WIN_EnumChildWindows( list, func, lParam );
2839     HeapFree( GetProcessHeap(), 0, list );
2840     return TRUE;
2841 }
2842
2843
2844 /*******************************************************************
2845  *              AnyPopup (USER.52)
2846  */
2847 BOOL16 WINAPI AnyPopup16(void)
2848 {
2849     return AnyPopup();
2850 }
2851
2852
2853 /*******************************************************************
2854  *              AnyPopup (USER32.@)
2855  */
2856 BOOL WINAPI AnyPopup(void)
2857 {
2858     int i;
2859     BOOL retvalue;
2860     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2861
2862     if (!list) return FALSE;
2863     for (i = 0; list[i]; i++)
2864     {
2865         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2866     }
2867     retvalue = (list[i] != 0);
2868     HeapFree( GetProcessHeap(), 0, list );
2869     return retvalue;
2870 }
2871
2872
2873 /*******************************************************************
2874  *              FlashWindow (USER32.@)
2875  */
2876 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2877 {
2878     WND *wndPtr;
2879
2880     TRACE("%p\n", hWnd);
2881
2882     if (IsIconic( hWnd ))
2883     {
2884         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2885
2886         wndPtr = WIN_GetPtr(hWnd);
2887         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2888         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2889         {
2890             wndPtr->flags |= WIN_NCACTIVATED;
2891         }
2892         else
2893         {
2894             wndPtr->flags &= ~WIN_NCACTIVATED;
2895         }
2896         WIN_ReleasePtr( wndPtr );
2897         return TRUE;
2898     }
2899     else
2900     {
2901         WPARAM wparam;
2902
2903         wndPtr = WIN_GetPtr(hWnd);
2904         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2905         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2906
2907         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2908         else wparam = (hWnd == GetForegroundWindow());
2909
2910         WIN_ReleasePtr( wndPtr );
2911         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2912         return wparam;
2913     }
2914 }
2915
2916 /*******************************************************************
2917  *              FlashWindowEx (USER32.@)
2918  */
2919 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2920 {
2921     FIXME("%p\n", pfwi);
2922     return TRUE;
2923 }
2924
2925 /*******************************************************************
2926  *              GetWindowContextHelpId (USER32.@)
2927  */
2928 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2929 {
2930     DWORD retval;
2931     WND *wnd = WIN_GetPtr( hwnd );
2932     if (!wnd || wnd == WND_DESKTOP) return 0;
2933     if (wnd == WND_OTHER_PROCESS)
2934     {
2935         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2936         return 0;
2937     }
2938     retval = wnd->helpContext;
2939     WIN_ReleasePtr( wnd );
2940     return retval;
2941 }
2942
2943
2944 /*******************************************************************
2945  *              SetWindowContextHelpId (USER32.@)
2946  */
2947 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2948 {
2949     WND *wnd = WIN_GetPtr( hwnd );
2950     if (!wnd || wnd == WND_DESKTOP) return FALSE;
2951     if (wnd == WND_OTHER_PROCESS)
2952     {
2953         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2954         return 0;
2955     }
2956     wnd->helpContext = id;
2957     WIN_ReleasePtr( wnd );
2958     return TRUE;
2959 }
2960
2961
2962 /*******************************************************************
2963  *              DragDetect (USER32.@)
2964  */
2965 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2966 {
2967     MSG msg;
2968     RECT rect;
2969
2970     rect.left = pt.x - wDragWidth;
2971     rect.right = pt.x + wDragWidth;
2972
2973     rect.top = pt.y - wDragHeight;
2974     rect.bottom = pt.y + wDragHeight;
2975
2976     SetCapture(hWnd);
2977
2978     while(1)
2979     {
2980         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
2981         {
2982             if( msg.message == WM_LBUTTONUP )
2983             {
2984                 ReleaseCapture();
2985                 return 0;
2986             }
2987             if( msg.message == WM_MOUSEMOVE )
2988             {
2989                 POINT tmp;
2990                 tmp.x = LOWORD(msg.lParam);
2991                 tmp.y = HIWORD(msg.lParam);
2992                 if( !PtInRect( &rect, tmp ))
2993                 {
2994                     ReleaseCapture();
2995                     return 1;
2996                 }
2997             }
2998         }
2999         WaitMessage();
3000     }
3001     return 0;
3002 }
3003
3004 /******************************************************************************
3005  *              GetWindowModuleFileNameA (USER32.@)
3006  */
3007 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3008 {
3009     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3010           hwnd, lpszFileName, cchFileNameMax);
3011     return 0;
3012 }
3013
3014 /******************************************************************************
3015  *              GetWindowModuleFileNameW (USER32.@)
3016  */
3017 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3018 {
3019     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3020           hwnd, lpszFileName, cchFileNameMax);
3021     return 0;
3022 }
3023
3024 /******************************************************************************
3025  *              GetWindowInfo (USER32.@)
3026  *
3027  * Note: tests show that Windows doesn't check cbSize of the structure.
3028  */
3029 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3030 {
3031     if (!pwi) return FALSE;
3032     if (!IsWindow(hwnd)) return FALSE;
3033
3034     GetWindowRect(hwnd, &pwi->rcWindow);
3035     GetClientRect(hwnd, &pwi->rcClient);
3036     /* translate to screen coordinates */
3037     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3038
3039     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3040     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3041     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3042
3043     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3044     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3045
3046     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3047     pwi->wCreatorVersion = 0x0400;
3048
3049     return TRUE;
3050 }
3051
3052 /******************************************************************************
3053  *              SwitchDesktop (USER32.@)
3054  *
3055  * NOTES: Sets the current input or interactive desktop.
3056  */
3057 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3058 {
3059     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3060     return TRUE;
3061 }
3062
3063 /*****************************************************************************
3064  *              SetLayeredWindowAttributes (USER32.@)
3065  */
3066 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3067                                         BYTE bAlpha, DWORD dwFlags )
3068 {
3069     FIXME("(%p,0x%.8lx,%d,%ld): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3070     return TRUE;
3071 }