msi: Write-strings warnings fix.
[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 %ld 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 %lx/%lx 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=%08lx style=%08lx %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         STARTUPINFOW si;
1617         PROCESS_INFORMATION pi;
1618         WCHAR command_line[] = {'e','x','p','l','o','r','e','r','.','e','x','e',' ','/','d','e','s','k','t','o','p',0};
1619
1620         memset( &si, 0, sizeof(si) );
1621         si.cb = sizeof(si);
1622         if (CreateProcessW( NULL, command_line, NULL, NULL, FALSE, DETACHED_PROCESS,
1623                             NULL, NULL, &si, &pi ))
1624         {
1625             TRACE( "started explorer pid %04lx tid %04lx\n", pi.dwProcessId, pi.dwThreadId );
1626             WaitForInputIdle( pi.hProcess, 10000 );
1627             CloseHandle( pi.hThread );
1628             CloseHandle( pi.hProcess );
1629
1630         }
1631         else WARN( "failed to start explorer, err %ld\n", GetLastError() );
1632
1633         SERVER_START_REQ( get_desktop_window )
1634         {
1635             req->force = 1;
1636             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1637         }
1638         SERVER_END_REQ;
1639     }
1640
1641     if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1642         ERR( "failed to create desktop window\n" );
1643
1644     return thread_info->desktop;
1645 }
1646
1647
1648 /*******************************************************************
1649  *              EnableWindow (USER32.@)
1650  */
1651 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1652 {
1653     BOOL retvalue;
1654     HWND full_handle;
1655
1656     if (is_broadcast(hwnd))
1657     {
1658         SetLastError( ERROR_INVALID_PARAMETER );
1659         return FALSE;
1660     }
1661
1662     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1663         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1664
1665     hwnd = full_handle;
1666
1667     TRACE("( %p, %d )\n", hwnd, enable);
1668
1669     retvalue = !IsWindowEnabled( hwnd );
1670
1671     if (enable && retvalue)
1672     {
1673         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1674         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1675     }
1676     else if (!enable && !retvalue)
1677     {
1678         HWND capture_wnd;
1679
1680         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1681
1682         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1683
1684         if (hwnd == GetFocus())
1685             SetFocus( 0 );  /* A disabled window can't have the focus */
1686
1687         capture_wnd = GetCapture();
1688         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1689             ReleaseCapture();  /* A disabled window can't capture the mouse */
1690
1691         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1692     }
1693     return retvalue;
1694 }
1695
1696
1697 /***********************************************************************
1698  *              IsWindowEnabled (USER32.@)
1699  */
1700 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1701 {
1702     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1703 }
1704
1705
1706 /***********************************************************************
1707  *              IsWindowUnicode (USER32.@)
1708  */
1709 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1710 {
1711     WND * wndPtr;
1712     BOOL retvalue = FALSE;
1713
1714     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1715
1716     if (wndPtr == WND_DESKTOP) return TRUE;
1717
1718     if (wndPtr != WND_OTHER_PROCESS)
1719     {
1720         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
1721         WIN_ReleasePtr( wndPtr );
1722     }
1723     else
1724     {
1725         SERVER_START_REQ( get_window_info )
1726         {
1727             req->handle = hwnd;
1728             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1729         }
1730         SERVER_END_REQ;
1731     }
1732     return retvalue;
1733 }
1734
1735
1736 /**********************************************************************
1737  *           WIN_GetWindowLong
1738  *
1739  * Helper function for GetWindowLong().
1740  */
1741 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1742 {
1743     LONG_PTR retvalue = 0;
1744     WND *wndPtr;
1745
1746     if (offset == GWLP_HWNDPARENT)
1747     {
1748         HWND parent = GetAncestor( hwnd, GA_PARENT );
1749         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1750         return (ULONG_PTR)parent;
1751     }
1752
1753     if (!(wndPtr = WIN_GetPtr( hwnd )))
1754     {
1755         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1756         return 0;
1757     }
1758
1759     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1760     {
1761         if (offset == GWLP_WNDPROC)
1762         {
1763             SetLastError( ERROR_ACCESS_DENIED );
1764             return 0;
1765         }
1766         SERVER_START_REQ( set_window_info )
1767         {
1768             req->handle = hwnd;
1769             req->flags  = 0;  /* don't set anything, just retrieve */
1770             req->extra_offset = (offset >= 0) ? offset : -1;
1771             req->extra_size = (offset >= 0) ? size : 0;
1772             if (!wine_server_call_err( req ))
1773             {
1774                 switch(offset)
1775                 {
1776                 case GWL_STYLE:      retvalue = reply->old_style; break;
1777                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1778                 case GWLP_ID:        retvalue = reply->old_id; break;
1779                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1780                 case GWLP_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1781                 default:
1782                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
1783                     else SetLastError( ERROR_INVALID_INDEX );
1784                     break;
1785                 }
1786             }
1787         }
1788         SERVER_END_REQ;
1789         return retvalue;
1790     }
1791
1792     /* now we have a valid wndPtr */
1793
1794     if (offset >= 0)
1795     {
1796         if (offset > (int)(wndPtr->cbWndExtra - size))
1797         {
1798             WARN("Invalid offset %d\n", offset );
1799             WIN_ReleasePtr( wndPtr );
1800             SetLastError( ERROR_INVALID_INDEX );
1801             return 0;
1802         }
1803         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
1804
1805         /* Special case for dialog window procedure */
1806         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1807             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
1808         WIN_ReleasePtr( wndPtr );
1809         return retvalue;
1810     }
1811
1812     switch(offset)
1813     {
1814     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1815     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1816     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1817     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1818     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break;
1819     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1820     default:
1821         WARN("Unknown offset %d\n", offset );
1822         SetLastError( ERROR_INVALID_INDEX );
1823         break;
1824     }
1825     WIN_ReleasePtr(wndPtr);
1826     return retvalue;
1827 }
1828
1829
1830 /**********************************************************************
1831  *           WIN_SetWindowLong
1832  *
1833  * Helper function for SetWindowLong().
1834  *
1835  * 0 is the failure code. However, in the case of failure SetLastError
1836  * must be set to distinguish between a 0 return value and a failure.
1837  */
1838 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
1839 {
1840     STYLESTRUCT style;
1841     BOOL ok;
1842     LONG_PTR retval = 0;
1843     WND *wndPtr;
1844
1845     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
1846
1847     if (is_broadcast(hwnd))
1848     {
1849         SetLastError( ERROR_INVALID_PARAMETER );
1850         return FALSE;
1851     }
1852
1853     if (!(wndPtr = WIN_GetPtr( hwnd )))
1854     {
1855         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1856         return 0;
1857     }
1858     if (wndPtr == WND_DESKTOP)
1859     {
1860         /* can't change anything on the desktop window */
1861         SetLastError( ERROR_ACCESS_DENIED );
1862         return 0;
1863     }
1864     if (wndPtr == WND_OTHER_PROCESS)
1865     {
1866         if (offset == GWLP_WNDPROC)
1867         {
1868             SetLastError( ERROR_ACCESS_DENIED );
1869             return 0;
1870         }
1871         if (offset > 32767 || offset < -32767)
1872         {
1873             SetLastError( ERROR_INVALID_INDEX );
1874             return 0;
1875         }
1876         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
1877     }
1878
1879     /* first some special cases */
1880     switch( offset )
1881     {
1882     case GWL_STYLE:
1883     case GWL_EXSTYLE:
1884         style.styleOld =
1885             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1886         style.styleNew = newval;
1887         WIN_ReleasePtr( wndPtr );
1888         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1889         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1890         newval = style.styleNew;
1891         break;
1892     case GWLP_HWNDPARENT:
1893         if (wndPtr->parent == GetDesktopWindow())
1894         {
1895             WIN_ReleasePtr( wndPtr );
1896             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1897         }
1898         else
1899         {
1900             WIN_ReleasePtr( wndPtr );
1901             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1902         }
1903     case GWLP_WNDPROC:
1904     {
1905         WNDPROC proc;
1906         UINT old_flags = wndPtr->flags;
1907         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
1908         if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1909         else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1910         if (proc) wndPtr->winproc = proc;
1911         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
1912         else wndPtr->flags &= ~WIN_ISUNICODE;
1913         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
1914         {
1915             WIN_ReleasePtr( wndPtr );
1916             return retval;
1917         }
1918         /* update is_unicode flag on the server side */
1919         break;
1920     }
1921     case GWLP_ID:
1922     case GWLP_HINSTANCE:
1923     case GWLP_USERDATA:
1924         break;
1925     case DWLP_DLGPROC:
1926         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
1927             (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1928         {
1929             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1930             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
1931             if (unicode) *ptr = WINPROC_AllocProc( NULL, (WNDPROC)newval );
1932             else *ptr = WINPROC_AllocProc( (WNDPROC)newval, NULL );
1933             WIN_ReleasePtr( wndPtr );
1934             return retval;
1935         }
1936         /* fall through */
1937     default:
1938         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
1939         {
1940             WARN("Invalid offset %d\n", offset );
1941             WIN_ReleasePtr( wndPtr );
1942             SetLastError( ERROR_INVALID_INDEX );
1943             return 0;
1944         }
1945         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
1946         {
1947             /* already set to the same value */
1948             WIN_ReleasePtr( wndPtr );
1949             return newval;
1950         }
1951         break;
1952     }
1953
1954     SERVER_START_REQ( set_window_info )
1955     {
1956         req->handle = hwnd;
1957         req->extra_offset = -1;
1958         switch(offset)
1959         {
1960         case GWL_STYLE:
1961             req->flags = SET_WIN_STYLE;
1962             req->style = newval;
1963             break;
1964         case GWL_EXSTYLE:
1965             req->flags = SET_WIN_EXSTYLE;
1966             req->ex_style = newval;
1967             break;
1968         case GWLP_ID:
1969             req->flags = SET_WIN_ID;
1970             req->id = newval;
1971             break;
1972         case GWLP_HINSTANCE:
1973             req->flags = SET_WIN_INSTANCE;
1974             req->instance = (void *)newval;
1975             break;
1976         case GWLP_WNDPROC:
1977             req->flags = SET_WIN_UNICODE;
1978             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1979             break;
1980         case GWLP_USERDATA:
1981             req->flags = SET_WIN_USERDATA;
1982             req->user_data = (void *)newval;
1983             break;
1984         default:
1985             req->flags = SET_WIN_EXTRA;
1986             req->extra_offset = offset;
1987             req->extra_size = size;
1988             set_win_data( &req->extra_value, newval, size );
1989         }
1990         if ((ok = !wine_server_call_err( req )))
1991         {
1992             switch(offset)
1993             {
1994             case GWL_STYLE:
1995                 wndPtr->dwStyle = newval;
1996                 retval = reply->old_style;
1997                 break;
1998             case GWL_EXSTYLE:
1999                 wndPtr->dwExStyle = newval;
2000                 retval = reply->old_ex_style;
2001                 break;
2002             case GWLP_ID:
2003                 wndPtr->wIDmenu = newval;
2004                 retval = reply->old_id;
2005                 break;
2006             case GWLP_HINSTANCE:
2007                 wndPtr->hInstance = (HINSTANCE)newval;
2008                 retval = (ULONG_PTR)reply->old_instance;
2009                 break;
2010             case GWLP_WNDPROC:
2011                 break;
2012             case GWLP_USERDATA:
2013                 wndPtr->userdata = newval;
2014                 retval = (ULONG_PTR)reply->old_user_data;
2015                 break;
2016             default:
2017                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2018                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2019                 break;
2020             }
2021         }
2022     }
2023     SERVER_END_REQ;
2024     WIN_ReleasePtr( wndPtr );
2025
2026     if (!ok) return 0;
2027
2028     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2029
2030     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2031         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2032
2033     return retval;
2034 }
2035
2036
2037 /**********************************************************************
2038  *              GetWindowLong (USER.135)
2039  */
2040 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2041 {
2042     WND *wndPtr;
2043     LONG_PTR retvalue;
2044     BOOL is_winproc = (offset == GWLP_WNDPROC);
2045
2046     if (offset >= 0)
2047     {
2048         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2049         {
2050             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2051             return 0;
2052         }
2053         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2054         {
2055             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2056             {
2057                 /*
2058                  * Some programs try to access last element from 16 bit
2059                  * code using illegal offset value. Hopefully this is
2060                  * what those programs really expect.
2061                  */
2062                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2063                 {
2064                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2065                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2066                     offset = offset2;
2067                 }
2068                 else
2069                 {
2070                     WARN("Invalid offset %d\n", offset );
2071                     WIN_ReleasePtr( wndPtr );
2072                     SetLastError( ERROR_INVALID_INDEX );
2073                     return 0;
2074                 }
2075             }
2076             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2077             WIN_ReleasePtr( wndPtr );
2078         }
2079     }
2080     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2081     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2082     return retvalue;
2083 }
2084
2085
2086 /**********************************************************************
2087  *              GetWindowWord (USER32.@)
2088  */
2089 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2090 {
2091     switch(offset)
2092     {
2093     case GWLP_ID:
2094     case GWLP_HINSTANCE:
2095     case GWLP_HWNDPARENT:
2096         break;
2097     default:
2098         if (offset < 0)
2099         {
2100             WARN("Invalid offset %d\n", offset );
2101             SetLastError( ERROR_INVALID_INDEX );
2102             return 0;
2103         }
2104         break;
2105     }
2106     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2107 }
2108
2109
2110 /**********************************************************************
2111  *              GetWindowLongA (USER32.@)
2112  */
2113 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2114 {
2115     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2116 }
2117
2118
2119 /**********************************************************************
2120  *              GetWindowLongW (USER32.@)
2121  */
2122 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2123 {
2124     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2125 }
2126
2127
2128 /**********************************************************************
2129  *              SetWindowLong (USER.136)
2130  */
2131 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2132 {
2133     WND *wndPtr;
2134     BOOL is_winproc = (offset == GWLP_WNDPROC);
2135
2136     if (offset == DWLP_DLGPROC)
2137     {
2138         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2139         {
2140             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2141             return 0;
2142         }
2143         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2144         {
2145             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2146                           (wndPtr->flags & WIN_ISDIALOG));
2147             WIN_ReleasePtr( wndPtr );
2148         }
2149     }
2150
2151     if (is_winproc)
2152     {
2153         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2154         WNDPROC old_proc = (WNDPROC)SetWindowLongA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2155         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2156     }
2157     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2158 }
2159
2160
2161 /**********************************************************************
2162  *              SetWindowWord (USER32.@)
2163  */
2164 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2165 {
2166     switch(offset)
2167     {
2168     case GWLP_ID:
2169     case GWLP_HINSTANCE:
2170     case GWLP_HWNDPARENT:
2171         break;
2172     default:
2173         if (offset < 0)
2174         {
2175             WARN("Invalid offset %d\n", offset );
2176             SetLastError( ERROR_INVALID_INDEX );
2177             return 0;
2178         }
2179         break;
2180     }
2181     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2182 }
2183
2184
2185 /**********************************************************************
2186  *              SetWindowLongA (USER32.@)
2187  *
2188  * See SetWindowLongW.
2189  */
2190 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2191 {
2192     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2193 }
2194
2195
2196 /**********************************************************************
2197  *              SetWindowLongW (USER32.@) Set window attribute
2198  *
2199  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2200  * value in a window's extra memory.
2201  *
2202  * The _hwnd_ parameter specifies the window.  is the handle to a
2203  * window that has extra memory. The _newval_ parameter contains the
2204  * new attribute or extra memory value.  If positive, the _offset_
2205  * parameter is the byte-addressed location in the window's extra
2206  * memory to set.  If negative, _offset_ specifies the window
2207  * attribute to set, and should be one of the following values:
2208  *
2209  * GWL_EXSTYLE      The window's extended window style
2210  *
2211  * GWL_STYLE        The window's window style.
2212  *
2213  * GWLP_WNDPROC     Pointer to the window's window procedure.
2214  *
2215  * GWLP_HINSTANCE   The window's pplication instance handle.
2216  *
2217  * GWLP_ID          The window's identifier.
2218  *
2219  * GWLP_USERDATA    The window's user-specified data.
2220  *
2221  * If the window is a dialog box, the _offset_ parameter can be one of
2222  * the following values:
2223  *
2224  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2225  *
2226  * DWLP_MSGRESULT   The return value of a message
2227  *                  that the dialog box procedure processed.
2228  *
2229  * DWLP_USER        Application specific information.
2230  *
2231  * RETURNS
2232  *
2233  * If successful, returns the previous value located at _offset_. Otherwise,
2234  * returns 0.
2235  *
2236  * NOTES
2237  *
2238  * Extra memory for a window class is specified by a nonzero cbWndExtra
2239  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2240  * time of class creation.
2241  *
2242  * Using GWL_WNDPROC to set a new window procedure effectively creates
2243  * a window subclass. Use CallWindowProc() in the new windows procedure
2244  * to pass messages to the superclass's window procedure.
2245  *
2246  * The user data is reserved for use by the application which created
2247  * the window.
2248  *
2249  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2250  * instead, call the EnableWindow() function to change the window's
2251  * disabled state.
2252  *
2253  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2254  * SetParent() instead.
2255  *
2256  * Win95:
2257  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2258  * it sends WM_STYLECHANGING before changing the settings
2259  * and WM_STYLECHANGED afterwards.
2260  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2261  */
2262 LONG WINAPI SetWindowLongW(
2263     HWND hwnd,  /* [in] window to alter */
2264     INT offset, /* [in] offset, in bytes, of location to alter */
2265     LONG newval /* [in] new value of location */
2266 ) {
2267     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2268 }
2269
2270
2271 /*******************************************************************
2272  *              GetWindowTextA (USER32.@)
2273  */
2274 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2275 {
2276     WCHAR *buffer;
2277
2278     if (!lpString) return 0;
2279
2280     if (WIN_IsCurrentProcess( hwnd ))
2281         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2282
2283     /* when window belongs to other process, don't send a message */
2284     if (nMaxCount <= 0) return 0;
2285     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2286     get_server_window_text( hwnd, buffer, nMaxCount );
2287     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2288         lpString[nMaxCount-1] = 0;
2289     HeapFree( GetProcessHeap(), 0, buffer );
2290     return strlen(lpString);
2291 }
2292
2293
2294 /*******************************************************************
2295  *              InternalGetWindowText (USER32.@)
2296  */
2297 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2298 {
2299     WND *win;
2300
2301     if (nMaxCount <= 0) return 0;
2302     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2303     if (win == WND_DESKTOP) lpString[0] = 0;
2304     else if (win != WND_OTHER_PROCESS)
2305     {
2306         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2307         else lpString[0] = 0;
2308         WIN_ReleasePtr( win );
2309     }
2310     else
2311     {
2312         get_server_window_text( hwnd, lpString, nMaxCount );
2313     }
2314     return strlenW(lpString);
2315 }
2316
2317
2318 /*******************************************************************
2319  *              GetWindowTextW (USER32.@)
2320  */
2321 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2322 {
2323     if (!lpString) return 0;
2324
2325     if (WIN_IsCurrentProcess( hwnd ))
2326         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2327
2328     /* when window belongs to other process, don't send a message */
2329     if (nMaxCount <= 0) return 0;
2330     get_server_window_text( hwnd, lpString, nMaxCount );
2331     return strlenW(lpString);
2332 }
2333
2334
2335 /*******************************************************************
2336  *              SetWindowTextA (USER32.@)
2337  *              SetWindowText  (USER32.@)
2338  */
2339 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2340 {
2341     if (is_broadcast(hwnd))
2342     {
2343         SetLastError( ERROR_INVALID_PARAMETER );
2344         return FALSE;
2345     }
2346     if (!WIN_IsCurrentProcess( hwnd ))
2347         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2348                debugstr_a(lpString), hwnd );
2349     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2350 }
2351
2352
2353 /*******************************************************************
2354  *              SetWindowTextW (USER32.@)
2355  */
2356 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2357 {
2358     if (is_broadcast(hwnd))
2359     {
2360         SetLastError( ERROR_INVALID_PARAMETER );
2361         return FALSE;
2362     }
2363     if (!WIN_IsCurrentProcess( hwnd ))
2364         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2365                debugstr_w(lpString), hwnd );
2366     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2367 }
2368
2369
2370 /*******************************************************************
2371  *              GetWindowTextLengthA (USER32.@)
2372  */
2373 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2374 {
2375     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2376 }
2377
2378 /*******************************************************************
2379  *              GetWindowTextLengthW (USER32.@)
2380  */
2381 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2382 {
2383     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2384 }
2385
2386
2387 /*******************************************************************
2388  *              IsWindow (USER32.@)
2389  */
2390 BOOL WINAPI IsWindow( HWND hwnd )
2391 {
2392     WND *ptr;
2393     BOOL ret;
2394
2395     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2396     if (ptr == WND_DESKTOP) return TRUE;
2397
2398     if (ptr != WND_OTHER_PROCESS)
2399     {
2400         WIN_ReleasePtr( ptr );
2401         return TRUE;
2402     }
2403
2404     /* check other processes */
2405     SERVER_START_REQ( get_window_info )
2406     {
2407         req->handle = hwnd;
2408         ret = !wine_server_call_err( req );
2409     }
2410     SERVER_END_REQ;
2411     return ret;
2412 }
2413
2414
2415 /***********************************************************************
2416  *              GetWindowThreadProcessId (USER32.@)
2417  */
2418 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2419 {
2420     WND *ptr;
2421     DWORD tid = 0;
2422
2423     if (!(ptr = WIN_GetPtr( hwnd )))
2424     {
2425         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2426         return 0;
2427     }
2428
2429     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2430     {
2431         /* got a valid window */
2432         tid = ptr->tid;
2433         if (process) *process = GetCurrentProcessId();
2434         WIN_ReleasePtr( ptr );
2435         return tid;
2436     }
2437
2438     /* check other processes */
2439     SERVER_START_REQ( get_window_info )
2440     {
2441         req->handle = hwnd;
2442         if (!wine_server_call_err( req ))
2443         {
2444             tid = (DWORD)reply->tid;
2445             if (process) *process = (DWORD)reply->pid;
2446         }
2447     }
2448     SERVER_END_REQ;
2449     return tid;
2450 }
2451
2452
2453 /*****************************************************************
2454  *              GetParent (USER32.@)
2455  */
2456 HWND WINAPI GetParent( HWND hwnd )
2457 {
2458     WND *wndPtr;
2459     HWND retvalue = 0;
2460
2461     if (!(wndPtr = WIN_GetPtr( hwnd )))
2462     {
2463         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2464         return 0;
2465     }
2466     if (wndPtr == WND_DESKTOP) return 0;
2467     if (wndPtr == WND_OTHER_PROCESS)
2468     {
2469         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2470         if (style & (WS_POPUP | WS_CHILD))
2471         {
2472             SERVER_START_REQ( get_window_tree )
2473             {
2474                 req->handle = hwnd;
2475                 if (!wine_server_call_err( req ))
2476                 {
2477                     if (style & WS_POPUP) retvalue = reply->owner;
2478                     else if (style & WS_CHILD) retvalue = reply->parent;
2479                 }
2480             }
2481             SERVER_END_REQ;
2482         }
2483     }
2484     else
2485     {
2486         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2487         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2488         WIN_ReleasePtr( wndPtr );
2489     }
2490     return retvalue;
2491 }
2492
2493
2494 /*****************************************************************
2495  *              GetAncestor (USER32.@)
2496  */
2497 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2498 {
2499     WND *win;
2500     HWND *list, ret = 0;
2501
2502     switch(type)
2503     {
2504     case GA_PARENT:
2505         if (!(win = WIN_GetPtr( hwnd )))
2506         {
2507             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2508             return 0;
2509         }
2510         if (win == WND_DESKTOP) return 0;
2511         if (win != WND_OTHER_PROCESS)
2512         {
2513             ret = win->parent;
2514             WIN_ReleasePtr( win );
2515         }
2516         else /* need to query the server */
2517         {
2518             SERVER_START_REQ( get_window_tree )
2519             {
2520                 req->handle = hwnd;
2521                 if (!wine_server_call_err( req )) ret = reply->parent;
2522             }
2523             SERVER_END_REQ;
2524         }
2525         break;
2526
2527     case GA_ROOT:
2528         if (!(list = list_window_parents( hwnd ))) return 0;
2529
2530         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2531         else
2532         {
2533             int count = 2;
2534             while (list[count]) count++;
2535             ret = list[count - 2];  /* get the one before the desktop */
2536         }
2537         HeapFree( GetProcessHeap(), 0, list );
2538         break;
2539
2540     case GA_ROOTOWNER:
2541         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2542         for (;;)
2543         {
2544             HWND parent = GetParent( ret );
2545             if (!parent) break;
2546             ret = parent;
2547         }
2548         break;
2549     }
2550     return ret;
2551 }
2552
2553
2554 /*****************************************************************
2555  *              SetParent (USER32.@)
2556  */
2557 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2558 {
2559     HWND full_handle;
2560
2561     if (is_broadcast(hwnd) || is_broadcast(parent))
2562     {
2563         SetLastError(ERROR_INVALID_PARAMETER);
2564         return 0;
2565     }
2566
2567     if (!parent) parent = GetDesktopWindow();
2568     else parent = WIN_GetFullHandle( parent );
2569
2570     if (!IsWindow( parent ))
2571     {
2572         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2573         return 0;
2574     }
2575
2576     /* Some applications try to set a child as a parent */
2577     if (IsChild(hwnd, parent))
2578     {
2579         SetLastError( ERROR_INVALID_PARAMETER );
2580         return 0;
2581     }
2582
2583     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2584         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2585
2586     return USER_Driver->pSetParent( full_handle, parent );
2587 }
2588
2589
2590 /*******************************************************************
2591  *              IsChild (USER32.@)
2592  */
2593 BOOL WINAPI IsChild( HWND parent, HWND child )
2594 {
2595     HWND *list = list_window_parents( child );
2596     int i;
2597     BOOL ret;
2598
2599     if (!list) return FALSE;
2600     parent = WIN_GetFullHandle( parent );
2601     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2602     ret = (list[i] != 0);
2603     HeapFree( GetProcessHeap(), 0, list );
2604     return ret;
2605 }
2606
2607
2608 /***********************************************************************
2609  *              IsWindowVisible (USER32.@)
2610  */
2611 BOOL WINAPI IsWindowVisible( HWND hwnd )
2612 {
2613     HWND *list;
2614     BOOL retval = TRUE;
2615     int i;
2616
2617     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2618     if (!(list = list_window_parents( hwnd ))) return TRUE;
2619     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2620     {
2621         for (i = 0; list[i+1]; i++)
2622             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2623         retval = !list[i+1];
2624     }
2625     HeapFree( GetProcessHeap(), 0, list );
2626     return retval;
2627 }
2628
2629
2630 /***********************************************************************
2631  *           WIN_IsWindowDrawable
2632  *
2633  * hwnd is drawable when it is visible, all parents are not
2634  * minimized, and it is itself not minimized unless we are
2635  * trying to draw its default class icon.
2636  */
2637 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2638 {
2639     HWND *list;
2640     BOOL retval = TRUE;
2641     int i;
2642     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2643
2644     if (!(style & WS_VISIBLE)) return FALSE;
2645     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2646
2647     if (!(list = list_window_parents( hwnd ))) return TRUE;
2648     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2649     {
2650         for (i = 0; list[i+1]; i++)
2651             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2652                 break;
2653         retval = !list[i+1];
2654     }
2655     HeapFree( GetProcessHeap(), 0, list );
2656     return retval;
2657 }
2658
2659
2660 /*******************************************************************
2661  *              GetTopWindow (USER32.@)
2662  */
2663 HWND WINAPI GetTopWindow( HWND hwnd )
2664 {
2665     if (!hwnd) hwnd = GetDesktopWindow();
2666     return GetWindow( hwnd, GW_CHILD );
2667 }
2668
2669
2670 /*******************************************************************
2671  *              GetWindow (USER32.@)
2672  */
2673 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2674 {
2675     HWND retval = 0;
2676
2677     if (rel == GW_OWNER)  /* this one may be available locally */
2678     {
2679         WND *wndPtr = WIN_GetPtr( hwnd );
2680         if (!wndPtr)
2681         {
2682             SetLastError( ERROR_INVALID_HANDLE );
2683             return 0;
2684         }
2685         if (wndPtr == WND_DESKTOP) return 0;
2686         if (wndPtr != WND_OTHER_PROCESS)
2687         {
2688             retval = wndPtr->owner;
2689             WIN_ReleasePtr( wndPtr );
2690             return retval;
2691         }
2692         /* else fall through to server call */
2693     }
2694
2695     SERVER_START_REQ( get_window_tree )
2696     {
2697         req->handle = hwnd;
2698         if (!wine_server_call_err( req ))
2699         {
2700             switch(rel)
2701             {
2702             case GW_HWNDFIRST:
2703                 retval = reply->first_sibling;
2704                 break;
2705             case GW_HWNDLAST:
2706                 retval = reply->last_sibling;
2707                 break;
2708             case GW_HWNDNEXT:
2709                 retval = reply->next_sibling;
2710                 break;
2711             case GW_HWNDPREV:
2712                 retval = reply->prev_sibling;
2713                 break;
2714             case GW_OWNER:
2715                 retval = reply->owner;
2716                 break;
2717             case GW_CHILD:
2718                 retval = reply->first_child;
2719                 break;
2720             }
2721         }
2722     }
2723     SERVER_END_REQ;
2724     return retval;
2725 }
2726
2727
2728 /*******************************************************************
2729  *              ShowOwnedPopups (USER32.@)
2730  */
2731 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2732 {
2733     int count = 0;
2734     WND *pWnd;
2735     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2736
2737     if (!win_array) return TRUE;
2738
2739     while (win_array[count]) count++;
2740     while (--count >= 0)
2741     {
2742         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2743         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2744         if (pWnd == WND_OTHER_PROCESS) continue;
2745         if (fShow)
2746         {
2747             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2748             {
2749                 WIN_ReleasePtr( pWnd );
2750                 /* In Windows, ShowOwnedPopups(TRUE) generates
2751                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2752                  * regardless of the state of the owner
2753                  */
2754                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2755                 continue;
2756             }
2757         }
2758         else
2759         {
2760             if (pWnd->dwStyle & WS_VISIBLE)
2761             {
2762                 WIN_ReleasePtr( pWnd );
2763                 /* In Windows, ShowOwnedPopups(FALSE) generates
2764                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2765                  * regardless of the state of the owner
2766                  */
2767                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2768                 continue;
2769             }
2770         }
2771         WIN_ReleasePtr( pWnd );
2772     }
2773     HeapFree( GetProcessHeap(), 0, win_array );
2774     return TRUE;
2775 }
2776
2777
2778 /*******************************************************************
2779  *              GetLastActivePopup (USER32.@)
2780  */
2781 HWND WINAPI GetLastActivePopup( HWND hwnd )
2782 {
2783     HWND retval = hwnd;
2784
2785     SERVER_START_REQ( get_window_info )
2786     {
2787         req->handle = hwnd;
2788         if (!wine_server_call_err( req )) retval = reply->last_active;
2789     }
2790     SERVER_END_REQ;
2791     return retval;
2792 }
2793
2794
2795 /*******************************************************************
2796  *           WIN_ListChildren
2797  *
2798  * Build an array of the children of a given window. The array must be
2799  * freed with HeapFree. Returns NULL when no windows are found.
2800  */
2801 HWND *WIN_ListChildren( HWND hwnd )
2802 {
2803     return list_window_children( hwnd, 0, 0 );
2804 }
2805
2806
2807 /*******************************************************************
2808  *              EnumWindows (USER32.@)
2809  */
2810 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2811 {
2812     HWND *list;
2813     BOOL ret = TRUE;
2814     int i;
2815
2816     USER_CheckNotLock();
2817
2818     /* We have to build a list of all windows first, to avoid */
2819     /* unpleasant side-effects, for instance if the callback */
2820     /* function changes the Z-order of the windows.          */
2821
2822     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2823
2824     /* Now call the callback function for every window */
2825
2826     for (i = 0; list[i]; i++)
2827     {
2828         /* Make sure that the window still exists */
2829         if (!IsWindow( list[i] )) continue;
2830         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2831     }
2832     HeapFree( GetProcessHeap(), 0, list );
2833     return ret;
2834 }
2835
2836
2837 /**********************************************************************
2838  *              EnumThreadWindows (USER32.@)
2839  */
2840 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2841 {
2842     HWND *list;
2843     int i;
2844
2845     USER_CheckNotLock();
2846
2847     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2848
2849     /* Now call the callback function for every window */
2850
2851     for (i = 0; list[i]; i++)
2852         if (!func( list[i], lParam )) break;
2853     HeapFree( GetProcessHeap(), 0, list );
2854     return TRUE;
2855 }
2856
2857
2858 /**********************************************************************
2859  *           WIN_EnumChildWindows
2860  *
2861  * Helper function for EnumChildWindows().
2862  */
2863 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2864 {
2865     HWND *childList;
2866     BOOL ret = FALSE;
2867
2868     for ( ; *list; list++)
2869     {
2870         /* Make sure that the window still exists */
2871         if (!IsWindow( *list )) continue;
2872         /* Build children list first */
2873         childList = WIN_ListChildren( *list );
2874
2875         ret = func( *list, lParam );
2876
2877         if (childList)
2878         {
2879             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2880             HeapFree( GetProcessHeap(), 0, childList );
2881         }
2882         if (!ret) return FALSE;
2883     }
2884     return TRUE;
2885 }
2886
2887
2888 /**********************************************************************
2889  *              EnumChildWindows (USER32.@)
2890  */
2891 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2892 {
2893     HWND *list;
2894     BOOL ret;
2895
2896     USER_CheckNotLock();
2897
2898     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2899     ret = WIN_EnumChildWindows( list, func, lParam );
2900     HeapFree( GetProcessHeap(), 0, list );
2901     return ret;
2902 }
2903
2904
2905 /*******************************************************************
2906  *              AnyPopup (USER.52)
2907  */
2908 BOOL16 WINAPI AnyPopup16(void)
2909 {
2910     return AnyPopup();
2911 }
2912
2913
2914 /*******************************************************************
2915  *              AnyPopup (USER32.@)
2916  */
2917 BOOL WINAPI AnyPopup(void)
2918 {
2919     int i;
2920     BOOL retvalue;
2921     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2922
2923     if (!list) return FALSE;
2924     for (i = 0; list[i]; i++)
2925     {
2926         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2927     }
2928     retvalue = (list[i] != 0);
2929     HeapFree( GetProcessHeap(), 0, list );
2930     return retvalue;
2931 }
2932
2933
2934 /*******************************************************************
2935  *              FlashWindow (USER32.@)
2936  */
2937 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2938 {
2939     WND *wndPtr;
2940
2941     TRACE("%p\n", hWnd);
2942
2943     if (IsIconic( hWnd ))
2944     {
2945         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2946
2947         wndPtr = WIN_GetPtr(hWnd);
2948         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2949         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2950         {
2951             wndPtr->flags |= WIN_NCACTIVATED;
2952         }
2953         else
2954         {
2955             wndPtr->flags &= ~WIN_NCACTIVATED;
2956         }
2957         WIN_ReleasePtr( wndPtr );
2958         return TRUE;
2959     }
2960     else
2961     {
2962         WPARAM wparam;
2963
2964         wndPtr = WIN_GetPtr(hWnd);
2965         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2966         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2967
2968         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2969         else wparam = (hWnd == GetForegroundWindow());
2970
2971         WIN_ReleasePtr( wndPtr );
2972         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2973         return wparam;
2974     }
2975 }
2976
2977 /*******************************************************************
2978  *              FlashWindowEx (USER32.@)
2979  */
2980 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2981 {
2982     FIXME("%p\n", pfwi);
2983     return TRUE;
2984 }
2985
2986 /*******************************************************************
2987  *              GetWindowContextHelpId (USER32.@)
2988  */
2989 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2990 {
2991     DWORD retval;
2992     WND *wnd = WIN_GetPtr( hwnd );
2993     if (!wnd || wnd == WND_DESKTOP) return 0;
2994     if (wnd == WND_OTHER_PROCESS)
2995     {
2996         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2997         return 0;
2998     }
2999     retval = wnd->helpContext;
3000     WIN_ReleasePtr( wnd );
3001     return retval;
3002 }
3003
3004
3005 /*******************************************************************
3006  *              SetWindowContextHelpId (USER32.@)
3007  */
3008 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3009 {
3010     WND *wnd = WIN_GetPtr( hwnd );
3011     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3012     if (wnd == WND_OTHER_PROCESS)
3013     {
3014         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3015         return 0;
3016     }
3017     wnd->helpContext = id;
3018     WIN_ReleasePtr( wnd );
3019     return TRUE;
3020 }
3021
3022
3023 /*******************************************************************
3024  *              DragDetect (USER32.@)
3025  */
3026 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3027 {
3028     MSG msg;
3029     RECT rect;
3030     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3031     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3032
3033     rect.left = pt.x - wDragWidth;
3034     rect.right = pt.x + wDragWidth;
3035
3036     rect.top = pt.y - wDragHeight;
3037     rect.bottom = pt.y + wDragHeight;
3038
3039     SetCapture(hWnd);
3040
3041     while(1)
3042     {
3043         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3044         {
3045             if( msg.message == WM_LBUTTONUP )
3046             {
3047                 ReleaseCapture();
3048                 return 0;
3049             }
3050             if( msg.message == WM_MOUSEMOVE )
3051             {
3052                 POINT tmp;
3053                 tmp.x = LOWORD(msg.lParam);
3054                 tmp.y = HIWORD(msg.lParam);
3055                 if( !PtInRect( &rect, tmp ))
3056                 {
3057                     ReleaseCapture();
3058                     return 1;
3059                 }
3060             }
3061         }
3062         WaitMessage();
3063     }
3064     return 0;
3065 }
3066
3067 /******************************************************************************
3068  *              GetWindowModuleFileNameA (USER32.@)
3069  */
3070 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3071 {
3072     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3073           hwnd, lpszFileName, cchFileNameMax);
3074     return 0;
3075 }
3076
3077 /******************************************************************************
3078  *              GetWindowModuleFileNameW (USER32.@)
3079  */
3080 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3081 {
3082     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3083           hwnd, lpszFileName, cchFileNameMax);
3084     return 0;
3085 }
3086
3087 /******************************************************************************
3088  *              GetWindowInfo (USER32.@)
3089  *
3090  * Note: tests show that Windows doesn't check cbSize of the structure.
3091  */
3092 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3093 {
3094     if (!pwi) return FALSE;
3095     if (!IsWindow(hwnd)) return FALSE;
3096
3097     GetWindowRect(hwnd, &pwi->rcWindow);
3098     GetClientRect(hwnd, &pwi->rcClient);
3099     /* translate to screen coordinates */
3100     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3101
3102     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3103     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3104     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3105
3106     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3107     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3108
3109     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3110     pwi->wCreatorVersion = 0x0400;
3111
3112     return TRUE;
3113 }
3114
3115 /******************************************************************************
3116  *              SwitchDesktop (USER32.@)
3117  *
3118  * NOTES: Sets the current input or interactive desktop.
3119  */
3120 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3121 {
3122     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3123     return TRUE;
3124 }
3125
3126 /*****************************************************************************
3127  *              SetLayeredWindowAttributes (USER32.@)
3128  */
3129 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3130                                         BYTE bAlpha, DWORD dwFlags )
3131 {
3132     FIXME("(%p,0x%.8lx,%d,%ld): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3133     return TRUE;
3134 }
3135
3136 /*****************************************************************************
3137  *              UpdateLayeredWindow (USER32.@)
3138  */
3139 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3140                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3141                                  DWORD dwFlags)
3142 {
3143     FIXME("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%ld): stub!\n",
3144           hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3145     return 0;
3146 }
3147
3148 /* 64bit versions */
3149
3150 #ifdef GetWindowLongPtrW
3151 #undef GetWindowLongPtrW
3152 #endif
3153
3154 #ifdef GetWindowLongPtrA
3155 #undef GetWindowLongPtrA
3156 #endif
3157
3158 #ifdef SetWindowLongPtrW
3159 #undef SetWindowLongPtrW
3160 #endif
3161
3162 #ifdef SetWindowLongPtrA
3163 #undef SetWindowLongPtrA
3164 #endif
3165
3166 /*****************************************************************************
3167  *              GetWindowLongPtrW (USER32.@)
3168  */
3169 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3170 {
3171     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3172 }
3173
3174 /*****************************************************************************
3175  *              GetWindowLongPtrA (USER32.@)
3176  */
3177 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3178 {
3179     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3180 }
3181
3182 /*****************************************************************************
3183  *              SetWindowLongPtrW (USER32.@)
3184  */
3185 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3186 {
3187     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3188 }
3189
3190 /*****************************************************************************
3191  *              SetWindowLongPtrA (USER32.@)
3192  */
3193 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3194 {
3195     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3196 }