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