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