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