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