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