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