mapi32: Implement FGetComponentPath.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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, BOOL unicode )
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->flags      = 0;
126     win->cbWndExtra = extra_bytes;
127     memset( win->wExtra, 0, extra_bytes );
128     CLASS_AddWindow( class, win, unicode );
129     return win;
130 }
131
132
133 /***********************************************************************
134  *           free_window_handle
135  *
136  * Free a window handle.
137  */
138 static WND *free_window_handle( HWND hwnd )
139 {
140     WND *ptr;
141     WORD index = USER_HANDLE_TO_INDEX(hwnd);
142
143     if (index >= NB_USER_HANDLES) return NULL;
144     USER_Lock();
145     if ((ptr = user_handles[index]))
146     {
147         SERVER_START_REQ( destroy_window )
148         {
149             req->handle = hwnd;
150             if (!wine_server_call_err( req ))
151             {
152                 user_handles[index] = NULL;
153                 ptr->dwMagic = 0;
154             }
155             else
156                 ptr = NULL;
157         }
158         SERVER_END_REQ;
159     }
160     USER_Unlock();
161     HeapFree( GetProcessHeap(), 0, ptr );
162     return ptr;
163 }
164
165
166 /*******************************************************************
167  *           list_window_children
168  *
169  * Build an array of the children of a given window. The array must be
170  * freed with HeapFree. Returns NULL when no windows are found.
171  */
172 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
173 {
174     HWND *list;
175     int size = 32;
176
177     for (;;)
178     {
179         int count = 0;
180
181         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
182
183         SERVER_START_REQ( get_window_children )
184         {
185             req->parent = hwnd;
186             req->atom = atom;
187             req->tid = tid;
188             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
189             if (!wine_server_call( req )) count = reply->count;
190         }
191         SERVER_END_REQ;
192         if (count && count < size)
193         {
194             list[count] = 0;
195             return list;
196         }
197         HeapFree( GetProcessHeap(), 0, list );
198         if (!count) break;
199         size = count + 1;  /* restart with a large enough buffer */
200     }
201     return NULL;
202 }
203
204
205 /*******************************************************************
206  *           list_window_parents
207  *
208  * Build an array of all parents of a given window, starting with
209  * the immediate parent. The array must be freed with HeapFree.
210  * Returns NULL if window is a top-level window.
211  */
212 static HWND *list_window_parents( HWND hwnd )
213 {
214     WND *win;
215     HWND current, *list;
216     int pos = 0, size = 16, count = 0;
217
218     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
219
220     current = hwnd;
221     for (;;)
222     {
223         if (!(win = WIN_GetPtr( current ))) goto empty;
224         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
225         if (win == WND_DESKTOP)
226         {
227             if (!pos) goto empty;
228             list[pos] = 0;
229             return list;
230         }
231         list[pos] = current = win->parent;
232         WIN_ReleasePtr( win );
233         if (++pos == size - 1)
234         {
235             /* need to grow the list */
236             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
237             if (!new_list) goto empty;
238             list = new_list;
239             size += 16;
240         }
241     }
242
243     /* at least one parent belongs to another process, have to query the server */
244
245     for (;;)
246     {
247         count = 0;
248         SERVER_START_REQ( get_window_parents )
249         {
250             req->handle = hwnd;
251             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
252             if (!wine_server_call( req )) count = reply->count;
253         }
254         SERVER_END_REQ;
255         if (!count) goto empty;
256         if (size > count)
257         {
258             list[count] = 0;
259             return list;
260         }
261         HeapFree( GetProcessHeap(), 0, list );
262         size = count + 1;
263         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
264     }
265
266  empty:
267     HeapFree( GetProcessHeap(), 0, list );
268     return NULL;
269 }
270
271
272 /*******************************************************************
273  *           send_parent_notify
274  */
275 static void send_parent_notify( HWND hwnd, UINT msg )
276 {
277     if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
278         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
279     {
280         HWND parent = GetParent(hwnd);
281         if (parent && parent != GetDesktopWindow())
282             SendMessageW( parent, WM_PARENTNOTIFY,
283                           MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
284     }
285 }
286
287
288 /*******************************************************************
289  *              get_server_window_text
290  *
291  * Retrieve the window text from the server.
292  */
293 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
294 {
295     size_t len = 0;
296
297     SERVER_START_REQ( get_window_text )
298     {
299         req->handle = hwnd;
300         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
301         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
302     }
303     SERVER_END_REQ;
304     text[len / sizeof(WCHAR)] = 0;
305 }
306
307
308 /***********************************************************************
309  *           WIN_GetPtr
310  *
311  * Return a pointer to the WND structure if local to the process,
312  * or WND_OTHER_PROCESS if handle may be valid in other process.
313  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
314  */
315 WND *WIN_GetPtr( HWND hwnd )
316 {
317     WND * ptr;
318     WORD index = USER_HANDLE_TO_INDEX(hwnd);
319
320     if (index >= NB_USER_HANDLES) return NULL;
321
322     USER_Lock();
323     if ((ptr = user_handles[index]))
324     {
325         if (ptr->dwMagic == WND_MAGIC &&
326             (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
327             return ptr;
328         ptr = NULL;
329     }
330     else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
331     {
332         if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
333         else ptr = NULL;
334     }
335     else ptr = WND_OTHER_PROCESS;
336     USER_Unlock();
337     return ptr;
338 }
339
340
341 /***********************************************************************
342  *           WIN_IsCurrentProcess
343  *
344  * Check whether a given window belongs to the current process (and return the full handle).
345  */
346 HWND WIN_IsCurrentProcess( HWND hwnd )
347 {
348     WND *ptr;
349     HWND ret;
350
351     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
352     ret = ptr->hwndSelf;
353     WIN_ReleasePtr( ptr );
354     return ret;
355 }
356
357
358 /***********************************************************************
359  *           WIN_IsCurrentThread
360  *
361  * Check whether a given window belongs to the current thread (and return the full handle).
362  */
363 HWND WIN_IsCurrentThread( HWND hwnd )
364 {
365     WND *ptr;
366     HWND ret = 0;
367
368     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
369     if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
370     WIN_ReleasePtr( ptr );
371     return ret;
372 }
373
374
375 /***********************************************************************
376  *           WIN_Handle32
377  *
378  * Convert a 16-bit window handle to a full 32-bit handle.
379  */
380 HWND WIN_Handle32( HWND16 hwnd16 )
381 {
382     WND *ptr;
383     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
384
385     if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
386     /* do sign extension for -2 and -3 */
387     if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
388
389     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
390
391     if (ptr == WND_DESKTOP) return GetDesktopWindow();
392
393     if (ptr != WND_OTHER_PROCESS)
394     {
395         hwnd = ptr->hwndSelf;
396         WIN_ReleasePtr( ptr );
397     }
398     else  /* may belong to another process */
399     {
400         SERVER_START_REQ( get_window_info )
401         {
402             req->handle = hwnd;
403             if (!wine_server_call_err( req )) hwnd = reply->full_handle;
404         }
405         SERVER_END_REQ;
406     }
407     return hwnd;
408 }
409
410
411 /***********************************************************************
412  *           WIN_SetOwner
413  *
414  * Change the owner of a window.
415  */
416 HWND WIN_SetOwner( HWND hwnd, HWND owner )
417 {
418     WND *win = WIN_GetPtr( hwnd );
419     HWND ret = 0;
420
421     if (!win || win == WND_DESKTOP) return 0;
422     if (win == WND_OTHER_PROCESS)
423     {
424         if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
425         return 0;
426     }
427     SERVER_START_REQ( set_window_owner )
428     {
429         req->handle = hwnd;
430         req->owner  = owner;
431         if (!wine_server_call( req ))
432         {
433             win->owner = reply->full_owner;
434             ret = reply->prev_owner;
435         }
436     }
437     SERVER_END_REQ;
438     WIN_ReleasePtr( win );
439     return ret;
440 }
441
442
443 /***********************************************************************
444  *           WIN_SetStyle
445  *
446  * Change the style of a window.
447  */
448 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
449 {
450     BOOL ok;
451     ULONG new_style, old_style = 0;
452     WND *win = WIN_GetPtr( hwnd );
453
454     if (!win || win == WND_DESKTOP) return 0;
455     if (win == WND_OTHER_PROCESS)
456     {
457         if (IsWindow(hwnd))
458             ERR( "cannot set style %lx/%lx on other process window %p\n",
459                  set_bits, clear_bits, hwnd );
460         return 0;
461     }
462     new_style = (win->dwStyle | set_bits) & ~clear_bits;
463     if (new_style == win->dwStyle)
464     {
465         WIN_ReleasePtr( win );
466         return new_style;
467     }
468     SERVER_START_REQ( set_window_info )
469     {
470         req->handle = hwnd;
471         req->flags  = SET_WIN_STYLE;
472         req->style  = new_style;
473         req->extra_offset = -1;
474         if ((ok = !wine_server_call( req )))
475         {
476             old_style = reply->old_style;
477             win->dwStyle = new_style;
478         }
479     }
480     SERVER_END_REQ;
481     WIN_ReleasePtr( win );
482     if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
483     return old_style;
484 }
485
486
487 /***********************************************************************
488  *           WIN_GetRectangles
489  *
490  * Get the window and client rectangles.
491  */
492 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
493 {
494     WND *win = WIN_GetPtr( hwnd );
495     BOOL ret = TRUE;
496
497     if (!win) return FALSE;
498     if (win == WND_DESKTOP)
499     {
500         RECT rect;
501         rect.left = rect.top = 0;
502         rect.right  = GetSystemMetrics(SM_CXSCREEN);
503         rect.bottom = GetSystemMetrics(SM_CYSCREEN);
504         if (rectWindow) *rectWindow = rect;
505         if (rectClient) *rectClient = rect;
506     }
507     else if (win == WND_OTHER_PROCESS)
508     {
509         SERVER_START_REQ( get_window_rectangles )
510         {
511             req->handle = hwnd;
512             if ((ret = !wine_server_call( req )))
513             {
514                 if (rectWindow)
515                 {
516                     rectWindow->left   = reply->window.left;
517                     rectWindow->top    = reply->window.top;
518                     rectWindow->right  = reply->window.right;
519                     rectWindow->bottom = reply->window.bottom;
520                 }
521                 if (rectClient)
522                 {
523                     rectClient->left   = reply->client.left;
524                     rectClient->top    = reply->client.top;
525                     rectClient->right  = reply->client.right;
526                     rectClient->bottom = reply->client.bottom;
527                 }
528             }
529         }
530         SERVER_END_REQ;
531     }
532     else
533     {
534         if (rectWindow) *rectWindow = win->rectWindow;
535         if (rectClient) *rectClient = win->rectClient;
536         WIN_ReleasePtr( win );
537     }
538     return ret;
539 }
540
541
542 /***********************************************************************
543  *           WIN_DestroyWindow
544  *
545  * Destroy storage associated to a window. "Internals" p.358
546  */
547 LRESULT WIN_DestroyWindow( HWND hwnd )
548 {
549     WND *wndPtr;
550     HWND *list;
551     HMENU menu = 0, sys_menu;
552
553     TRACE("%p\n", hwnd );
554
555     /* free child windows */
556     if ((list = WIN_ListChildren( hwnd )))
557     {
558         int i;
559         for (i = 0; list[i]; i++)
560         {
561             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
562             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
563         }
564         HeapFree( GetProcessHeap(), 0, list );
565     }
566
567     /* Unlink now so we won't bother with the children later on */
568     SERVER_START_REQ( set_parent )
569     {
570         req->handle = hwnd;
571         req->parent = 0;
572         wine_server_call( req );
573     }
574     SERVER_END_REQ;
575
576     /*
577      * Send the WM_NCDESTROY to the window being destroyed.
578      */
579     SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
580
581     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
582
583     WINPOS_CheckInternalPos( hwnd );
584
585     /* free resources associated with the window */
586
587     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
588     if (!(wndPtr->dwStyle & WS_CHILD)) menu = (HMENU)wndPtr->wIDmenu;
589     sys_menu = wndPtr->hSysMenu;
590     WIN_ReleasePtr( wndPtr );
591
592     if (menu) DestroyMenu( menu );
593     if (sys_menu) DestroyMenu( sys_menu );
594
595     USER_Driver->pDestroyWindow( hwnd );
596
597     free_window_handle( hwnd );
598     return 0;
599 }
600
601 /***********************************************************************
602  *           WIN_DestroyThreadWindows
603  *
604  * Destroy all children of 'wnd' owned by the current thread.
605  * Return TRUE if something was done.
606  */
607 void WIN_DestroyThreadWindows( HWND hwnd )
608 {
609     HWND *list;
610     int i;
611
612     if (!(list = WIN_ListChildren( hwnd ))) return;
613     for (i = 0; list[i]; i++)
614     {
615         if (WIN_IsCurrentThread( list[i] ))
616             DestroyWindow( list[i] );
617         else
618             WIN_DestroyThreadWindows( list[i] );
619     }
620     HeapFree( GetProcessHeap(), 0, list );
621 }
622
623
624 /***********************************************************************
625  *           WIN_FixCoordinates
626  *
627  * Fix the coordinates - Helper for WIN_CreateWindowEx.
628  * returns default show mode in sw.
629  * Note: the feature presented as undocumented *is* in the MSDN since 1993.
630  */
631 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
632 {
633     POINT pos[2];
634
635     if (cs->dwExStyle & WS_EX_MDICHILD)
636     {
637         UINT id = 0;
638
639         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
640         if (!(cs->style & WS_POPUP)) cs->hMenu = (HMENU)id;
641
642         TRACE("MDI child id %04x\n", id);
643     }
644
645     if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
646         cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
647     {
648         if (cs->style & (WS_CHILD | WS_POPUP))
649         {
650             if (cs->dwExStyle & WS_EX_MDICHILD)
651             {
652                 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
653                 {
654                     cs->x = pos[0].x;
655                     cs->y = pos[0].y;
656                 }
657                 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
658                     cs->cx = pos[1].x;
659                 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
660                     cs->cy = pos[1].y;
661             }
662             else
663             {
664                 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
665                     cs->x = cs->y = 0;
666                 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
667                     cs->cx = cs->cy = 0;
668             }
669         }
670         else  /* overlapped window */
671         {
672             STARTUPINFOW info;
673
674             GetStartupInfoW( &info );
675
676             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
677             {
678                 /* Never believe Microsoft's documentation... CreateWindowEx doc says
679                  * that if an overlapped window is created with WS_VISIBLE style bit
680                  * set and the x parameter is set to CW_USEDEFAULT, the system ignores
681                  * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
682                  * reveals that
683                  *
684                  * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
685                  * 2) it does not ignore the y parameter as the docs claim; instead, it
686                  *    uses it as second parameter to ShowWindow() unless y is either
687                  *    CW_USEDEFAULT or CW_USEDEFAULT16.
688                  *
689                  * The fact that we didn't do 2) caused bogus windows pop up when wine
690                  * was running apps that were using this obscure feature. Example -
691                  * calc.exe that comes with Win98 (only Win98, it's different from
692                  * the one that comes with Win95 and NT)
693                  */
694                 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
695                 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
696                 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
697             }
698
699             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
700             {
701                 if (info.dwFlags & STARTF_USESIZE)
702                 {
703                     cs->cx = info.dwXSize;
704                     cs->cy = info.dwYSize;
705                 }
706                 else  /* if no other hint from the app, pick 3/4 of the screen real estate */
707                 {
708                     RECT r;
709                     SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
710                     cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
711                     cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
712                 }
713             }
714             /* Handle case where only the cy values is set to default */
715             else if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16)
716             {
717                 RECT r;
718                 SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
719                 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
720             }
721         }
722     }
723     else
724     {
725         /* neither x nor cx are default. Check the y values .
726          * In the trace we see Outlook and Outlook Express using
727          * cy set to CW_USEDEFAULT when opening the address book.
728          */
729         if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
730             RECT r;
731             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
732             SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
733             cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
734         }
735     }
736 }
737
738 /***********************************************************************
739  *           dump_window_styles
740  */
741 static void dump_window_styles( DWORD style, DWORD exstyle )
742 {
743     TRACE( "style:" );
744     if(style & WS_POPUP) TRACE(" WS_POPUP");
745     if(style & WS_CHILD) TRACE(" WS_CHILD");
746     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
747     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
748     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
749     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
750     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
751     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
752     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
753     else
754     {
755         if(style & WS_BORDER) TRACE(" WS_BORDER");
756         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
757     }
758     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
759     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
760     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
761     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
762     if (style & WS_CHILD)
763     {
764         if(style & WS_GROUP) TRACE(" WS_GROUP");
765         if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
766     }
767     else
768     {
769         if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
770         if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
771     }
772
773     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
774 #define DUMPED_STYLES \
775     (WS_POPUP | \
776      WS_CHILD | \
777      WS_MINIMIZE | \
778      WS_VISIBLE | \
779      WS_DISABLED | \
780      WS_CLIPSIBLINGS | \
781      WS_CLIPCHILDREN | \
782      WS_MAXIMIZE | \
783      WS_BORDER | \
784      WS_DLGFRAME | \
785      WS_VSCROLL | \
786      WS_HSCROLL | \
787      WS_SYSMENU | \
788      WS_THICKFRAME | \
789      WS_GROUP | \
790      WS_TABSTOP | \
791      WS_MINIMIZEBOX | \
792      WS_MAXIMIZEBOX)
793
794     if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
795     TRACE("\n");
796 #undef DUMPED_STYLES
797
798     TRACE( "exstyle:" );
799     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
800     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
801     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
802     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
803     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
804     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
805     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
806     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
807     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
808     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
809     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
810     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
811     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
812     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
813     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
814     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
815     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
816     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
817
818 #define DUMPED_EX_STYLES \
819     (WS_EX_DLGMODALFRAME | \
820      WS_EX_DRAGDETECT | \
821      WS_EX_NOPARENTNOTIFY | \
822      WS_EX_TOPMOST | \
823      WS_EX_ACCEPTFILES | \
824      WS_EX_TRANSPARENT | \
825      WS_EX_MDICHILD | \
826      WS_EX_TOOLWINDOW | \
827      WS_EX_WINDOWEDGE | \
828      WS_EX_CLIENTEDGE | \
829      WS_EX_CONTEXTHELP | \
830      WS_EX_RIGHT | \
831      WS_EX_RTLREADING | \
832      WS_EX_LEFTSCROLLBAR | \
833      WS_EX_CONTROLPARENT | \
834      WS_EX_STATICEDGE | \
835      WS_EX_APPWINDOW | \
836      WS_EX_LAYERED)
837
838     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
839     TRACE("\n");
840 #undef DUMPED_EX_STYLES
841 }
842
843
844 /***********************************************************************
845  *           WIN_CreateWindowEx
846  *
847  * Implementation of CreateWindowEx().
848  */
849 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, UINT flags )
850 {
851     INT sw = SW_SHOW;
852     WND *wndPtr;
853     HWND hwnd, parent, owner, top_child = 0;
854     BOOL unicode = (flags & WIN_ISUNICODE) != 0;
855     MDICREATESTRUCTA mdi_cs;
856
857     TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
858           unicode ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
859           unicode ? debugstr_w((LPCWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
860           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
861           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
862     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
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, unicode )))
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->pVScroll       = NULL;
988     wndPtr->pHScroll       = NULL;
989     wndPtr->userdata       = 0;
990     wndPtr->hIcon          = 0;
991     wndPtr->hIconSmall     = 0;
992     wndPtr->hSysMenu       = 0;
993     wndPtr->flags         |= (flags & WIN_ISWIN32);
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 = (wndPtr->flags & WIN_ISUNICODE) != 0;
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, 0 ));
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_ISWIN32 );
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_ISWIN32 | WIN_ISUNICODE );
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 = (wndPtr->flags & WIN_ISUNICODE) != 0;
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, BOOL unicode )
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             WARN("Invalid offset %d\n", offset );
1888             WIN_ReleasePtr( wndPtr );
1889             SetLastError( ERROR_INVALID_INDEX );
1890             return 0;
1891         }
1892         retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset);
1893         /* Special case for dialog window procedure */
1894         if ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1895             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1896         WIN_ReleasePtr( wndPtr );
1897         return retvalue;
1898     }
1899
1900     switch(offset)
1901     {
1902     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1903     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1904     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1905     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1906     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break;
1907     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1908     default:
1909         WARN("Unknown offset %d\n", offset );
1910         SetLastError( ERROR_INVALID_INDEX );
1911         break;
1912     }
1913     WIN_ReleasePtr(wndPtr);
1914     return retvalue;
1915 }
1916
1917
1918 /**********************************************************************
1919  *           WIN_SetWindowLong
1920  *
1921  * Helper function for SetWindowLong().
1922  *
1923  * 0 is the failure code. However, in the case of failure SetLastError
1924  * must be set to distinguish between a 0 return value and a failure.
1925  */
1926 static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval, BOOL unicode )
1927 {
1928     STYLESTRUCT style;
1929     BOOL ok;
1930     LONG_PTR retval = 0;
1931     WND *wndPtr;
1932
1933     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1934
1935     if (is_broadcast(hwnd))
1936     {
1937         SetLastError( ERROR_INVALID_PARAMETER );
1938         return FALSE;
1939     }
1940
1941     if (!(wndPtr = WIN_GetPtr( hwnd )))
1942     {
1943         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1944         return 0;
1945     }
1946     if (wndPtr == WND_DESKTOP)
1947     {
1948         /* can't change anything on the desktop window */
1949         SetLastError( ERROR_ACCESS_DENIED );
1950         return 0;
1951     }
1952     if (wndPtr == WND_OTHER_PROCESS)
1953     {
1954         if (offset == GWLP_WNDPROC)
1955         {
1956             SetLastError( ERROR_ACCESS_DENIED );
1957             return 0;
1958         }
1959         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1960     }
1961
1962     /* first some special cases */
1963     switch( offset )
1964     {
1965     case GWL_STYLE:
1966     case GWL_EXSTYLE:
1967         style.styleOld =
1968             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1969         style.styleNew = newval;
1970         WIN_ReleasePtr( wndPtr );
1971         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1972         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1973         newval = style.styleNew;
1974         break;
1975     case GWLP_HWNDPARENT:
1976         if (wndPtr->parent == GetDesktopWindow())
1977         {
1978             WIN_ReleasePtr( wndPtr );
1979             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1980         }
1981         else
1982         {
1983             WIN_ReleasePtr( wndPtr );
1984             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1985         }
1986     case GWLP_WNDPROC:
1987     {
1988         UINT old_flags = wndPtr->flags;
1989         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1990         if (unicode) wndPtr->winproc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1991         else wndPtr->winproc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1992         if (WINPROC_IsUnicode( wndPtr->winproc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1993         else wndPtr->flags &= ~WIN_ISUNICODE;
1994         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1995         {
1996             WIN_ReleasePtr( wndPtr );
1997             return retval;
1998         }
1999         /* update is_unicode flag on the server side */
2000         break;
2001     }
2002     case GWLP_ID:
2003     case GWLP_HINSTANCE:
2004     case GWLP_USERDATA:
2005         break;
2006     case DWLP_DLGPROC:
2007         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2008         {
2009             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2010             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2011             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2012             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2013             WIN_ReleasePtr( wndPtr );
2014             return retval;
2015         }
2016         /* fall through */
2017     default:
2018         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG_PTR)))
2019         {
2020             WARN("Invalid offset %d\n", offset );
2021             WIN_ReleasePtr( wndPtr );
2022             SetLastError( ERROR_INVALID_INDEX );
2023             return 0;
2024         }
2025         else
2026         {
2027             LONG_PTR *ptr = (LONG_PTR *)((char *)wndPtr->wExtra + offset);
2028             if (*ptr == newval)  /* already set to the same value */
2029             {
2030                 WIN_ReleasePtr( wndPtr );
2031                 return newval;
2032             }
2033         }
2034         break;
2035     }
2036
2037     SERVER_START_REQ( set_window_info )
2038     {
2039         req->handle = hwnd;
2040         req->extra_offset = -1;
2041         switch(offset)
2042         {
2043         case GWL_STYLE:
2044             req->flags = SET_WIN_STYLE;
2045             req->style = newval;
2046             break;
2047         case GWL_EXSTYLE:
2048             req->flags = SET_WIN_EXSTYLE;
2049             req->ex_style = newval;
2050             break;
2051         case GWLP_ID:
2052             req->flags = SET_WIN_ID;
2053             req->id = newval;
2054             break;
2055         case GWLP_HINSTANCE:
2056             req->flags = SET_WIN_INSTANCE;
2057             req->instance = (void *)newval;
2058             break;
2059         case GWLP_WNDPROC:
2060             req->flags = SET_WIN_UNICODE;
2061             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2062             break;
2063         case GWLP_USERDATA:
2064             req->flags = SET_WIN_USERDATA;
2065             req->user_data = (void *)newval;
2066             break;
2067         default:
2068             req->flags = SET_WIN_EXTRA;
2069             req->extra_offset = offset;
2070             req->extra_size = sizeof(newval);
2071             memcpy( &req->extra_value, &newval, sizeof(newval) );
2072         }
2073         if ((ok = !wine_server_call_err( req )))
2074         {
2075             switch(offset)
2076             {
2077             case GWL_STYLE:
2078                 wndPtr->dwStyle = newval;
2079                 retval = reply->old_style;
2080                 break;
2081             case GWL_EXSTYLE:
2082                 wndPtr->dwExStyle = newval;
2083                 retval = reply->old_ex_style;
2084                 break;
2085             case GWLP_ID:
2086                 wndPtr->wIDmenu = newval;
2087                 retval = reply->old_id;
2088                 break;
2089             case GWLP_HINSTANCE:
2090                 wndPtr->hInstance = (HINSTANCE)newval;
2091                 retval = (ULONG_PTR)reply->old_instance;
2092                 break;
2093             case GWLP_WNDPROC:
2094                 break;
2095             case GWLP_USERDATA:
2096                 wndPtr->userdata = newval;
2097                 retval = (ULONG_PTR)reply->old_user_data;
2098                 break;
2099             default:
2100                 {
2101                     void *ptr = (char *)wndPtr->wExtra + offset;
2102                     memcpy( &retval, ptr, sizeof(retval) );
2103                     memcpy( ptr, &newval, sizeof(newval) );
2104                 }
2105                 break;
2106             }
2107         }
2108     }
2109     SERVER_END_REQ;
2110     WIN_ReleasePtr( wndPtr );
2111
2112     if (!ok) return 0;
2113
2114     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2115
2116     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2117         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2118
2119     return retval;
2120 }
2121
2122
2123 /**********************************************************************
2124  *              GetWindowLong (USER.135)
2125  */
2126 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2127 {
2128     WND *wndPtr;
2129     LONG_PTR retvalue;
2130     BOOL is_winproc = (offset == GWLP_WNDPROC);
2131
2132     if (offset >= 0)
2133     {
2134         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2135         {
2136             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2137             return 0;
2138         }
2139         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2140         {
2141             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2142             {
2143                 /*
2144                  * Some programs try to access last element from 16 bit
2145                  * code using illegal offset value. Hopefully this is
2146                  * what those programs really expect.
2147                  */
2148                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2149                 {
2150                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2151                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2152                     offset = offset2;
2153                 }
2154                 else
2155                 {
2156                     WARN("Invalid offset %d\n", offset );
2157                     WIN_ReleasePtr( wndPtr );
2158                     SetLastError( ERROR_INVALID_INDEX );
2159                     return 0;
2160                 }
2161             }
2162             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2163             WIN_ReleasePtr( wndPtr );
2164         }
2165     }
2166     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2167     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2168     return retvalue;
2169 }
2170
2171
2172 /**********************************************************************
2173  *              GetWindowLongA (USER32.@)
2174  */
2175 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2176 {
2177     return WIN_GetWindowLong( hwnd, offset, FALSE );
2178 }
2179
2180
2181 /**********************************************************************
2182  *              GetWindowLongW (USER32.@)
2183  */
2184 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2185 {
2186     return WIN_GetWindowLong( hwnd, offset, TRUE );
2187 }
2188
2189
2190 /**********************************************************************
2191  *              SetWindowLong (USER.136)
2192  */
2193 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2194 {
2195     WND *wndPtr;
2196     BOOL is_winproc = (offset == GWLP_WNDPROC);
2197
2198     if (offset == DWLP_DLGPROC)
2199     {
2200         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2201         {
2202             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2203             return 0;
2204         }
2205         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2206         {
2207             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2208                           (wndPtr->flags & WIN_ISDIALOG));
2209             WIN_ReleasePtr( wndPtr );
2210         }
2211     }
2212
2213     if (is_winproc)
2214     {
2215         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2216         WNDPROC old_proc = (WNDPROC)SetWindowLongA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2217         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2218     }
2219     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2220 }
2221
2222
2223 /**********************************************************************
2224  *              SetWindowLongA (USER32.@)
2225  *
2226  * See SetWindowLongW.
2227  */
2228 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2229 {
2230     return WIN_SetWindowLong( hwnd, offset, newval, FALSE );
2231 }
2232
2233
2234 /**********************************************************************
2235  *              SetWindowLongW (USER32.@) Set window attribute
2236  *
2237  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2238  * value in a window's extra memory.
2239  *
2240  * The _hwnd_ parameter specifies the window.  is the handle to a
2241  * window that has extra memory. The _newval_ parameter contains the
2242  * new attribute or extra memory value.  If positive, the _offset_
2243  * parameter is the byte-addressed location in the window's extra
2244  * memory to set.  If negative, _offset_ specifies the window
2245  * attribute to set, and should be one of the following values:
2246  *
2247  * GWL_EXSTYLE      The window's extended window style
2248  *
2249  * GWL_STYLE        The window's window style.
2250  *
2251  * GWLP_WNDPROC     Pointer to the window's window procedure.
2252  *
2253  * GWLP_HINSTANCE   The window's pplication instance handle.
2254  *
2255  * GWLP_ID          The window's identifier.
2256  *
2257  * GWLP_USERDATA    The window's user-specified data.
2258  *
2259  * If the window is a dialog box, the _offset_ parameter can be one of
2260  * the following values:
2261  *
2262  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2263  *
2264  * DWLP_MSGRESULT   The return value of a message
2265  *                  that the dialog box procedure processed.
2266  *
2267  * DWLP_USER        Application specific information.
2268  *
2269  * RETURNS
2270  *
2271  * If successful, returns the previous value located at _offset_. Otherwise,
2272  * returns 0.
2273  *
2274  * NOTES
2275  *
2276  * Extra memory for a window class is specified by a nonzero cbWndExtra
2277  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2278  * time of class creation.
2279  *
2280  * Using GWL_WNDPROC to set a new window procedure effectively creates
2281  * a window subclass. Use CallWindowProc() in the new windows procedure
2282  * to pass messages to the superclass's window procedure.
2283  *
2284  * The user data is reserved for use by the application which created
2285  * the window.
2286  *
2287  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2288  * instead, call the EnableWindow() function to change the window's
2289  * disabled state.
2290  *
2291  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2292  * SetParent() instead.
2293  *
2294  * Win95:
2295  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2296  * it sends WM_STYLECHANGING before changing the settings
2297  * and WM_STYLECHANGED afterwards.
2298  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2299  */
2300 LONG WINAPI SetWindowLongW(
2301     HWND hwnd,  /* [in] window to alter */
2302     INT offset, /* [in] offset, in bytes, of location to alter */
2303     LONG newval /* [in] new value of location */
2304 ) {
2305     return WIN_SetWindowLong( hwnd, offset, newval, TRUE );
2306 }
2307
2308
2309 /*******************************************************************
2310  *              GetWindowTextA (USER32.@)
2311  */
2312 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2313 {
2314     WCHAR *buffer;
2315
2316     if (!lpString) return 0;
2317
2318     if (WIN_IsCurrentProcess( hwnd ))
2319         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2320
2321     /* when window belongs to other process, don't send a message */
2322     if (nMaxCount <= 0) return 0;
2323     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2324     get_server_window_text( hwnd, buffer, nMaxCount );
2325     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2326         lpString[nMaxCount-1] = 0;
2327     HeapFree( GetProcessHeap(), 0, buffer );
2328     return strlen(lpString);
2329 }
2330
2331
2332 /*******************************************************************
2333  *              InternalGetWindowText (USER32.@)
2334  */
2335 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2336 {
2337     WND *win;
2338
2339     if (nMaxCount <= 0) return 0;
2340     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2341     if (win == WND_DESKTOP) lpString[0] = 0;
2342     else if (win != WND_OTHER_PROCESS)
2343     {
2344         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2345         else lpString[0] = 0;
2346         WIN_ReleasePtr( win );
2347     }
2348     else
2349     {
2350         get_server_window_text( hwnd, lpString, nMaxCount );
2351     }
2352     return strlenW(lpString);
2353 }
2354
2355
2356 /*******************************************************************
2357  *              GetWindowTextW (USER32.@)
2358  */
2359 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2360 {
2361     if (!lpString) return 0;
2362
2363     if (WIN_IsCurrentProcess( hwnd ))
2364         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2365
2366     /* when window belongs to other process, don't send a message */
2367     if (nMaxCount <= 0) return 0;
2368     get_server_window_text( hwnd, lpString, nMaxCount );
2369     return strlenW(lpString);
2370 }
2371
2372
2373 /*******************************************************************
2374  *              SetWindowTextA (USER32.@)
2375  *              SetWindowText  (USER32.@)
2376  */
2377 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2378 {
2379     if (is_broadcast(hwnd))
2380     {
2381         SetLastError( ERROR_INVALID_PARAMETER );
2382         return FALSE;
2383     }
2384     if (!WIN_IsCurrentProcess( hwnd ))
2385         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2386                debugstr_a(lpString), hwnd );
2387     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2388 }
2389
2390
2391 /*******************************************************************
2392  *              SetWindowTextW (USER32.@)
2393  */
2394 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2395 {
2396     if (is_broadcast(hwnd))
2397     {
2398         SetLastError( ERROR_INVALID_PARAMETER );
2399         return FALSE;
2400     }
2401     if (!WIN_IsCurrentProcess( hwnd ))
2402         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2403                debugstr_w(lpString), hwnd );
2404     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2405 }
2406
2407
2408 /*******************************************************************
2409  *              GetWindowTextLengthA (USER32.@)
2410  */
2411 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2412 {
2413     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2414 }
2415
2416 /*******************************************************************
2417  *              GetWindowTextLengthW (USER32.@)
2418  */
2419 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2420 {
2421     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2422 }
2423
2424
2425 /*******************************************************************
2426  *              IsWindow (USER32.@)
2427  */
2428 BOOL WINAPI IsWindow( HWND hwnd )
2429 {
2430     WND *ptr;
2431     BOOL ret;
2432
2433     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2434     if (ptr == WND_DESKTOP) return TRUE;
2435
2436     if (ptr != WND_OTHER_PROCESS)
2437     {
2438         WIN_ReleasePtr( ptr );
2439         return TRUE;
2440     }
2441
2442     /* check other processes */
2443     SERVER_START_REQ( get_window_info )
2444     {
2445         req->handle = hwnd;
2446         ret = !wine_server_call_err( req );
2447     }
2448     SERVER_END_REQ;
2449     return ret;
2450 }
2451
2452
2453 /***********************************************************************
2454  *              GetWindowThreadProcessId (USER32.@)
2455  */
2456 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2457 {
2458     WND *ptr;
2459     DWORD tid = 0;
2460
2461     if (!(ptr = WIN_GetPtr( hwnd )))
2462     {
2463         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2464         return 0;
2465     }
2466
2467     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2468     {
2469         /* got a valid window */
2470         tid = ptr->tid;
2471         if (process) *process = GetCurrentProcessId();
2472         WIN_ReleasePtr( ptr );
2473         return tid;
2474     }
2475
2476     /* check other processes */
2477     SERVER_START_REQ( get_window_info )
2478     {
2479         req->handle = hwnd;
2480         if (!wine_server_call_err( req ))
2481         {
2482             tid = (DWORD)reply->tid;
2483             if (process) *process = (DWORD)reply->pid;
2484         }
2485     }
2486     SERVER_END_REQ;
2487     return tid;
2488 }
2489
2490
2491 /*****************************************************************
2492  *              GetParent (USER32.@)
2493  */
2494 HWND WINAPI GetParent( HWND hwnd )
2495 {
2496     WND *wndPtr;
2497     HWND retvalue = 0;
2498
2499     if (!(wndPtr = WIN_GetPtr( hwnd )))
2500     {
2501         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2502         return 0;
2503     }
2504     if (wndPtr == WND_DESKTOP) return 0;
2505     if (wndPtr == WND_OTHER_PROCESS)
2506     {
2507         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2508         if (style & (WS_POPUP | WS_CHILD))
2509         {
2510             SERVER_START_REQ( get_window_tree )
2511             {
2512                 req->handle = hwnd;
2513                 if (!wine_server_call_err( req ))
2514                 {
2515                     if (style & WS_POPUP) retvalue = reply->owner;
2516                     else if (style & WS_CHILD) retvalue = reply->parent;
2517                 }
2518             }
2519             SERVER_END_REQ;
2520         }
2521     }
2522     else
2523     {
2524         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2525         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2526         WIN_ReleasePtr( wndPtr );
2527     }
2528     return retvalue;
2529 }
2530
2531
2532 /*****************************************************************
2533  *              GetAncestor (USER32.@)
2534  */
2535 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2536 {
2537     WND *win;
2538     HWND *list, ret = 0;
2539
2540     switch(type)
2541     {
2542     case GA_PARENT:
2543         if (!(win = WIN_GetPtr( hwnd )))
2544         {
2545             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2546             return 0;
2547         }
2548         if (win == WND_DESKTOP) return 0;
2549         if (win != WND_OTHER_PROCESS)
2550         {
2551             ret = win->parent;
2552             WIN_ReleasePtr( win );
2553         }
2554         else /* need to query the server */
2555         {
2556             SERVER_START_REQ( get_window_tree )
2557             {
2558                 req->handle = hwnd;
2559                 if (!wine_server_call_err( req )) ret = reply->parent;
2560             }
2561             SERVER_END_REQ;
2562         }
2563         break;
2564
2565     case GA_ROOT:
2566         if (!(list = list_window_parents( hwnd ))) return 0;
2567
2568         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2569         else
2570         {
2571             int count = 2;
2572             while (list[count]) count++;
2573             ret = list[count - 2];  /* get the one before the desktop */
2574         }
2575         HeapFree( GetProcessHeap(), 0, list );
2576         break;
2577
2578     case GA_ROOTOWNER:
2579         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2580         for (;;)
2581         {
2582             HWND parent = GetParent( ret );
2583             if (!parent) break;
2584             ret = parent;
2585         }
2586         break;
2587     }
2588     return ret;
2589 }
2590
2591
2592 /*****************************************************************
2593  *              SetParent (USER32.@)
2594  */
2595 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2596 {
2597     HWND full_handle;
2598
2599     if (is_broadcast(hwnd) || is_broadcast(parent))
2600     {
2601         SetLastError(ERROR_INVALID_PARAMETER);
2602         return 0;
2603     }
2604
2605     if (!parent) parent = GetDesktopWindow();
2606     else parent = WIN_GetFullHandle( parent );
2607
2608     if (!IsWindow( parent ))
2609     {
2610         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2611         return 0;
2612     }
2613
2614     /* Some applications try to set a child as a parent */
2615     if (IsChild(hwnd, parent))
2616     {
2617         SetLastError( ERROR_INVALID_PARAMETER );
2618         return 0;
2619     }
2620
2621     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2622         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2623
2624     return USER_Driver->pSetParent( full_handle, parent );
2625 }
2626
2627
2628 /*******************************************************************
2629  *              IsChild (USER32.@)
2630  */
2631 BOOL WINAPI IsChild( HWND parent, HWND child )
2632 {
2633     HWND *list = list_window_parents( child );
2634     int i;
2635     BOOL ret;
2636
2637     if (!list) return FALSE;
2638     parent = WIN_GetFullHandle( parent );
2639     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2640     ret = (list[i] != 0);
2641     HeapFree( GetProcessHeap(), 0, list );
2642     return ret;
2643 }
2644
2645
2646 /***********************************************************************
2647  *              IsWindowVisible (USER32.@)
2648  */
2649 BOOL WINAPI IsWindowVisible( HWND hwnd )
2650 {
2651     HWND *list;
2652     BOOL retval;
2653     int i;
2654
2655     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2656     if (!(list = list_window_parents( hwnd ))) return TRUE;
2657     for (i = 0; list[i]; i++)
2658         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2659     retval = !list[i];
2660     HeapFree( GetProcessHeap(), 0, list );
2661     return retval;
2662 }
2663
2664
2665 /***********************************************************************
2666  *           WIN_IsWindowDrawable
2667  *
2668  * hwnd is drawable when it is visible, all parents are not
2669  * minimized, and it is itself not minimized unless we are
2670  * trying to draw its default class icon.
2671  */
2672 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2673 {
2674     HWND *list;
2675     BOOL retval;
2676     int i;
2677     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2678
2679     if (!(style & WS_VISIBLE)) return FALSE;
2680     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2681
2682     if (!(list = list_window_parents( hwnd ))) return TRUE;
2683     for (i = 0; list[i]; i++)
2684         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2685             break;
2686     retval = !list[i];
2687     HeapFree( GetProcessHeap(), 0, list );
2688     return retval;
2689 }
2690
2691
2692 /*******************************************************************
2693  *              GetTopWindow (USER32.@)
2694  */
2695 HWND WINAPI GetTopWindow( HWND hwnd )
2696 {
2697     if (!hwnd) hwnd = GetDesktopWindow();
2698     return GetWindow( hwnd, GW_CHILD );
2699 }
2700
2701
2702 /*******************************************************************
2703  *              GetWindow (USER32.@)
2704  */
2705 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2706 {
2707     HWND retval = 0;
2708
2709     if (rel == GW_OWNER)  /* this one may be available locally */
2710     {
2711         WND *wndPtr = WIN_GetPtr( hwnd );
2712         if (!wndPtr)
2713         {
2714             SetLastError( ERROR_INVALID_HANDLE );
2715             return 0;
2716         }
2717         if (wndPtr == WND_DESKTOP) return 0;
2718         if (wndPtr != WND_OTHER_PROCESS)
2719         {
2720             retval = wndPtr->owner;
2721             WIN_ReleasePtr( wndPtr );
2722             return retval;
2723         }
2724         /* else fall through to server call */
2725     }
2726
2727     SERVER_START_REQ( get_window_tree )
2728     {
2729         req->handle = hwnd;
2730         if (!wine_server_call_err( req ))
2731         {
2732             switch(rel)
2733             {
2734             case GW_HWNDFIRST:
2735                 retval = reply->first_sibling;
2736                 break;
2737             case GW_HWNDLAST:
2738                 retval = reply->last_sibling;
2739                 break;
2740             case GW_HWNDNEXT:
2741                 retval = reply->next_sibling;
2742                 break;
2743             case GW_HWNDPREV:
2744                 retval = reply->prev_sibling;
2745                 break;
2746             case GW_OWNER:
2747                 retval = reply->owner;
2748                 break;
2749             case GW_CHILD:
2750                 retval = reply->first_child;
2751                 break;
2752             }
2753         }
2754     }
2755     SERVER_END_REQ;
2756     return retval;
2757 }
2758
2759
2760 /*******************************************************************
2761  *              ShowOwnedPopups (USER32.@)
2762  */
2763 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2764 {
2765     int count = 0;
2766     WND *pWnd;
2767     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2768
2769     if (!win_array) return TRUE;
2770
2771     while (win_array[count]) count++;
2772     while (--count >= 0)
2773     {
2774         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2775         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2776         if (pWnd == WND_OTHER_PROCESS) continue;
2777         if (fShow)
2778         {
2779             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2780             {
2781                 WIN_ReleasePtr( pWnd );
2782                 /* In Windows, ShowOwnedPopups(TRUE) generates
2783                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2784                  * regardless of the state of the owner
2785                  */
2786                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2787                 continue;
2788             }
2789         }
2790         else
2791         {
2792             if (pWnd->dwStyle & WS_VISIBLE)
2793             {
2794                 WIN_ReleasePtr( pWnd );
2795                 /* In Windows, ShowOwnedPopups(FALSE) generates
2796                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2797                  * regardless of the state of the owner
2798                  */
2799                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2800                 continue;
2801             }
2802         }
2803         WIN_ReleasePtr( pWnd );
2804     }
2805     HeapFree( GetProcessHeap(), 0, win_array );
2806     return TRUE;
2807 }
2808
2809
2810 /*******************************************************************
2811  *              GetLastActivePopup (USER32.@)
2812  */
2813 HWND WINAPI GetLastActivePopup( HWND hwnd )
2814 {
2815     HWND retval = hwnd;
2816
2817     SERVER_START_REQ( get_window_info )
2818     {
2819         req->handle = hwnd;
2820         if (!wine_server_call_err( req )) retval = reply->last_active;
2821     }
2822     SERVER_END_REQ;
2823     return retval;
2824 }
2825
2826
2827 /*******************************************************************
2828  *           WIN_ListChildren
2829  *
2830  * Build an array of the children of a given window. The array must be
2831  * freed with HeapFree. Returns NULL when no windows are found.
2832  */
2833 HWND *WIN_ListChildren( HWND hwnd )
2834 {
2835     return list_window_children( hwnd, 0, 0 );
2836 }
2837
2838
2839 /*******************************************************************
2840  *              EnumWindows (USER32.@)
2841  */
2842 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2843 {
2844     HWND *list;
2845     BOOL ret = TRUE;
2846     int i;
2847
2848     USER_CheckNotLock();
2849
2850     /* We have to build a list of all windows first, to avoid */
2851     /* unpleasant side-effects, for instance if the callback */
2852     /* function changes the Z-order of the windows.          */
2853
2854     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2855
2856     /* Now call the callback function for every window */
2857
2858     for (i = 0; list[i]; i++)
2859     {
2860         /* Make sure that the window still exists */
2861         if (!IsWindow( list[i] )) continue;
2862         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2863     }
2864     HeapFree( GetProcessHeap(), 0, list );
2865     return ret;
2866 }
2867
2868
2869 /**********************************************************************
2870  *              EnumThreadWindows (USER32.@)
2871  */
2872 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2873 {
2874     HWND *list;
2875     int i;
2876
2877     USER_CheckNotLock();
2878
2879     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2880
2881     /* Now call the callback function for every window */
2882
2883     for (i = 0; list[i]; i++)
2884         if (!func( list[i], lParam )) break;
2885     HeapFree( GetProcessHeap(), 0, list );
2886     return TRUE;
2887 }
2888
2889
2890 /**********************************************************************
2891  *           WIN_EnumChildWindows
2892  *
2893  * Helper function for EnumChildWindows().
2894  */
2895 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2896 {
2897     HWND *childList;
2898     BOOL ret = FALSE;
2899
2900     for ( ; *list; list++)
2901     {
2902         /* Make sure that the window still exists */
2903         if (!IsWindow( *list )) continue;
2904         /* Build children list first */
2905         childList = WIN_ListChildren( *list );
2906
2907         ret = func( *list, lParam );
2908
2909         if (childList)
2910         {
2911             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2912             HeapFree( GetProcessHeap(), 0, childList );
2913         }
2914         if (!ret) return FALSE;
2915     }
2916     return TRUE;
2917 }
2918
2919
2920 /**********************************************************************
2921  *              EnumChildWindows (USER32.@)
2922  */
2923 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2924 {
2925     HWND *list;
2926     BOOL ret;
2927
2928     USER_CheckNotLock();
2929
2930     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2931     ret = WIN_EnumChildWindows( list, func, lParam );
2932     HeapFree( GetProcessHeap(), 0, list );
2933     return ret;
2934 }
2935
2936
2937 /*******************************************************************
2938  *              AnyPopup (USER.52)
2939  */
2940 BOOL16 WINAPI AnyPopup16(void)
2941 {
2942     return AnyPopup();
2943 }
2944
2945
2946 /*******************************************************************
2947  *              AnyPopup (USER32.@)
2948  */
2949 BOOL WINAPI AnyPopup(void)
2950 {
2951     int i;
2952     BOOL retvalue;
2953     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2954
2955     if (!list) return FALSE;
2956     for (i = 0; list[i]; i++)
2957     {
2958         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2959     }
2960     retvalue = (list[i] != 0);
2961     HeapFree( GetProcessHeap(), 0, list );
2962     return retvalue;
2963 }
2964
2965
2966 /*******************************************************************
2967  *              FlashWindow (USER32.@)
2968  */
2969 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2970 {
2971     WND *wndPtr;
2972
2973     TRACE("%p\n", hWnd);
2974
2975     if (IsIconic( hWnd ))
2976     {
2977         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2978
2979         wndPtr = WIN_GetPtr(hWnd);
2980         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2981         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2982         {
2983             wndPtr->flags |= WIN_NCACTIVATED;
2984         }
2985         else
2986         {
2987             wndPtr->flags &= ~WIN_NCACTIVATED;
2988         }
2989         WIN_ReleasePtr( wndPtr );
2990         return TRUE;
2991     }
2992     else
2993     {
2994         WPARAM wparam;
2995
2996         wndPtr = WIN_GetPtr(hWnd);
2997         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2998         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2999
3000         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3001         else wparam = (hWnd == GetForegroundWindow());
3002
3003         WIN_ReleasePtr( wndPtr );
3004         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3005         return wparam;
3006     }
3007 }
3008
3009 /*******************************************************************
3010  *              FlashWindowEx (USER32.@)
3011  */
3012 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3013 {
3014     FIXME("%p\n", pfwi);
3015     return TRUE;
3016 }
3017
3018 /*******************************************************************
3019  *              GetWindowContextHelpId (USER32.@)
3020  */
3021 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3022 {
3023     DWORD retval;
3024     WND *wnd = WIN_GetPtr( hwnd );
3025     if (!wnd || wnd == WND_DESKTOP) return 0;
3026     if (wnd == WND_OTHER_PROCESS)
3027     {
3028         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3029         return 0;
3030     }
3031     retval = wnd->helpContext;
3032     WIN_ReleasePtr( wnd );
3033     return retval;
3034 }
3035
3036
3037 /*******************************************************************
3038  *              SetWindowContextHelpId (USER32.@)
3039  */
3040 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3041 {
3042     WND *wnd = WIN_GetPtr( hwnd );
3043     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3044     if (wnd == WND_OTHER_PROCESS)
3045     {
3046         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3047         return 0;
3048     }
3049     wnd->helpContext = id;
3050     WIN_ReleasePtr( wnd );
3051     return TRUE;
3052 }
3053
3054
3055 /*******************************************************************
3056  *              DragDetect (USER32.@)
3057  */
3058 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3059 {
3060     MSG msg;
3061     RECT rect;
3062     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3063     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3064
3065     rect.left = pt.x - wDragWidth;
3066     rect.right = pt.x + wDragWidth;
3067
3068     rect.top = pt.y - wDragHeight;
3069     rect.bottom = pt.y + wDragHeight;
3070
3071     SetCapture(hWnd);
3072
3073     while(1)
3074     {
3075         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3076         {
3077             if( msg.message == WM_LBUTTONUP )
3078             {
3079                 ReleaseCapture();
3080                 return 0;
3081             }
3082             if( msg.message == WM_MOUSEMOVE )
3083             {
3084                 POINT tmp;
3085                 tmp.x = LOWORD(msg.lParam);
3086                 tmp.y = HIWORD(msg.lParam);
3087                 if( !PtInRect( &rect, tmp ))
3088                 {
3089                     ReleaseCapture();
3090                     return 1;
3091                 }
3092             }
3093         }
3094         WaitMessage();
3095     }
3096     return 0;
3097 }
3098
3099 /******************************************************************************
3100  *              GetWindowModuleFileNameA (USER32.@)
3101  */
3102 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3103 {
3104     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3105           hwnd, lpszFileName, cchFileNameMax);
3106     return 0;
3107 }
3108
3109 /******************************************************************************
3110  *              GetWindowModuleFileNameW (USER32.@)
3111  */
3112 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3113 {
3114     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3115           hwnd, lpszFileName, cchFileNameMax);
3116     return 0;
3117 }
3118
3119 /******************************************************************************
3120  *              GetWindowInfo (USER32.@)
3121  *
3122  * Note: tests show that Windows doesn't check cbSize of the structure.
3123  */
3124 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3125 {
3126     if (!pwi) return FALSE;
3127     if (!IsWindow(hwnd)) return FALSE;
3128
3129     GetWindowRect(hwnd, &pwi->rcWindow);
3130     GetClientRect(hwnd, &pwi->rcClient);
3131     /* translate to screen coordinates */
3132     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3133
3134     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3135     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3136     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3137
3138     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3139     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3140
3141     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3142     pwi->wCreatorVersion = 0x0400;
3143
3144     return TRUE;
3145 }
3146
3147 /******************************************************************************
3148  *              SwitchDesktop (USER32.@)
3149  *
3150  * NOTES: Sets the current input or interactive desktop.
3151  */
3152 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3153 {
3154     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3155     return TRUE;
3156 }
3157
3158 /*****************************************************************************
3159  *              SetLayeredWindowAttributes (USER32.@)
3160  */
3161 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3162                                         BYTE bAlpha, DWORD dwFlags )
3163 {
3164     FIXME("(%p,0x%.8lx,%d,%ld): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3165     return TRUE;
3166 }
3167
3168 /*****************************************************************************
3169  *              UpdateLayeredWindow (USER32.@)
3170  */
3171 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3172                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3173                                  DWORD dwFlags)
3174 {
3175     FIXME("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%ld): stub!\n",
3176           hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3177     return 0;
3178 }