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