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