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