wined3d: Add the bulk of the GLSL string generation functions.
[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_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1041         (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1042     {
1043         if (cs->hMenu)
1044         {
1045             if (!MENU_SetMenu(hwnd, cs->hMenu))
1046             {
1047                 WIN_ReleasePtr( wndPtr );
1048                 free_window_handle( hwnd );
1049                 return 0;
1050             }
1051         }
1052         else
1053         {
1054             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1055             if (menuName)
1056             {
1057                 if (!cs->hInstance || HIWORD(cs->hInstance))
1058                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1059                 else
1060                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1061
1062                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1063             }
1064         }
1065     }
1066     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1067     WIN_ReleasePtr( wndPtr );
1068
1069     if (!USER_Driver->pCreateWindow( hwnd, cs, unicode))
1070     {
1071         WIN_DestroyWindow( hwnd );
1072         return 0;
1073     }
1074
1075     /* Notify the parent window only */
1076
1077     send_parent_notify( hwnd, WM_CREATE );
1078     if (!IsWindow( hwnd )) return 0;
1079
1080     if (cs->style & WS_VISIBLE)
1081     {
1082         if (cs->style & WS_MAXIMIZE)
1083             sw = SW_SHOW;
1084         else if (cs->style & WS_MINIMIZE)
1085             sw = SW_SHOWMINIMIZED;
1086
1087         ShowWindow( hwnd, sw );
1088         if (cs->dwExStyle & WS_EX_MDICHILD)
1089         {
1090             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1091             /* ShowWindow won't activate child windows */
1092             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1093         }
1094     }
1095
1096     /* Call WH_SHELL hook */
1097
1098     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1099         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1100
1101     TRACE("created window %p\n", hwnd);
1102     return hwnd;
1103 }
1104
1105
1106 /***********************************************************************
1107  *              CreateWindow (USER.41)
1108  */
1109 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1110                               DWORD style, INT16 x, INT16 y, INT16 width,
1111                               INT16 height, HWND16 parent, HMENU16 menu,
1112                               HINSTANCE16 instance, LPVOID data )
1113 {
1114     return CreateWindowEx16( 0, className, windowName, style,
1115                              x, y, width, height, parent, menu, instance, data );
1116 }
1117
1118
1119 /***********************************************************************
1120  *              CreateWindowEx (USER.452)
1121  */
1122 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1123                                 LPCSTR windowName, DWORD style, INT16 x,
1124                                 INT16 y, INT16 width, INT16 height,
1125                                 HWND16 parent, HMENU16 menu,
1126                                 HINSTANCE16 instance, LPVOID data )
1127 {
1128     ATOM classAtom;
1129     CREATESTRUCTA cs;
1130     char buffer[256];
1131
1132     /* Find the class atom */
1133
1134     if (HIWORD(className))
1135     {
1136         if (!(classAtom = GlobalFindAtomA( className )))
1137         {
1138             ERR( "bad class name %s\n", debugstr_a(className) );
1139             return 0;
1140         }
1141     }
1142     else
1143     {
1144         classAtom = LOWORD(className);
1145         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1146         {
1147             ERR( "bad atom %x\n", classAtom);
1148             return 0;
1149         }
1150         className = buffer;
1151     }
1152
1153     /* Fix the coordinates */
1154
1155     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1156     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1157     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1158     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1159
1160     /* Create the window */
1161
1162     cs.lpCreateParams = data;
1163     cs.hInstance      = HINSTANCE_32(instance);
1164     cs.hMenu          = HMENU_32(menu);
1165     cs.hwndParent     = WIN_Handle32( parent );
1166     cs.style          = style;
1167     cs.lpszName       = windowName;
1168     cs.lpszClass      = className;
1169     cs.dwExStyle      = exStyle;
1170
1171     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, 0 ));
1172 }
1173
1174
1175 /***********************************************************************
1176  *              CreateWindowExA (USER32.@)
1177  */
1178 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1179                                  LPCSTR windowName, DWORD style, INT x,
1180                                  INT y, INT width, INT height,
1181                                  HWND parent, HMENU menu,
1182                                  HINSTANCE instance, LPVOID data )
1183 {
1184     ATOM classAtom;
1185     CREATESTRUCTA cs;
1186     char buffer[256];
1187
1188     /* Find the class atom */
1189
1190     if (HIWORD(className))
1191     {
1192         if (!(classAtom = GlobalFindAtomA( className )))
1193         {
1194             ERR( "bad class name %s\n", debugstr_a(className) );
1195             return 0;
1196         }
1197     }
1198     else
1199     {
1200         classAtom = LOWORD(className);
1201         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1202         {
1203             ERR( "bad atom %x\n", classAtom);
1204             return 0;
1205         }
1206         className = buffer;
1207     }
1208
1209     /* Create the window */
1210
1211     cs.lpCreateParams = data;
1212     cs.hInstance      = instance;
1213     cs.hMenu          = menu;
1214     cs.hwndParent     = parent;
1215     cs.x              = x;
1216     cs.y              = y;
1217     cs.cx             = width;
1218     cs.cy             = height;
1219     cs.style          = style;
1220     cs.lpszName       = windowName;
1221     cs.lpszClass      = className;
1222     cs.dwExStyle      = exStyle;
1223
1224     return WIN_CreateWindowEx( &cs, classAtom, WIN_ISWIN32 );
1225 }
1226
1227
1228 /***********************************************************************
1229  *              CreateWindowExW (USER32.@)
1230  */
1231 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1232                                  LPCWSTR windowName, DWORD style, INT x,
1233                                  INT y, INT width, INT height,
1234                                  HWND parent, HMENU menu,
1235                                  HINSTANCE instance, LPVOID data )
1236 {
1237     ATOM classAtom;
1238     CREATESTRUCTW cs;
1239     WCHAR buffer[256];
1240
1241     /* Find the class atom */
1242
1243     if (HIWORD(className))
1244     {
1245         if (!(classAtom = GlobalFindAtomW( className )))
1246         {
1247             ERR( "bad class name %s\n", debugstr_w(className) );
1248             return 0;
1249         }
1250     }
1251     else
1252     {
1253         classAtom = LOWORD(className);
1254         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1255         {
1256             ERR( "bad atom %x\n", classAtom);
1257             return 0;
1258         }
1259         className = buffer;
1260     }
1261
1262     /* Create the window */
1263
1264     cs.lpCreateParams = data;
1265     cs.hInstance      = instance;
1266     cs.hMenu          = menu;
1267     cs.hwndParent     = parent;
1268     cs.x              = x;
1269     cs.y              = y;
1270     cs.cx             = width;
1271     cs.cy             = height;
1272     cs.style          = style;
1273     cs.lpszName       = windowName;
1274     cs.lpszClass      = className;
1275     cs.dwExStyle      = exStyle;
1276
1277     /* Note: we rely on the fact that CREATESTRUCTA and */
1278     /* CREATESTRUCTW have the same layout. */
1279     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_ISWIN32 | WIN_ISUNICODE );
1280 }
1281
1282
1283 /***********************************************************************
1284  *           WIN_SendDestroyMsg
1285  */
1286 static void WIN_SendDestroyMsg( HWND hwnd )
1287 {
1288     GUITHREADINFO info;
1289
1290     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1291     {
1292         if (hwnd == info.hwndCaret) DestroyCaret();
1293         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1294     }
1295
1296     /*
1297      * Send the WM_DESTROY to the window.
1298      */
1299     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1300
1301     /*
1302      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1303      * make sure that the window still exists when we come back.
1304      */
1305     if (IsWindow(hwnd))
1306     {
1307         HWND* pWndArray;
1308         int i;
1309
1310         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1311
1312         for (i = 0; pWndArray[i]; i++)
1313         {
1314             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1315         }
1316         HeapFree( GetProcessHeap(), 0, pWndArray );
1317     }
1318     else
1319       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1320 }
1321
1322
1323 /***********************************************************************
1324  *              DestroyWindow (USER32.@)
1325  */
1326 BOOL WINAPI DestroyWindow( HWND hwnd )
1327 {
1328     BOOL is_child;
1329
1330     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1331     {
1332         SetLastError( ERROR_ACCESS_DENIED );
1333         return FALSE;
1334     }
1335
1336     TRACE("(%p)\n", hwnd);
1337
1338       /* Call hooks */
1339
1340     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1341
1342     if (MENU_IsMenuActive() == hwnd)
1343         EndMenu();
1344
1345     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1346
1347     if (is_child)
1348     {
1349         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1350             send_parent_notify( hwnd, WM_DESTROY );
1351     }
1352     else if (!GetWindow( hwnd, GW_OWNER ))
1353     {
1354         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1355         /* FIXME: clean up palette - see "Internals" p.352 */
1356     }
1357
1358     if (!IsWindow(hwnd)) return TRUE;
1359
1360       /* Hide the window */
1361     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1362     {
1363         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1364         if (is_child)
1365             ShowWindow( hwnd, SW_HIDE );
1366         else
1367             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1368                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1369     }
1370
1371     if (!IsWindow(hwnd)) return TRUE;
1372
1373       /* Recursively destroy owned windows */
1374
1375     if (!is_child)
1376     {
1377         for (;;)
1378         {
1379             int i, got_one = 0;
1380             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1381             if (list)
1382             {
1383                 for (i = 0; list[i]; i++)
1384                 {
1385                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1386                     if (WIN_IsCurrentThread( list[i] ))
1387                     {
1388                         DestroyWindow( list[i] );
1389                         got_one = 1;
1390                         continue;
1391                     }
1392                     WIN_SetOwner( list[i], 0 );
1393                 }
1394                 HeapFree( GetProcessHeap(), 0, list );
1395             }
1396             if (!got_one) break;
1397         }
1398     }
1399
1400       /* Send destroy messages */
1401
1402     WIN_SendDestroyMsg( hwnd );
1403     if (!IsWindow( hwnd )) return TRUE;
1404
1405     if (GetClipboardOwner() == hwnd)
1406         CLIPBOARD_ReleaseOwner();
1407
1408       /* Destroy the window storage */
1409
1410     WIN_DestroyWindow( hwnd );
1411     return TRUE;
1412 }
1413
1414
1415 /***********************************************************************
1416  *              CloseWindow (USER32.@)
1417  */
1418 BOOL WINAPI CloseWindow( HWND hwnd )
1419 {
1420     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1421     ShowWindow( hwnd, SW_MINIMIZE );
1422     return TRUE;
1423 }
1424
1425
1426 /***********************************************************************
1427  *              OpenIcon (USER32.@)
1428  */
1429 BOOL WINAPI OpenIcon( HWND hwnd )
1430 {
1431     if (!IsIconic( hwnd )) return FALSE;
1432     ShowWindow( hwnd, SW_SHOWNORMAL );
1433     return TRUE;
1434 }
1435
1436
1437 /***********************************************************************
1438  *           WIN_FindWindow
1439  *
1440  * Implementation of FindWindow() and FindWindowEx().
1441  */
1442 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1443 {
1444     HWND *list = NULL;
1445     HWND retvalue = 0;
1446     int i = 0, len = 0;
1447     WCHAR *buffer = NULL;
1448
1449     if (!parent) parent = GetDesktopWindow();
1450     if (title)
1451     {
1452         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1453         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1454     }
1455
1456     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1457
1458     if (child)
1459     {
1460         child = WIN_GetFullHandle( child );
1461         while (list[i] && list[i] != child) i++;
1462         if (!list[i]) goto done;
1463         i++;  /* start from next window */
1464     }
1465
1466     if (title)
1467     {
1468         while (list[i])
1469         {
1470             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1471             i++;
1472         }
1473     }
1474     retvalue = list[i];
1475
1476  done:
1477     HeapFree( GetProcessHeap(), 0, list );
1478     HeapFree( GetProcessHeap(), 0, buffer );
1479     return retvalue;
1480 }
1481
1482
1483
1484 /***********************************************************************
1485  *              FindWindowA (USER32.@)
1486  */
1487 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1488 {
1489     HWND ret = FindWindowExA( 0, 0, className, title );
1490     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1491     return ret;
1492 }
1493
1494
1495 /***********************************************************************
1496  *              FindWindowExA (USER32.@)
1497  */
1498 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1499                                LPCSTR className, LPCSTR title )
1500 {
1501     ATOM atom = 0;
1502     LPWSTR buffer;
1503     HWND hwnd;
1504     INT len;
1505
1506     if (className)
1507     {
1508         /* If the atom doesn't exist, then no class */
1509         /* with this name exists either. */
1510         if (!(atom = GlobalFindAtomA( className )))
1511         {
1512             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1513             return 0;
1514         }
1515     }
1516     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1517
1518     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1519     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1520     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1521     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1522     HeapFree( GetProcessHeap(), 0, buffer );
1523     return hwnd;
1524 }
1525
1526
1527 /***********************************************************************
1528  *              FindWindowExW (USER32.@)
1529  */
1530 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1531                                LPCWSTR className, LPCWSTR title )
1532 {
1533     ATOM atom = 0;
1534
1535     if (className)
1536     {
1537         /* If the atom doesn't exist, then no class */
1538         /* with this name exists either. */
1539         if (!(atom = GlobalFindAtomW( className )))
1540         {
1541             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1542             return 0;
1543         }
1544     }
1545     return WIN_FindWindow( parent, child, atom, title );
1546 }
1547
1548
1549 /***********************************************************************
1550  *              FindWindowW (USER32.@)
1551  */
1552 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1553 {
1554     return FindWindowExW( 0, 0, className, title );
1555 }
1556
1557
1558 /**********************************************************************
1559  *              GetDesktopWindow (USER32.@)
1560  */
1561 HWND WINAPI GetDesktopWindow(void)
1562 {
1563     struct user_thread_info *thread_info = get_user_thread_info();
1564
1565     if (thread_info->desktop) return thread_info->desktop;
1566
1567     SERVER_START_REQ( get_desktop_window )
1568     {
1569         req->force = 0;
1570         if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1571     }
1572     SERVER_END_REQ;
1573
1574     if (!thread_info->desktop)
1575     {
1576         STARTUPINFOW si;
1577         PROCESS_INFORMATION pi;
1578         WCHAR command_line[] = {'e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1579
1580         memset( &si, 0, sizeof(si) );
1581         si.cb = sizeof(si);
1582         if (CreateProcessW( NULL, command_line, NULL, NULL, FALSE, DETACHED_PROCESS,
1583                             NULL, NULL, &si, &pi ))
1584         {
1585             TRACE( "started explorer pid %04lx tid %04lx\n", pi.dwProcessId, pi.dwThreadId );
1586             WaitForInputIdle( pi.hProcess, 10000 );
1587             CloseHandle( pi.hThread );
1588             CloseHandle( pi.hProcess );
1589
1590         }
1591         else WARN( "failed to start explorer, err %ld\n", GetLastError() );
1592
1593         SERVER_START_REQ( get_desktop_window )
1594         {
1595             req->force = 1;
1596             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1597         }
1598         SERVER_END_REQ;
1599     }
1600
1601     if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1602         ERR( "failed to create desktop window\n" );
1603
1604     return thread_info->desktop;
1605 }
1606
1607
1608 /*******************************************************************
1609  *              EnableWindow (USER32.@)
1610  */
1611 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1612 {
1613     BOOL retvalue;
1614     HWND full_handle;
1615
1616     if (is_broadcast(hwnd))
1617     {
1618         SetLastError( ERROR_INVALID_PARAMETER );
1619         return FALSE;
1620     }
1621
1622     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1623         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1624
1625     hwnd = full_handle;
1626
1627     TRACE("( %p, %d )\n", hwnd, enable);
1628
1629     retvalue = !IsWindowEnabled( hwnd );
1630
1631     if (enable && retvalue)
1632     {
1633         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1634         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1635     }
1636     else if (!enable && !retvalue)
1637     {
1638         HWND capture_wnd;
1639
1640         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1641
1642         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1643
1644         if (hwnd == GetFocus())
1645             SetFocus( 0 );  /* A disabled window can't have the focus */
1646
1647         capture_wnd = GetCapture();
1648         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1649             ReleaseCapture();  /* A disabled window can't capture the mouse */
1650
1651         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1652     }
1653     return retvalue;
1654 }
1655
1656
1657 /***********************************************************************
1658  *              IsWindowEnabled (USER32.@)
1659  */
1660 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1661 {
1662     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1663 }
1664
1665
1666 /***********************************************************************
1667  *              IsWindowUnicode (USER32.@)
1668  */
1669 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1670 {
1671     WND * wndPtr;
1672     BOOL retvalue = FALSE;
1673
1674     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1675
1676     if (wndPtr == WND_DESKTOP) return TRUE;
1677
1678     if (wndPtr != WND_OTHER_PROCESS)
1679     {
1680         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1681         WIN_ReleasePtr( wndPtr );
1682     }
1683     else
1684     {
1685         SERVER_START_REQ( get_window_info )
1686         {
1687             req->handle = hwnd;
1688             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1689         }
1690         SERVER_END_REQ;
1691     }
1692     return retvalue;
1693 }
1694
1695
1696 /**********************************************************************
1697  *              GetWindowWord (USER32.@)
1698  */
1699 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1700 {
1701     if (offset >= 0)
1702     {
1703         WORD retvalue = 0;
1704         WND *wndPtr = WIN_GetPtr( hwnd );
1705         if (!wndPtr)
1706         {
1707             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1708             return 0;
1709         }
1710         if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1711         {
1712             SERVER_START_REQ( set_window_info )
1713             {
1714                 req->handle = hwnd;
1715                 req->flags  = 0;  /* don't set anything, just retrieve */
1716                 req->extra_offset = offset;
1717                 req->extra_size = sizeof(retvalue);
1718                 if (!wine_server_call_err( req ))
1719                     memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1720             }
1721             SERVER_END_REQ;
1722             return retvalue;
1723         }
1724         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1725         {
1726             WARN("Invalid offset %d\n", offset );
1727             SetLastError( ERROR_INVALID_INDEX );
1728         }
1729         else memcpy( &retvalue,  (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1730         WIN_ReleasePtr( wndPtr );
1731         return retvalue;
1732     }
1733
1734     switch(offset)
1735     {
1736     case GWLP_HWNDPARENT:
1737         return GetWindowLongPtrW( hwnd, offset );
1738     case GWLP_ID:
1739     case GWLP_HINSTANCE:
1740         {
1741             LONG_PTR ret = GetWindowLongPtrW( hwnd, offset );
1742             if (HIWORD(ret))
1743                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1744             return LOWORD(ret);
1745         }
1746     default:
1747         WARN("Invalid offset %d\n", offset );
1748         return 0;
1749     }
1750 }
1751
1752
1753 /**********************************************************************
1754  *              SetWindowWord (USER32.@)
1755  */
1756 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1757 {
1758     WORD retval = 0;
1759     WND * wndPtr;
1760
1761     switch(offset)
1762     {
1763     case GWLP_ID:
1764     case GWLP_HINSTANCE:
1765     case GWLP_HWNDPARENT:
1766         return SetWindowLongPtrW( hwnd, offset, (ULONG_PTR)newval );
1767     default:
1768         if (offset < 0)
1769         {
1770             WARN("Invalid offset %d\n", offset );
1771             SetLastError( ERROR_INVALID_INDEX );
1772             return 0;
1773         }
1774     }
1775
1776     wndPtr = WIN_GetPtr( hwnd );
1777     if (wndPtr == WND_DESKTOP)
1778     {
1779         SetLastError( ERROR_ACCESS_DENIED );
1780         return 0;
1781     }
1782     if (wndPtr == WND_OTHER_PROCESS)
1783     {
1784         if (IsWindow(hwnd))
1785             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1786                    offset, newval, hwnd );
1787         wndPtr = NULL;
1788     }
1789     if (!wndPtr)
1790     {
1791        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1792        return 0;
1793     }
1794
1795     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1796     {
1797         WARN("Invalid offset %d\n", offset );
1798         WIN_ReleasePtr(wndPtr);
1799         SetLastError( ERROR_INVALID_INDEX );
1800         return 0;
1801     }
1802
1803     SERVER_START_REQ( set_window_info )
1804     {
1805         req->handle = hwnd;
1806         req->flags = SET_WIN_EXTRA;
1807         req->extra_offset = offset;
1808         req->extra_size = sizeof(newval);
1809         memcpy( &req->extra_value, &newval, sizeof(newval) );
1810         if (!wine_server_call_err( req ))
1811         {
1812             void *ptr = (char *)wndPtr->wExtra + offset;
1813             memcpy( &retval, ptr, sizeof(retval) );
1814             memcpy( ptr, &newval, sizeof(newval) );
1815         }
1816     }
1817     SERVER_END_REQ;
1818     WIN_ReleasePtr( wndPtr );
1819     return retval;
1820 }
1821
1822
1823 /**********************************************************************
1824  *           WIN_GetWindowLong
1825  *
1826  * Helper function for GetWindowLong().
1827  */
1828 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, BOOL unicode )
1829 {
1830     LONG_PTR retvalue = 0;
1831     WND *wndPtr;
1832
1833     if (offset == GWLP_HWNDPARENT)
1834     {
1835         HWND parent = GetAncestor( hwnd, GA_PARENT );
1836         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1837         return (ULONG_PTR)parent;
1838     }
1839
1840     if (!(wndPtr = WIN_GetPtr( hwnd )))
1841     {
1842         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1843         return 0;
1844     }
1845
1846     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1847     {
1848         if (offset == GWLP_WNDPROC)
1849         {
1850             SetLastError( ERROR_ACCESS_DENIED );
1851             return 0;
1852         }
1853         SERVER_START_REQ( set_window_info )
1854         {
1855             req->handle = hwnd;
1856             req->flags  = 0;  /* don't set anything, just retrieve */
1857             req->extra_offset = (offset >= 0) ? offset : -1;
1858             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1859             if (!wine_server_call_err( req ))
1860             {
1861                 switch(offset)
1862                 {
1863                 case GWL_STYLE:      retvalue = reply->old_style; break;
1864                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1865                 case GWLP_ID:        retvalue = reply->old_id; break;
1866                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1867                 case GWLP_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1868                 default:
1869                     if (offset >= 0) retvalue = reply->old_extra_value;
1870                     else SetLastError( ERROR_INVALID_INDEX );
1871                     break;
1872                 }
1873             }
1874         }
1875         SERVER_END_REQ;
1876         return retvalue;
1877     }
1878
1879     /* now we have a valid wndPtr */
1880
1881     if (offset >= 0)
1882     {
1883         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1884         {
1885             WARN("Invalid offset %d\n", offset );
1886             WIN_ReleasePtr( wndPtr );
1887             SetLastError( ERROR_INVALID_INDEX );
1888             return 0;
1889         }
1890         retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset);
1891         /* Special case for dialog window procedure */
1892         if ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1893             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1894         WIN_ReleasePtr( wndPtr );
1895         return retvalue;
1896     }
1897
1898     switch(offset)
1899     {
1900     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1901     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1902     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1903     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1904     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break;
1905     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1906     default:
1907         WARN("Unknown offset %d\n", offset );
1908         SetLastError( ERROR_INVALID_INDEX );
1909         break;
1910     }
1911     WIN_ReleasePtr(wndPtr);
1912     return retvalue;
1913 }
1914
1915
1916 /**********************************************************************
1917  *           WIN_SetWindowLong
1918  *
1919  * Helper function for SetWindowLong().
1920  *
1921  * 0 is the failure code. However, in the case of failure SetLastError
1922  * must be set to distinguish between a 0 return value and a failure.
1923  */
1924 static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval, BOOL unicode )
1925 {
1926     STYLESTRUCT style;
1927     BOOL ok;
1928     LONG_PTR retval = 0;
1929     WND *wndPtr;
1930
1931     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1932
1933     if (is_broadcast(hwnd))
1934     {
1935         SetLastError( ERROR_INVALID_PARAMETER );
1936         return FALSE;
1937     }
1938
1939     if (!(wndPtr = WIN_GetPtr( hwnd )))
1940     {
1941         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1942         return 0;
1943     }
1944     if (wndPtr == WND_DESKTOP)
1945     {
1946         /* can't change anything on the desktop window */
1947         SetLastError( ERROR_ACCESS_DENIED );
1948         return 0;
1949     }
1950     if (wndPtr == WND_OTHER_PROCESS)
1951     {
1952         if (offset == GWLP_WNDPROC)
1953         {
1954             SetLastError( ERROR_ACCESS_DENIED );
1955             return 0;
1956         }
1957         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1958     }
1959
1960     /* first some special cases */
1961     switch( offset )
1962     {
1963     case GWL_STYLE:
1964     case GWL_EXSTYLE:
1965         style.styleOld =
1966             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1967         style.styleNew = newval;
1968         WIN_ReleasePtr( wndPtr );
1969         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1970         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1971         newval = style.styleNew;
1972         break;
1973     case GWLP_HWNDPARENT:
1974         if (wndPtr->parent == GetDesktopWindow())
1975         {
1976             WIN_ReleasePtr( wndPtr );
1977             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1978         }
1979         else
1980         {
1981             WIN_ReleasePtr( wndPtr );
1982             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1983         }
1984     case GWLP_WNDPROC:
1985     {
1986         UINT old_flags = wndPtr->flags;
1987         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1988         if (unicode) wndPtr->winproc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1989         else wndPtr->winproc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1990         if (WINPROC_IsUnicode( wndPtr->winproc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1991         else wndPtr->flags &= ~WIN_ISUNICODE;
1992         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1993         {
1994             WIN_ReleasePtr( wndPtr );
1995             return retval;
1996         }
1997         /* update is_unicode flag on the server side */
1998         break;
1999     }
2000     case GWLP_ID:
2001     case GWLP_HINSTANCE:
2002     case GWLP_USERDATA:
2003         break;
2004     case DWLP_DLGPROC:
2005         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2006         {
2007             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2008             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2009             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
2010             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
2011             WIN_ReleasePtr( wndPtr );
2012             return retval;
2013         }
2014         /* fall through */
2015     default:
2016         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG_PTR)))
2017         {
2018             WARN("Invalid offset %d\n", offset );
2019             WIN_ReleasePtr( wndPtr );
2020             SetLastError( ERROR_INVALID_INDEX );
2021             return 0;
2022         }
2023         else
2024         {
2025             LONG_PTR *ptr = (LONG_PTR *)((char *)wndPtr->wExtra + offset);
2026             if (*ptr == newval)  /* already set to the same value */
2027             {
2028                 WIN_ReleasePtr( wndPtr );
2029                 return newval;
2030             }
2031         }
2032         break;
2033     }
2034
2035     SERVER_START_REQ( set_window_info )
2036     {
2037         req->handle = hwnd;
2038         req->extra_offset = -1;
2039         switch(offset)
2040         {
2041         case GWL_STYLE:
2042             req->flags = SET_WIN_STYLE;
2043             req->style = newval;
2044             break;
2045         case GWL_EXSTYLE:
2046             req->flags = SET_WIN_EXSTYLE;
2047             req->ex_style = newval;
2048             break;
2049         case GWLP_ID:
2050             req->flags = SET_WIN_ID;
2051             req->id = newval;
2052             break;
2053         case GWLP_HINSTANCE:
2054             req->flags = SET_WIN_INSTANCE;
2055             req->instance = (void *)newval;
2056             break;
2057         case GWLP_WNDPROC:
2058             req->flags = SET_WIN_UNICODE;
2059             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2060             break;
2061         case GWLP_USERDATA:
2062             req->flags = SET_WIN_USERDATA;
2063             req->user_data = (void *)newval;
2064             break;
2065         default:
2066             req->flags = SET_WIN_EXTRA;
2067             req->extra_offset = offset;
2068             req->extra_size = sizeof(newval);
2069             memcpy( &req->extra_value, &newval, sizeof(newval) );
2070         }
2071         if ((ok = !wine_server_call_err( req )))
2072         {
2073             switch(offset)
2074             {
2075             case GWL_STYLE:
2076                 wndPtr->dwStyle = newval;
2077                 retval = reply->old_style;
2078                 break;
2079             case GWL_EXSTYLE:
2080                 wndPtr->dwExStyle = newval;
2081                 retval = reply->old_ex_style;
2082                 break;
2083             case GWLP_ID:
2084                 wndPtr->wIDmenu = newval;
2085                 retval = reply->old_id;
2086                 break;
2087             case GWLP_HINSTANCE:
2088                 wndPtr->hInstance = (HINSTANCE)newval;
2089                 retval = (ULONG_PTR)reply->old_instance;
2090                 break;
2091             case GWLP_WNDPROC:
2092                 break;
2093             case GWLP_USERDATA:
2094                 wndPtr->userdata = newval;
2095                 retval = (ULONG_PTR)reply->old_user_data;
2096                 break;
2097             default:
2098                 {
2099                     void *ptr = (char *)wndPtr->wExtra + offset;
2100                     memcpy( &retval, ptr, sizeof(retval) );
2101                     memcpy( ptr, &newval, sizeof(newval) );
2102                 }
2103                 break;
2104             }
2105         }
2106     }
2107     SERVER_END_REQ;
2108     WIN_ReleasePtr( wndPtr );
2109
2110     if (!ok) return 0;
2111
2112     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2113
2114     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2115         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2116
2117     return retval;
2118 }
2119
2120
2121 /**********************************************************************
2122  *              GetWindowLong (USER.135)
2123  */
2124 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2125 {
2126     WND *wndPtr;
2127     LONG_PTR retvalue;
2128     BOOL is_winproc = (offset == GWLP_WNDPROC);
2129
2130     if (offset >= 0)
2131     {
2132         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2133         {
2134             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2135             return 0;
2136         }
2137         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2138         {
2139             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2140             {
2141                 /*
2142                  * Some programs try to access last element from 16 bit
2143                  * code using illegal offset value. Hopefully this is
2144                  * what those programs really expect.
2145                  */
2146                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2147                 {
2148                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2149                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2150                     offset = offset2;
2151                 }
2152                 else
2153                 {
2154                     WARN("Invalid offset %d\n", offset );
2155                     WIN_ReleasePtr( wndPtr );
2156                     SetLastError( ERROR_INVALID_INDEX );
2157                     return 0;
2158                 }
2159             }
2160             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2161             WIN_ReleasePtr( wndPtr );
2162         }
2163     }
2164     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2165     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2166     return retvalue;
2167 }
2168
2169
2170 /**********************************************************************
2171  *              GetWindowLongA (USER32.@)
2172  */
2173 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2174 {
2175     return WIN_GetWindowLong( hwnd, offset, FALSE );
2176 }
2177
2178
2179 /**********************************************************************
2180  *              GetWindowLongW (USER32.@)
2181  */
2182 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2183 {
2184     return WIN_GetWindowLong( hwnd, offset, TRUE );
2185 }
2186
2187
2188 /**********************************************************************
2189  *              SetWindowLong (USER.136)
2190  */
2191 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2192 {
2193     WND *wndPtr;
2194     BOOL is_winproc = (offset == GWLP_WNDPROC);
2195
2196     if (offset == DWLP_DLGPROC)
2197     {
2198         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2199         {
2200             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2201             return 0;
2202         }
2203         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2204         {
2205             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2206                           (wndPtr->flags & WIN_ISDIALOG));
2207             WIN_ReleasePtr( wndPtr );
2208         }
2209     }
2210
2211     if (is_winproc)
2212     {
2213         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2214         WNDPROC old_proc = (WNDPROC)SetWindowLongA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2215         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2216     }
2217     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2218 }
2219
2220
2221 /**********************************************************************
2222  *              SetWindowLongA (USER32.@)
2223  *
2224  * See SetWindowLongW.
2225  */
2226 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2227 {
2228     return WIN_SetWindowLong( hwnd, offset, newval, FALSE );
2229 }
2230
2231
2232 /**********************************************************************
2233  *              SetWindowLongW (USER32.@) Set window attribute
2234  *
2235  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2236  * value in a window's extra memory.
2237  *
2238  * The _hwnd_ parameter specifies the window.  is the handle to a
2239  * window that has extra memory. The _newval_ parameter contains the
2240  * new attribute or extra memory value.  If positive, the _offset_
2241  * parameter is the byte-addressed location in the window's extra
2242  * memory to set.  If negative, _offset_ specifies the window
2243  * attribute to set, and should be one of the following values:
2244  *
2245  * GWL_EXSTYLE      The window's extended window style
2246  *
2247  * GWL_STYLE        The window's window style.
2248  *
2249  * GWLP_WNDPROC     Pointer to the window's window procedure.
2250  *
2251  * GWLP_HINSTANCE   The window's pplication instance handle.
2252  *
2253  * GWLP_ID          The window's identifier.
2254  *
2255  * GWLP_USERDATA    The window's user-specified data.
2256  *
2257  * If the window is a dialog box, the _offset_ parameter can be one of
2258  * the following values:
2259  *
2260  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2261  *
2262  * DWLP_MSGRESULT   The return value of a message
2263  *                  that the dialog box procedure processed.
2264  *
2265  * DWLP_USER        Application specific information.
2266  *
2267  * RETURNS
2268  *
2269  * If successful, returns the previous value located at _offset_. Otherwise,
2270  * returns 0.
2271  *
2272  * NOTES
2273  *
2274  * Extra memory for a window class is specified by a nonzero cbWndExtra
2275  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2276  * time of class creation.
2277  *
2278  * Using GWL_WNDPROC to set a new window procedure effectively creates
2279  * a window subclass. Use CallWindowProc() in the new windows procedure
2280  * to pass messages to the superclass's window procedure.
2281  *
2282  * The user data is reserved for use by the application which created
2283  * the window.
2284  *
2285  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2286  * instead, call the EnableWindow() function to change the window's
2287  * disabled state.
2288  *
2289  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2290  * SetParent() instead.
2291  *
2292  * Win95:
2293  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2294  * it sends WM_STYLECHANGING before changing the settings
2295  * and WM_STYLECHANGED afterwards.
2296  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2297  */
2298 LONG WINAPI SetWindowLongW(
2299     HWND hwnd,  /* [in] window to alter */
2300     INT offset, /* [in] offset, in bytes, of location to alter */
2301     LONG newval /* [in] new value of location */
2302 ) {
2303     return WIN_SetWindowLong( hwnd, offset, newval, TRUE );
2304 }
2305
2306
2307 /*******************************************************************
2308  *              GetWindowTextA (USER32.@)
2309  */
2310 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2311 {
2312     WCHAR *buffer;
2313
2314     if (!lpString) return 0;
2315
2316     if (WIN_IsCurrentProcess( hwnd ))
2317         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2318
2319     /* when window belongs to other process, don't send a message */
2320     if (nMaxCount <= 0) return 0;
2321     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2322     get_server_window_text( hwnd, buffer, nMaxCount );
2323     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2324         lpString[nMaxCount-1] = 0;
2325     HeapFree( GetProcessHeap(), 0, buffer );
2326     return strlen(lpString);
2327 }
2328
2329
2330 /*******************************************************************
2331  *              InternalGetWindowText (USER32.@)
2332  */
2333 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2334 {
2335     WND *win;
2336
2337     if (nMaxCount <= 0) return 0;
2338     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2339     if (win == WND_DESKTOP) lpString[0] = 0;
2340     else if (win != WND_OTHER_PROCESS)
2341     {
2342         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2343         else lpString[0] = 0;
2344         WIN_ReleasePtr( win );
2345     }
2346     else
2347     {
2348         get_server_window_text( hwnd, lpString, nMaxCount );
2349     }
2350     return strlenW(lpString);
2351 }
2352
2353
2354 /*******************************************************************
2355  *              GetWindowTextW (USER32.@)
2356  */
2357 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2358 {
2359     if (!lpString) return 0;
2360
2361     if (WIN_IsCurrentProcess( hwnd ))
2362         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2363
2364     /* when window belongs to other process, don't send a message */
2365     if (nMaxCount <= 0) return 0;
2366     get_server_window_text( hwnd, lpString, nMaxCount );
2367     return strlenW(lpString);
2368 }
2369
2370
2371 /*******************************************************************
2372  *              SetWindowTextA (USER32.@)
2373  *              SetWindowText  (USER32.@)
2374  */
2375 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2376 {
2377     if (is_broadcast(hwnd))
2378     {
2379         SetLastError( ERROR_INVALID_PARAMETER );
2380         return FALSE;
2381     }
2382     if (!WIN_IsCurrentProcess( hwnd ))
2383         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2384                debugstr_a(lpString), hwnd );
2385     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2386 }
2387
2388
2389 /*******************************************************************
2390  *              SetWindowTextW (USER32.@)
2391  */
2392 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2393 {
2394     if (is_broadcast(hwnd))
2395     {
2396         SetLastError( ERROR_INVALID_PARAMETER );
2397         return FALSE;
2398     }
2399     if (!WIN_IsCurrentProcess( hwnd ))
2400         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2401                debugstr_w(lpString), hwnd );
2402     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2403 }
2404
2405
2406 /*******************************************************************
2407  *              GetWindowTextLengthA (USER32.@)
2408  */
2409 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2410 {
2411     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2412 }
2413
2414 /*******************************************************************
2415  *              GetWindowTextLengthW (USER32.@)
2416  */
2417 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2418 {
2419     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2420 }
2421
2422
2423 /*******************************************************************
2424  *              IsWindow (USER32.@)
2425  */
2426 BOOL WINAPI IsWindow( HWND hwnd )
2427 {
2428     WND *ptr;
2429     BOOL ret;
2430
2431     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2432     if (ptr == WND_DESKTOP) return TRUE;
2433
2434     if (ptr != WND_OTHER_PROCESS)
2435     {
2436         WIN_ReleasePtr( ptr );
2437         return TRUE;
2438     }
2439
2440     /* check other processes */
2441     SERVER_START_REQ( get_window_info )
2442     {
2443         req->handle = hwnd;
2444         ret = !wine_server_call_err( req );
2445     }
2446     SERVER_END_REQ;
2447     return ret;
2448 }
2449
2450
2451 /***********************************************************************
2452  *              GetWindowThreadProcessId (USER32.@)
2453  */
2454 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2455 {
2456     WND *ptr;
2457     DWORD tid = 0;
2458
2459     if (!(ptr = WIN_GetPtr( hwnd )))
2460     {
2461         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2462         return 0;
2463     }
2464
2465     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2466     {
2467         /* got a valid window */
2468         tid = ptr->tid;
2469         if (process) *process = GetCurrentProcessId();
2470         WIN_ReleasePtr( ptr );
2471         return tid;
2472     }
2473
2474     /* check other processes */
2475     SERVER_START_REQ( get_window_info )
2476     {
2477         req->handle = hwnd;
2478         if (!wine_server_call_err( req ))
2479         {
2480             tid = (DWORD)reply->tid;
2481             if (process) *process = (DWORD)reply->pid;
2482         }
2483     }
2484     SERVER_END_REQ;
2485     return tid;
2486 }
2487
2488
2489 /*****************************************************************
2490  *              GetParent (USER32.@)
2491  */
2492 HWND WINAPI GetParent( HWND hwnd )
2493 {
2494     WND *wndPtr;
2495     HWND retvalue = 0;
2496
2497     if (!(wndPtr = WIN_GetPtr( hwnd )))
2498     {
2499         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2500         return 0;
2501     }
2502     if (wndPtr == WND_DESKTOP) return 0;
2503     if (wndPtr == WND_OTHER_PROCESS)
2504     {
2505         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2506         if (style & (WS_POPUP | WS_CHILD))
2507         {
2508             SERVER_START_REQ( get_window_tree )
2509             {
2510                 req->handle = hwnd;
2511                 if (!wine_server_call_err( req ))
2512                 {
2513                     if (style & WS_POPUP) retvalue = reply->owner;
2514                     else if (style & WS_CHILD) retvalue = reply->parent;
2515                 }
2516             }
2517             SERVER_END_REQ;
2518         }
2519     }
2520     else
2521     {
2522         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2523         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2524         WIN_ReleasePtr( wndPtr );
2525     }
2526     return retvalue;
2527 }
2528
2529
2530 /*****************************************************************
2531  *              GetAncestor (USER32.@)
2532  */
2533 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2534 {
2535     WND *win;
2536     HWND *list, ret = 0;
2537
2538     switch(type)
2539     {
2540     case GA_PARENT:
2541         if (!(win = WIN_GetPtr( hwnd )))
2542         {
2543             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2544             return 0;
2545         }
2546         if (win == WND_DESKTOP) return 0;
2547         if (win != WND_OTHER_PROCESS)
2548         {
2549             ret = win->parent;
2550             WIN_ReleasePtr( win );
2551         }
2552         else /* need to query the server */
2553         {
2554             SERVER_START_REQ( get_window_tree )
2555             {
2556                 req->handle = hwnd;
2557                 if (!wine_server_call_err( req )) ret = reply->parent;
2558             }
2559             SERVER_END_REQ;
2560         }
2561         break;
2562
2563     case GA_ROOT:
2564         if (!(list = list_window_parents( hwnd ))) return 0;
2565
2566         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2567         else
2568         {
2569             int count = 2;
2570             while (list[count]) count++;
2571             ret = list[count - 2];  /* get the one before the desktop */
2572         }
2573         HeapFree( GetProcessHeap(), 0, list );
2574         break;
2575
2576     case GA_ROOTOWNER:
2577         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2578         for (;;)
2579         {
2580             HWND parent = GetParent( ret );
2581             if (!parent) break;
2582             ret = parent;
2583         }
2584         break;
2585     }
2586     return ret;
2587 }
2588
2589
2590 /*****************************************************************
2591  *              SetParent (USER32.@)
2592  */
2593 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2594 {
2595     HWND full_handle;
2596
2597     if (is_broadcast(hwnd) || is_broadcast(parent))
2598     {
2599         SetLastError(ERROR_INVALID_PARAMETER);
2600         return 0;
2601     }
2602
2603     if (!parent) parent = GetDesktopWindow();
2604     else parent = WIN_GetFullHandle( parent );
2605
2606     if (!IsWindow( parent ))
2607     {
2608         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2609         return 0;
2610     }
2611
2612     /* Some applications try to set a child as a parent */
2613     if (IsChild(hwnd, parent))
2614     {
2615         SetLastError( ERROR_INVALID_PARAMETER );
2616         return 0;
2617     }
2618
2619     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2620         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2621
2622     return USER_Driver->pSetParent( full_handle, parent );
2623 }
2624
2625
2626 /*******************************************************************
2627  *              IsChild (USER32.@)
2628  */
2629 BOOL WINAPI IsChild( HWND parent, HWND child )
2630 {
2631     HWND *list = list_window_parents( child );
2632     int i;
2633     BOOL ret;
2634
2635     if (!list) return FALSE;
2636     parent = WIN_GetFullHandle( parent );
2637     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2638     ret = (list[i] != 0);
2639     HeapFree( GetProcessHeap(), 0, list );
2640     return ret;
2641 }
2642
2643
2644 /***********************************************************************
2645  *              IsWindowVisible (USER32.@)
2646  */
2647 BOOL WINAPI IsWindowVisible( HWND hwnd )
2648 {
2649     HWND *list;
2650     BOOL retval;
2651     int i;
2652
2653     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2654     if (!(list = list_window_parents( hwnd ))) return TRUE;
2655     for (i = 0; list[i]; i++)
2656         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2657     retval = !list[i];
2658     HeapFree( GetProcessHeap(), 0, list );
2659     return retval;
2660 }
2661
2662
2663 /***********************************************************************
2664  *           WIN_IsWindowDrawable
2665  *
2666  * hwnd is drawable when it is visible, all parents are not
2667  * minimized, and it is itself not minimized unless we are
2668  * trying to draw its default class icon.
2669  */
2670 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2671 {
2672     HWND *list;
2673     BOOL retval;
2674     int i;
2675     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2676
2677     if (!(style & WS_VISIBLE)) return FALSE;
2678     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2679
2680     if (!(list = list_window_parents( hwnd ))) return TRUE;
2681     for (i = 0; list[i]; i++)
2682         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2683             break;
2684     retval = !list[i];
2685     HeapFree( GetProcessHeap(), 0, list );
2686     return retval;
2687 }
2688
2689
2690 /*******************************************************************
2691  *              GetTopWindow (USER32.@)
2692  */
2693 HWND WINAPI GetTopWindow( HWND hwnd )
2694 {
2695     if (!hwnd) hwnd = GetDesktopWindow();
2696     return GetWindow( hwnd, GW_CHILD );
2697 }
2698
2699
2700 /*******************************************************************
2701  *              GetWindow (USER32.@)
2702  */
2703 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2704 {
2705     HWND retval = 0;
2706
2707     if (rel == GW_OWNER)  /* this one may be available locally */
2708     {
2709         WND *wndPtr = WIN_GetPtr( hwnd );
2710         if (!wndPtr)
2711         {
2712             SetLastError( ERROR_INVALID_HANDLE );
2713             return 0;
2714         }
2715         if (wndPtr == WND_DESKTOP) return 0;
2716         if (wndPtr != WND_OTHER_PROCESS)
2717         {
2718             retval = wndPtr->owner;
2719             WIN_ReleasePtr( wndPtr );
2720             return retval;
2721         }
2722         /* else fall through to server call */
2723     }
2724
2725     SERVER_START_REQ( get_window_tree )
2726     {
2727         req->handle = hwnd;
2728         if (!wine_server_call_err( req ))
2729         {
2730             switch(rel)
2731             {
2732             case GW_HWNDFIRST:
2733                 retval = reply->first_sibling;
2734                 break;
2735             case GW_HWNDLAST:
2736                 retval = reply->last_sibling;
2737                 break;
2738             case GW_HWNDNEXT:
2739                 retval = reply->next_sibling;
2740                 break;
2741             case GW_HWNDPREV:
2742                 retval = reply->prev_sibling;
2743                 break;
2744             case GW_OWNER:
2745                 retval = reply->owner;
2746                 break;
2747             case GW_CHILD:
2748                 retval = reply->first_child;
2749                 break;
2750             }
2751         }
2752     }
2753     SERVER_END_REQ;
2754     return retval;
2755 }
2756
2757
2758 /*******************************************************************
2759  *              ShowOwnedPopups (USER32.@)
2760  */
2761 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2762 {
2763     int count = 0;
2764     WND *pWnd;
2765     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2766
2767     if (!win_array) return TRUE;
2768
2769     while (win_array[count]) count++;
2770     while (--count >= 0)
2771     {
2772         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2773         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2774         if (pWnd == WND_OTHER_PROCESS) continue;
2775         if (fShow)
2776         {
2777             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2778             {
2779                 WIN_ReleasePtr( pWnd );
2780                 /* In Windows, ShowOwnedPopups(TRUE) generates
2781                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2782                  * regardless of the state of the owner
2783                  */
2784                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2785                 continue;
2786             }
2787         }
2788         else
2789         {
2790             if (pWnd->dwStyle & WS_VISIBLE)
2791             {
2792                 WIN_ReleasePtr( pWnd );
2793                 /* In Windows, ShowOwnedPopups(FALSE) generates
2794                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2795                  * regardless of the state of the owner
2796                  */
2797                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2798                 continue;
2799             }
2800         }
2801         WIN_ReleasePtr( pWnd );
2802     }
2803     HeapFree( GetProcessHeap(), 0, win_array );
2804     return TRUE;
2805 }
2806
2807
2808 /*******************************************************************
2809  *              GetLastActivePopup (USER32.@)
2810  */
2811 HWND WINAPI GetLastActivePopup( HWND hwnd )
2812 {
2813     HWND retval = hwnd;
2814
2815     SERVER_START_REQ( get_window_info )
2816     {
2817         req->handle = hwnd;
2818         if (!wine_server_call_err( req )) retval = reply->last_active;
2819     }
2820     SERVER_END_REQ;
2821     return retval;
2822 }
2823
2824
2825 /*******************************************************************
2826  *           WIN_ListChildren
2827  *
2828  * Build an array of the children of a given window. The array must be
2829  * freed with HeapFree. Returns NULL when no windows are found.
2830  */
2831 HWND *WIN_ListChildren( HWND hwnd )
2832 {
2833     return list_window_children( hwnd, 0, 0 );
2834 }
2835
2836
2837 /*******************************************************************
2838  *              EnumWindows (USER32.@)
2839  */
2840 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2841 {
2842     HWND *list;
2843     BOOL ret = TRUE;
2844     int i;
2845
2846     USER_CheckNotLock();
2847
2848     /* We have to build a list of all windows first, to avoid */
2849     /* unpleasant side-effects, for instance if the callback */
2850     /* function changes the Z-order of the windows.          */
2851
2852     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2853
2854     /* Now call the callback function for every window */
2855
2856     for (i = 0; list[i]; i++)
2857     {
2858         /* Make sure that the window still exists */
2859         if (!IsWindow( list[i] )) continue;
2860         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2861     }
2862     HeapFree( GetProcessHeap(), 0, list );
2863     return ret;
2864 }
2865
2866
2867 /**********************************************************************
2868  *              EnumThreadWindows (USER32.@)
2869  */
2870 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2871 {
2872     HWND *list;
2873     int i;
2874
2875     USER_CheckNotLock();
2876
2877     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2878
2879     /* Now call the callback function for every window */
2880
2881     for (i = 0; list[i]; i++)
2882         if (!func( list[i], lParam )) break;
2883     HeapFree( GetProcessHeap(), 0, list );
2884     return TRUE;
2885 }
2886
2887
2888 /**********************************************************************
2889  *           WIN_EnumChildWindows
2890  *
2891  * Helper function for EnumChildWindows().
2892  */
2893 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2894 {
2895     HWND *childList;
2896     BOOL ret = FALSE;
2897
2898     for ( ; *list; list++)
2899     {
2900         /* Make sure that the window still exists */
2901         if (!IsWindow( *list )) continue;
2902         /* Build children list first */
2903         childList = WIN_ListChildren( *list );
2904
2905         ret = func( *list, lParam );
2906
2907         if (childList)
2908         {
2909             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2910             HeapFree( GetProcessHeap(), 0, childList );
2911         }
2912         if (!ret) return FALSE;
2913     }
2914     return TRUE;
2915 }
2916
2917
2918 /**********************************************************************
2919  *              EnumChildWindows (USER32.@)
2920  */
2921 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2922 {
2923     HWND *list;
2924     BOOL ret;
2925
2926     USER_CheckNotLock();
2927
2928     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2929     ret = WIN_EnumChildWindows( list, func, lParam );
2930     HeapFree( GetProcessHeap(), 0, list );
2931     return ret;
2932 }
2933
2934
2935 /*******************************************************************
2936  *              AnyPopup (USER.52)
2937  */
2938 BOOL16 WINAPI AnyPopup16(void)
2939 {
2940     return AnyPopup();
2941 }
2942
2943
2944 /*******************************************************************
2945  *              AnyPopup (USER32.@)
2946  */
2947 BOOL WINAPI AnyPopup(void)
2948 {
2949     int i;
2950     BOOL retvalue;
2951     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2952
2953     if (!list) return FALSE;
2954     for (i = 0; list[i]; i++)
2955     {
2956         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2957     }
2958     retvalue = (list[i] != 0);
2959     HeapFree( GetProcessHeap(), 0, list );
2960     return retvalue;
2961 }
2962
2963
2964 /*******************************************************************
2965  *              FlashWindow (USER32.@)
2966  */
2967 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2968 {
2969     WND *wndPtr;
2970
2971     TRACE("%p\n", hWnd);
2972
2973     if (IsIconic( hWnd ))
2974     {
2975         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2976
2977         wndPtr = WIN_GetPtr(hWnd);
2978         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2979         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2980         {
2981             wndPtr->flags |= WIN_NCACTIVATED;
2982         }
2983         else
2984         {
2985             wndPtr->flags &= ~WIN_NCACTIVATED;
2986         }
2987         WIN_ReleasePtr( wndPtr );
2988         return TRUE;
2989     }
2990     else
2991     {
2992         WPARAM wparam;
2993
2994         wndPtr = WIN_GetPtr(hWnd);
2995         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2996         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2997
2998         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2999         else wparam = (hWnd == GetForegroundWindow());
3000
3001         WIN_ReleasePtr( wndPtr );
3002         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3003         return wparam;
3004     }
3005 }
3006
3007 /*******************************************************************
3008  *              FlashWindowEx (USER32.@)
3009  */
3010 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3011 {
3012     FIXME("%p\n", pfwi);
3013     return TRUE;
3014 }
3015
3016 /*******************************************************************
3017  *              GetWindowContextHelpId (USER32.@)
3018  */
3019 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3020 {
3021     DWORD retval;
3022     WND *wnd = WIN_GetPtr( hwnd );
3023     if (!wnd || wnd == WND_DESKTOP) return 0;
3024     if (wnd == WND_OTHER_PROCESS)
3025     {
3026         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3027         return 0;
3028     }
3029     retval = wnd->helpContext;
3030     WIN_ReleasePtr( wnd );
3031     return retval;
3032 }
3033
3034
3035 /*******************************************************************
3036  *              SetWindowContextHelpId (USER32.@)
3037  */
3038 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3039 {
3040     WND *wnd = WIN_GetPtr( hwnd );
3041     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3042     if (wnd == WND_OTHER_PROCESS)
3043     {
3044         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3045         return 0;
3046     }
3047     wnd->helpContext = id;
3048     WIN_ReleasePtr( wnd );
3049     return TRUE;
3050 }
3051
3052
3053 /*******************************************************************
3054  *              DragDetect (USER32.@)
3055  */
3056 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3057 {
3058     MSG msg;
3059     RECT rect;
3060     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3061     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3062
3063     rect.left = pt.x - wDragWidth;
3064     rect.right = pt.x + wDragWidth;
3065
3066     rect.top = pt.y - wDragHeight;
3067     rect.bottom = pt.y + wDragHeight;
3068
3069     SetCapture(hWnd);
3070
3071     while(1)
3072     {
3073         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3074         {
3075             if( msg.message == WM_LBUTTONUP )
3076             {
3077                 ReleaseCapture();
3078                 return 0;
3079             }
3080             if( msg.message == WM_MOUSEMOVE )
3081             {
3082                 POINT tmp;
3083                 tmp.x = LOWORD(msg.lParam);
3084                 tmp.y = HIWORD(msg.lParam);
3085                 if( !PtInRect( &rect, tmp ))
3086                 {
3087                     ReleaseCapture();
3088                     return 1;
3089                 }
3090             }
3091         }
3092         WaitMessage();
3093     }
3094     return 0;
3095 }
3096
3097 /******************************************************************************
3098  *              GetWindowModuleFileNameA (USER32.@)
3099  */
3100 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3101 {
3102     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3103           hwnd, lpszFileName, cchFileNameMax);
3104     return 0;
3105 }
3106
3107 /******************************************************************************
3108  *              GetWindowModuleFileNameW (USER32.@)
3109  */
3110 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3111 {
3112     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3113           hwnd, lpszFileName, cchFileNameMax);
3114     return 0;
3115 }
3116
3117 /******************************************************************************
3118  *              GetWindowInfo (USER32.@)
3119  *
3120  * Note: tests show that Windows doesn't check cbSize of the structure.
3121  */
3122 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3123 {
3124     if (!pwi) return FALSE;
3125     if (!IsWindow(hwnd)) return FALSE;
3126
3127     GetWindowRect(hwnd, &pwi->rcWindow);
3128     GetClientRect(hwnd, &pwi->rcClient);
3129     /* translate to screen coordinates */
3130     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3131
3132     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3133     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3134     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3135
3136     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3137     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3138
3139     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3140     pwi->wCreatorVersion = 0x0400;
3141
3142     return TRUE;
3143 }
3144
3145 /******************************************************************************
3146  *              SwitchDesktop (USER32.@)
3147  *
3148  * NOTES: Sets the current input or interactive desktop.
3149  */
3150 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3151 {
3152     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3153     return TRUE;
3154 }
3155
3156 /*****************************************************************************
3157  *              SetLayeredWindowAttributes (USER32.@)
3158  */
3159 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3160                                         BYTE bAlpha, DWORD dwFlags )
3161 {
3162     FIXME("(%p,0x%.8lx,%d,%ld): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3163     return TRUE;
3164 }
3165
3166 /*****************************************************************************
3167  *              UpdateLayeredWindow (USER32.@)
3168  */
3169 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3170                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3171                                  DWORD dwFlags)
3172 {
3173     FIXME("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%ld): stub!\n",
3174           hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3175     return 0;
3176 }
3177
3178 /* 64bit versions */
3179
3180 #ifdef GetWindowLongPtrW
3181 #undef GetWindowLongPtrW
3182 #endif
3183
3184 #ifdef GetWindowLongPtrA
3185 #undef GetWindowLongPtrA
3186 #endif
3187
3188 #ifdef SetWindowLongPtrW
3189 #undef SetWindowLongPtrW
3190 #endif
3191
3192 #ifdef SetWindowLongPtrA
3193 #undef SetWindowLongPtrA
3194 #endif
3195
3196 /*****************************************************************************
3197  *              GetWindowLongPtrW (USER32.@)
3198  */
3199 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3200 {
3201     FIXME("\n");
3202     return 0;
3203 }
3204
3205 /*****************************************************************************
3206  *              GetWindowLongPtrA (USER32.@)
3207  */
3208 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3209 {
3210     FIXME("\n");
3211     return 0;
3212 }
3213
3214 /*****************************************************************************
3215  *              SetWindowLongPtrW (USER32.@)
3216  */
3217 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3218 {
3219     FIXME("\n");
3220     return 0;
3221 }
3222
3223 /*****************************************************************************
3224  *              SetWindowLongPtrA (USER32.@)
3225  */
3226 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3227 {
3228     FIXME("\n");
3229     return 0;
3230 }