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