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