Removed input.h, queue.h, spy.h and sysmetrics.h and moved their
[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 (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\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     {
1147         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1148         else
1149         {
1150             LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1151             if (menuName)
1152             {
1153                 if (HIWORD(cs->hInstance))
1154                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1155                 else
1156                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1157
1158                 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1159             }
1160         }
1161     }
1162     else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1163     WIN_ReleaseWndPtr( wndPtr );
1164
1165     if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1166     {
1167         WIN_DestroyWindow( hwnd );
1168         return 0;
1169     }
1170
1171     /* Notify the parent window only */
1172
1173     send_parent_notify( hwnd, WM_CREATE );
1174     if (!IsWindow( hwnd )) return 0;
1175
1176     if (cs->style & WS_VISIBLE)
1177     {
1178         /* in case WS_VISIBLE got set in the meantime */
1179         if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1180         WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1181         WIN_ReleasePtr( wndPtr );
1182         ShowWindow( hwnd, sw );
1183     }
1184
1185     /* Call WH_SHELL hook */
1186
1187     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1188         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1189
1190     TRACE("created window %p\n", hwnd);
1191     return hwnd;
1192 }
1193
1194
1195 /***********************************************************************
1196  *              CreateWindow (USER.41)
1197  */
1198 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1199                               DWORD style, INT16 x, INT16 y, INT16 width,
1200                               INT16 height, HWND16 parent, HMENU16 menu,
1201                               HINSTANCE16 instance, LPVOID data )
1202 {
1203     return CreateWindowEx16( 0, className, windowName, style,
1204                            x, y, width, height, parent, menu, instance, data );
1205 }
1206
1207
1208 /***********************************************************************
1209  *              CreateWindowEx (USER.452)
1210  */
1211 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1212                                 LPCSTR windowName, DWORD style, INT16 x,
1213                                 INT16 y, INT16 width, INT16 height,
1214                                 HWND16 parent, HMENU16 menu,
1215                                 HINSTANCE16 instance, LPVOID data )
1216 {
1217     ATOM classAtom;
1218     CREATESTRUCTA cs;
1219     char buffer[256];
1220
1221     /* Find the class atom */
1222
1223     if (HIWORD(className))
1224     {
1225         if (!(classAtom = GlobalFindAtomA( className )))
1226         {
1227             ERR( "bad class name %s\n", debugstr_a(className) );
1228             return 0;
1229         }
1230     }
1231     else
1232     {
1233         classAtom = LOWORD(className);
1234         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1235         {
1236             ERR( "bad atom %x\n", classAtom);
1237             return 0;
1238         }
1239         className = buffer;
1240     }
1241
1242     /* Fix the coordinates */
1243
1244     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1245     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1246     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1247     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1248
1249     /* Create the window */
1250
1251     cs.lpCreateParams = data;
1252     cs.hInstance      = HINSTANCE_32(instance);
1253     cs.hMenu          = HMENU_32(menu);
1254     cs.hwndParent     = WIN_Handle32( parent );
1255     cs.style          = style;
1256     cs.lpszName       = windowName;
1257     cs.lpszClass      = className;
1258     cs.dwExStyle      = exStyle;
1259
1260     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1261 }
1262
1263
1264 /***********************************************************************
1265  *              CreateWindowExA (USER32.@)
1266  */
1267 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1268                                  LPCSTR windowName, DWORD style, INT x,
1269                                  INT y, INT width, INT height,
1270                                  HWND parent, HMENU menu,
1271                                  HINSTANCE instance, LPVOID data )
1272 {
1273     ATOM classAtom;
1274     CREATESTRUCTA cs;
1275     char buffer[256];
1276
1277     if(!instance)
1278         instance=GetModuleHandleA(NULL);
1279
1280     if(exStyle & WS_EX_MDICHILD)
1281         return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1282
1283     /* Find the class atom */
1284
1285     if (HIWORD(className))
1286     {
1287         if (!(classAtom = GlobalFindAtomA( className )))
1288         {
1289             ERR( "bad class name %s\n", debugstr_a(className) );
1290             return 0;
1291         }
1292     }
1293     else
1294     {
1295         classAtom = LOWORD(className);
1296         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1297         {
1298             ERR( "bad atom %x\n", classAtom);
1299             return 0;
1300         }
1301         className = buffer;
1302     }
1303
1304     /* Create the window */
1305
1306     cs.lpCreateParams = data;
1307     cs.hInstance      = instance;
1308     cs.hMenu          = menu;
1309     cs.hwndParent     = parent;
1310     cs.x              = x;
1311     cs.y              = y;
1312     cs.cx             = width;
1313     cs.cy             = height;
1314     cs.style          = style;
1315     cs.lpszName       = windowName;
1316     cs.lpszClass      = className;
1317     cs.dwExStyle      = exStyle;
1318
1319     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1320 }
1321
1322
1323 /***********************************************************************
1324  *              CreateWindowExW (USER32.@)
1325  */
1326 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1327                                  LPCWSTR windowName, DWORD style, INT x,
1328                                  INT y, INT width, INT height,
1329                                  HWND parent, HMENU menu,
1330                                  HINSTANCE instance, LPVOID data )
1331 {
1332     ATOM classAtom;
1333     CREATESTRUCTW cs;
1334     WCHAR buffer[256];
1335
1336     if(!instance)
1337         instance=GetModuleHandleW(NULL);
1338
1339     if(exStyle & WS_EX_MDICHILD)
1340         return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1341
1342     /* Find the class atom */
1343
1344     if (HIWORD(className))
1345     {
1346         if (!(classAtom = GlobalFindAtomW( className )))
1347         {
1348             ERR( "bad class name %s\n", debugstr_w(className) );
1349             return 0;
1350         }
1351     }
1352     else
1353     {
1354         classAtom = LOWORD(className);
1355         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1356         {
1357             ERR( "bad atom %x\n", classAtom);
1358             return 0;
1359         }
1360         className = buffer;
1361     }
1362
1363     /* Create the window */
1364
1365     cs.lpCreateParams = data;
1366     cs.hInstance      = instance;
1367     cs.hMenu          = menu;
1368     cs.hwndParent     = parent;
1369     cs.x              = x;
1370     cs.y              = y;
1371     cs.cx             = width;
1372     cs.cy             = height;
1373     cs.style          = style;
1374     cs.lpszName       = windowName;
1375     cs.lpszClass      = className;
1376     cs.dwExStyle      = exStyle;
1377
1378     /* Note: we rely on the fact that CREATESTRUCTA and */
1379     /* CREATESTRUCTW have the same layout. */
1380     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1381 }
1382
1383
1384 /***********************************************************************
1385  *           WIN_SendDestroyMsg
1386  */
1387 static void WIN_SendDestroyMsg( HWND hwnd )
1388 {
1389     GUITHREADINFO info;
1390
1391     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1392     {
1393         if (hwnd == info.hwndCaret) DestroyCaret();
1394     }
1395     if (USER_Driver.pResetSelectionOwner)
1396         USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1397
1398     /*
1399      * Send the WM_DESTROY to the window.
1400      */
1401     SendMessageA( hwnd, WM_DESTROY, 0, 0);
1402
1403     /*
1404      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1405      * make sure that the window still exists when we come back.
1406      */
1407     if (IsWindow(hwnd))
1408     {
1409         HWND* pWndArray;
1410         int i;
1411
1412         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1413
1414         /* start from the end (FIXME: is this needed?) */
1415         for (i = 0; pWndArray[i]; i++) ;
1416
1417         while (--i >= 0)
1418         {
1419             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1420         }
1421         HeapFree( GetProcessHeap(), 0, pWndArray );
1422     }
1423     else
1424       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1425 }
1426
1427
1428 /***********************************************************************
1429  *              DestroyWindow (USER32.@)
1430  */
1431 BOOL WINAPI DestroyWindow( HWND hwnd )
1432 {
1433     BOOL is_child;
1434     HWND h;
1435
1436     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1437     {
1438         SetLastError( ERROR_ACCESS_DENIED );
1439         return FALSE;
1440     }
1441
1442     TRACE("(%p)\n", hwnd);
1443
1444     /* Look whether the focus is within the tree of windows we will
1445      * be destroying.
1446      */
1447     h = GetFocus();
1448     if (h == hwnd || IsChild( hwnd, h ))
1449     {
1450         HWND parent = GetAncestor( hwnd, GA_PARENT );
1451         if (parent == GetDesktopWindow()) parent = 0;
1452         SetFocus( parent );
1453     }
1454
1455       /* Call hooks */
1456
1457     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1458
1459     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1460
1461     if (is_child)
1462     {
1463         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1464             send_parent_notify( hwnd, WM_DESTROY );
1465     }
1466     else if (!GetWindow( hwnd, GW_OWNER ))
1467     {
1468         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1469         /* FIXME: clean up palette - see "Internals" p.352 */
1470     }
1471
1472     if (!IsWindow(hwnd)) return TRUE;
1473
1474     if (USER_Driver.pResetSelectionOwner)
1475         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1476
1477       /* Hide the window */
1478
1479     if (!ShowWindow( hwnd, SW_HIDE ))
1480     {
1481         if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1482     }
1483     if (!IsWindow(hwnd)) return TRUE;
1484
1485       /* Recursively destroy owned windows */
1486
1487     if (!is_child)
1488     {
1489         for (;;)
1490         {
1491             int i, got_one = 0;
1492             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1493             if (list)
1494             {
1495                 for (i = 0; list[i]; i++)
1496                 {
1497                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1498                     if (WIN_IsCurrentThread( list[i] ))
1499                     {
1500                         DestroyWindow( list[i] );
1501                         got_one = 1;
1502                         continue;
1503                     }
1504                     WIN_SetOwner( list[i], 0 );
1505                 }
1506                 HeapFree( GetProcessHeap(), 0, list );
1507             }
1508             if (!got_one) break;
1509         }
1510     }
1511
1512       /* Send destroy messages */
1513
1514     WIN_SendDestroyMsg( hwnd );
1515     if (!IsWindow( hwnd )) return TRUE;
1516
1517       /* Unlink now so we won't bother with the children later on */
1518
1519     WIN_UnlinkWindow( hwnd );
1520
1521       /* Destroy the window storage */
1522
1523     WIN_DestroyWindow( hwnd );
1524     return TRUE;
1525 }
1526
1527
1528 /***********************************************************************
1529  *              CloseWindow (USER32.@)
1530  */
1531 BOOL WINAPI CloseWindow( HWND hwnd )
1532 {
1533     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1534     ShowWindow( hwnd, SW_MINIMIZE );
1535     return TRUE;
1536 }
1537
1538
1539 /***********************************************************************
1540  *              OpenIcon (USER32.@)
1541  */
1542 BOOL WINAPI OpenIcon( HWND hwnd )
1543 {
1544     if (!IsIconic( hwnd )) return FALSE;
1545     ShowWindow( hwnd, SW_SHOWNORMAL );
1546     return TRUE;
1547 }
1548
1549
1550 /***********************************************************************
1551  *           WIN_FindWindow
1552  *
1553  * Implementation of FindWindow() and FindWindowEx().
1554  */
1555 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1556 {
1557     HWND *list = NULL;
1558     HWND retvalue = 0;
1559     int i = 0, len = 0;
1560     WCHAR *buffer = NULL;
1561
1562     if (!parent) parent = GetDesktopWindow();
1563     if (title)
1564     {
1565         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1566         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1567     }
1568
1569     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1570
1571     if (child)
1572     {
1573         child = WIN_GetFullHandle( child );
1574         while (list[i] && list[i] != child) i++;
1575         if (!list[i]) goto done;
1576         i++;  /* start from next window */
1577     }
1578
1579     if (title)
1580     {
1581         while (list[i])
1582         {
1583             if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1584             i++;
1585         }
1586     }
1587     retvalue = list[i];
1588
1589  done:
1590     if (list) HeapFree( GetProcessHeap(), 0, list );
1591     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1592     return retvalue;
1593 }
1594
1595
1596
1597 /***********************************************************************
1598  *              FindWindowA (USER32.@)
1599  */
1600 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1601 {
1602     HWND ret = FindWindowExA( 0, 0, className, title );
1603     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1604     return ret;
1605 }
1606
1607
1608 /***********************************************************************
1609  *              FindWindowExA (USER32.@)
1610  */
1611 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1612                                LPCSTR className, LPCSTR title )
1613 {
1614     ATOM atom = 0;
1615     LPWSTR buffer;
1616     HWND hwnd;
1617     INT len;
1618
1619     if (className)
1620     {
1621         /* If the atom doesn't exist, then no class */
1622         /* with this name exists either. */
1623         if (!(atom = GlobalFindAtomA( className )))
1624         {
1625             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1626             return 0;
1627         }
1628     }
1629     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1630
1631     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1632     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1633     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1634     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1635     HeapFree( GetProcessHeap(), 0, buffer );
1636     return hwnd;
1637 }
1638
1639
1640 /***********************************************************************
1641  *              FindWindowExW (USER32.@)
1642  */
1643 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1644                                LPCWSTR className, LPCWSTR title )
1645 {
1646     ATOM atom = 0;
1647
1648     if (className)
1649     {
1650         /* If the atom doesn't exist, then no class */
1651         /* with this name exists either. */
1652         if (!(atom = GlobalFindAtomW( className )))
1653         {
1654             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1655             return 0;
1656         }
1657     }
1658     return WIN_FindWindow( parent, child, atom, title );
1659 }
1660
1661
1662 /***********************************************************************
1663  *              FindWindowW (USER32.@)
1664  */
1665 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1666 {
1667     return FindWindowExW( 0, 0, className, title );
1668 }
1669
1670
1671 /**********************************************************************
1672  *              GetDesktopWindow (USER32.@)
1673  */
1674 HWND WINAPI GetDesktopWindow(void)
1675 {
1676     if (pWndDesktop) return pWndDesktop->hwndSelf;
1677     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" );
1678     ExitProcess(1);
1679     return 0;
1680 }
1681
1682
1683 /*******************************************************************
1684  *              EnableWindow (USER32.@)
1685  */
1686 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1687 {
1688     WND *wndPtr;
1689     BOOL retvalue;
1690     LONG style;
1691     HWND full_handle;
1692
1693     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1694         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1695
1696     hwnd = full_handle;
1697
1698     TRACE("( %p, %d )\n", hwnd, enable);
1699
1700     if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1701     style = wndPtr->dwStyle;
1702     retvalue = ((style & WS_DISABLED) != 0);
1703     WIN_ReleasePtr( wndPtr );
1704
1705     if (enable && retvalue)
1706     {
1707         WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1708         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1709     }
1710     else if (!enable && !retvalue)
1711     {
1712         SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1713
1714         WIN_SetStyle( hwnd, style | WS_DISABLED );
1715
1716         if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1717             SetFocus( 0 );  /* A disabled window can't have the focus */
1718
1719         if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1720             ReleaseCapture();  /* A disabled window can't capture the mouse */
1721
1722         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1723     }
1724     return retvalue;
1725 }
1726
1727
1728 /***********************************************************************
1729  *              IsWindowEnabled (USER32.@)
1730  */
1731 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1732 {
1733     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1734 }
1735
1736
1737 /***********************************************************************
1738  *              IsWindowUnicode (USER32.@)
1739  */
1740 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1741 {
1742     WND * wndPtr;
1743     BOOL retvalue;
1744
1745     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1746     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1747     WIN_ReleaseWndPtr(wndPtr);
1748     return retvalue;
1749 }
1750
1751
1752 /**********************************************************************
1753  *              GetWindowWord (USER32.@)
1754  */
1755 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1756 {
1757     if (offset >= 0)
1758     {
1759         WORD retvalue = 0;
1760         WND *wndPtr = WIN_GetPtr( hwnd );
1761         if (!wndPtr)
1762         {
1763             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1764             return 0;
1765         }
1766         if (wndPtr == WND_OTHER_PROCESS)
1767         {
1768             if (IsWindow( hwnd ))
1769                 FIXME( "(%d) not supported yet on other process window %p\n", offset, hwnd );
1770             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1771             return 0;
1772         }
1773         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1774         {
1775             WARN("Invalid offset %d\n", offset );
1776             SetLastError( ERROR_INVALID_INDEX );
1777         }
1778         else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1779         WIN_ReleasePtr( wndPtr );
1780         return retvalue;
1781     }
1782
1783     switch(offset)
1784     {
1785     case GWL_HWNDPARENT:
1786         return GetWindowLongW( hwnd, offset );
1787     case GWL_ID:
1788     case GWL_HINSTANCE:
1789         {
1790             LONG ret = GetWindowLongW( hwnd, offset );
1791             if (HIWORD(ret))
1792                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1793             return LOWORD(ret);
1794         }
1795     default:
1796         WARN("Invalid offset %d\n", offset );
1797         return 0;
1798     }
1799 }
1800
1801
1802 /**********************************************************************
1803  *              SetWindowWord (USER32.@)
1804  */
1805 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1806 {
1807     WORD *ptr, retval;
1808     WND * wndPtr;
1809
1810     switch(offset)
1811     {
1812     case GWL_ID:
1813     case GWL_HINSTANCE:
1814     case GWL_HWNDPARENT:
1815         return SetWindowLongW( hwnd, offset, (UINT)newval );
1816     default:
1817         if (offset < 0)
1818         {
1819             WARN("Invalid offset %d\n", offset );
1820             SetLastError( ERROR_INVALID_INDEX );
1821             return 0;
1822         }
1823     }
1824
1825     wndPtr = WIN_GetPtr( hwnd );
1826     if (wndPtr == WND_OTHER_PROCESS)
1827     {
1828         if (IsWindow(hwnd))
1829             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1830                    offset, newval, hwnd );
1831         wndPtr = NULL;
1832     }
1833     if (!wndPtr)
1834     {
1835        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1836        return 0;
1837     }
1838
1839     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1840     {
1841         WARN("Invalid offset %d\n", offset );
1842         WIN_ReleasePtr(wndPtr);
1843         SetLastError( ERROR_INVALID_INDEX );
1844         return 0;
1845     }
1846     ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1847     retval = *ptr;
1848     *ptr = newval;
1849     WIN_ReleasePtr(wndPtr);
1850     return retval;
1851 }
1852
1853
1854 /**********************************************************************
1855  *           WIN_GetWindowLong
1856  *
1857  * Helper function for GetWindowLong().
1858  */
1859 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1860 {
1861     LONG retvalue = 0;
1862     WND *wndPtr;
1863
1864     if (offset == GWL_HWNDPARENT)
1865     {
1866         HWND parent = GetAncestor( hwnd, GA_PARENT );
1867         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1868         return (LONG)parent;
1869     }
1870
1871     if (!(wndPtr = WIN_GetPtr( hwnd )))
1872     {
1873         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1874         return 0;
1875     }
1876
1877     if (wndPtr == WND_OTHER_PROCESS)
1878     {
1879         if (offset >= 0)
1880         {
1881             if (IsWindow(hwnd))
1882                 FIXME( "(%d) not supported on other process window %p\n", offset, hwnd );
1883             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1884             return 0;
1885         }
1886         if (offset == GWL_WNDPROC)
1887         {
1888             SetLastError( ERROR_ACCESS_DENIED );
1889             return 0;
1890         }
1891         SERVER_START_REQ( set_window_info )
1892         {
1893             req->handle = hwnd;
1894             req->flags  = 0;  /* don't set anything, just retrieve */
1895             if (!wine_server_call_err( req ))
1896             {
1897                 switch(offset)
1898                 {
1899                 case GWL_STYLE:     retvalue = reply->old_style; break;
1900                 case GWL_EXSTYLE:   retvalue = reply->old_ex_style; break;
1901                 case GWL_ID:        retvalue = reply->old_id; break;
1902                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1903                 case GWL_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1904                 default:
1905                     SetLastError( ERROR_INVALID_INDEX );
1906                     break;
1907                 }
1908             }
1909         }
1910         SERVER_END_REQ;
1911         return retvalue;
1912     }
1913
1914     /* now we have a valid wndPtr */
1915
1916     if (offset >= 0)
1917     {
1918         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1919         {
1920           /*
1921             * Some programs try to access last element from 16 bit
1922             * code using illegal offset value. Hopefully this is
1923             * what those programs really expect.
1924             */
1925            if (type == WIN_PROC_16 &&
1926                wndPtr->cbWndExtra >= 4 &&
1927                offset == wndPtr->cbWndExtra - sizeof(WORD))
1928            {
1929                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1930
1931                ERR( "- replaced invalid offset %d with %d\n",
1932                     offset, offset2 );
1933
1934                 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1935                 WIN_ReleasePtr( wndPtr );
1936                 return retvalue;
1937             }
1938             WARN("Invalid offset %d\n", offset );
1939             WIN_ReleasePtr( wndPtr );
1940             SetLastError( ERROR_INVALID_INDEX );
1941             return 0;
1942         }
1943         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1944         /* Special case for dialog window procedure */
1945         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1946             retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
1947         WIN_ReleasePtr( wndPtr );
1948         return retvalue;
1949     }
1950
1951     switch(offset)
1952     {
1953     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
1954     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1955     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1956     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
1957     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1958     case GWL_HINSTANCE:  retvalue = (LONG)wndPtr->hInstance; break;
1959     default:
1960         WARN("Unknown offset %d\n", offset );
1961         SetLastError( ERROR_INVALID_INDEX );
1962         break;
1963     }
1964     WIN_ReleasePtr(wndPtr);
1965     return retvalue;
1966 }
1967
1968
1969 /**********************************************************************
1970  *           WIN_SetWindowLong
1971  *
1972  * Helper function for SetWindowLong().
1973  *
1974  * 0 is the failure code. However, in the case of failure SetLastError
1975  * must be set to distinguish between a 0 return value and a failure.
1976  */
1977 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1978                                WINDOWPROCTYPE type )
1979 {
1980     LONG retval = 0;
1981     WND *wndPtr;
1982
1983     TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
1984
1985     if (!WIN_IsCurrentProcess( hwnd ))
1986     {
1987         if (offset == GWL_WNDPROC)
1988         {
1989             SetLastError( ERROR_ACCESS_DENIED );
1990             return 0;
1991         }
1992         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1993     }
1994
1995     wndPtr = WIN_GetPtr( hwnd );
1996     if (wndPtr->hwndSelf == GetDesktopWindow())
1997     {
1998         /* can't change anything on the desktop window */
1999         WIN_ReleasePtr( wndPtr );
2000         SetLastError( ERROR_ACCESS_DENIED );
2001         return 0;
2002     }
2003
2004     if (offset >= 0)
2005     {
2006         LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
2007         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2008         {
2009             WARN("Invalid offset %d\n", offset );
2010             WIN_ReleasePtr( wndPtr );
2011             SetLastError( ERROR_INVALID_INDEX );
2012             return 0;
2013         }
2014         /* Special case for dialog window procedure */
2015         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2016         {
2017             retval = (LONG)WINPROC_GetProc( (WNDPROC)*ptr, type );
2018             WINPROC_SetProc( (WNDPROC *)ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2019             WIN_ReleasePtr( wndPtr );
2020             return retval;
2021         }
2022         retval = *ptr;
2023         *ptr = newval;
2024         WIN_ReleasePtr( wndPtr );
2025     }
2026     else
2027     {
2028         STYLESTRUCT style;
2029         BOOL ok;
2030
2031         /* first some special cases */
2032         switch( offset )
2033         {
2034         case GWL_STYLE:
2035         case GWL_EXSTYLE:
2036             style.styleOld = wndPtr->dwStyle;
2037             style.styleNew = newval;
2038             WIN_ReleasePtr( wndPtr );
2039             SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2040             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2041             newval = style.styleNew;
2042             break;
2043         case GWL_HWNDPARENT:
2044             if (wndPtr->parent == GetDesktopWindow())
2045             {
2046                 WIN_ReleasePtr( wndPtr );
2047                 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2048             }
2049             else
2050             {
2051                 WIN_ReleasePtr( wndPtr );
2052                 return (LONG)SetParent( hwnd, (HWND)newval );
2053             }
2054         case GWL_WNDPROC:
2055             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2056             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2057             WIN_ReleasePtr( wndPtr );
2058             return retval;
2059         case GWL_ID:
2060         case GWL_HINSTANCE:
2061         case GWL_USERDATA:
2062             break;
2063         default:
2064             WIN_ReleasePtr( wndPtr );
2065             WARN("Invalid offset %d\n", offset );
2066             SetLastError( ERROR_INVALID_INDEX );
2067             return 0;
2068         }
2069
2070         SERVER_START_REQ( set_window_info )
2071         {
2072             req->handle = hwnd;
2073             switch(offset)
2074             {
2075             case GWL_STYLE:
2076                 req->flags = SET_WIN_STYLE;
2077                 req->style = newval;
2078                 break;
2079             case GWL_EXSTYLE:
2080                 req->flags = SET_WIN_EXSTYLE;
2081                 req->ex_style = newval;
2082                 break;
2083             case GWL_ID:
2084                 req->flags = SET_WIN_ID;
2085                 req->id = newval;
2086                 break;
2087             case GWL_HINSTANCE:
2088                 req->flags = SET_WIN_INSTANCE;
2089                 req->instance = (void *)newval;
2090                 break;
2091             case GWL_USERDATA:
2092                 req->flags = SET_WIN_USERDATA;
2093                 req->user_data = (void *)newval;
2094                 break;
2095             }
2096             if ((ok = !wine_server_call_err( req )))
2097             {
2098                 switch(offset)
2099                 {
2100                 case GWL_STYLE:
2101                     wndPtr->dwStyle = newval;
2102                     retval = reply->old_style;
2103                     break;
2104                 case GWL_EXSTYLE:
2105                     wndPtr->dwExStyle = newval;
2106                     retval = reply->old_ex_style;
2107                     break;
2108                 case GWL_ID:
2109                     wndPtr->wIDmenu = newval;
2110                     retval = reply->old_id;
2111                     break;
2112                 case GWL_HINSTANCE:
2113                     wndPtr->hInstance = (HINSTANCE)newval;
2114                     retval = (ULONG_PTR)reply->old_instance;
2115                     break;
2116                 case GWL_USERDATA:
2117                     wndPtr->userdata = newval;
2118                     retval = (ULONG_PTR)reply->old_user_data;
2119                     break;
2120                 }
2121             }
2122         }
2123         SERVER_END_REQ;
2124         WIN_ReleasePtr( wndPtr );
2125
2126         if (!ok) return 0;
2127
2128         if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2129             USER_Driver.pSetWindowStyle( hwnd, retval );
2130
2131         if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2132             SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2133
2134     }
2135     return retval;
2136 }
2137
2138
2139 /**********************************************************************
2140  *              GetWindowLong (USER.135)
2141  */
2142 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2143 {
2144     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2145 }
2146
2147
2148 /**********************************************************************
2149  *              GetWindowLongA (USER32.@)
2150  */
2151 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2152 {
2153     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2154 }
2155
2156
2157 /**********************************************************************
2158  *              GetWindowLongW (USER32.@)
2159  */
2160 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2161 {
2162     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2163 }
2164
2165
2166 /**********************************************************************
2167  *              SetWindowLong (USER.136)
2168  */
2169 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2170 {
2171     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2172 }
2173
2174
2175 /**********************************************************************
2176  *              SetWindowLongA (USER32.@)
2177  */
2178 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2179 {
2180     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2181 }
2182
2183
2184 /**********************************************************************
2185  *              SetWindowLongW (USER32.@) Set window attribute
2186  *
2187  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2188  * value in a window's extra memory.
2189  *
2190  * The _hwnd_ parameter specifies the window.  is the handle to a
2191  * window that has extra memory. The _newval_ parameter contains the
2192  * new attribute or extra memory value.  If positive, the _offset_
2193  * parameter is the byte-addressed location in the window's extra
2194  * memory to set.  If negative, _offset_ specifies the window
2195  * attribute to set, and should be one of the following values:
2196  *
2197  * GWL_EXSTYLE      The window's extended window style
2198  *
2199  * GWL_STYLE        The window's window style.
2200  *
2201  * GWL_WNDPROC      Pointer to the window's window procedure.
2202  *
2203  * GWL_HINSTANCE    The window's pplication instance handle.
2204  *
2205  * GWL_ID           The window's identifier.
2206  *
2207  * GWL_USERDATA     The window's user-specified data.
2208  *
2209  * If the window is a dialog box, the _offset_ parameter can be one of
2210  * the following values:
2211  *
2212  * DWL_DLGPROC      The address of the window's dialog box procedure.
2213  *
2214  * DWL_MSGRESULT    The return value of a message
2215  *                  that the dialog box procedure processed.
2216  *
2217  * DWL_USER         Application specific information.
2218  *
2219  * RETURNS
2220  *
2221  * If successful, returns the previous value located at _offset_. Otherwise,
2222  * returns 0.
2223  *
2224  * NOTES
2225  *
2226  * Extra memory for a window class is specified by a nonzero cbWndExtra
2227  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2228  * time of class creation.
2229  *
2230  * Using GWL_WNDPROC to set a new window procedure effectively creates
2231  * a window subclass. Use CallWindowProc() in the new windows procedure
2232  * to pass messages to the superclass's window procedure.
2233  *
2234  * The user data is reserved for use by the application which created
2235  * the window.
2236  *
2237  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2238  * instead, call the EnableWindow() function to change the window's
2239  * disabled state.
2240  *
2241  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2242  * SetParent() instead.
2243  *
2244  * Win95:
2245  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2246  * it sends WM_STYLECHANGING before changing the settings
2247  * and WM_STYLECHANGED afterwards.
2248  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2249  */
2250 LONG WINAPI SetWindowLongW(
2251     HWND hwnd,  /* [in] window to alter */
2252     INT offset, /* [in] offset, in bytes, of location to alter */
2253     LONG newval /* [in] new value of location */
2254 ) {
2255     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2256 }
2257
2258
2259 /*******************************************************************
2260  *              GetWindowTextA (USER32.@)
2261  */
2262 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2263 {
2264     WCHAR *buffer;
2265
2266     if (WIN_IsCurrentProcess( hwnd ))
2267         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2268
2269     /* when window belongs to other process, don't send a message */
2270     if (nMaxCount <= 0) return 0;
2271     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2272     get_server_window_text( hwnd, buffer, nMaxCount );
2273     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2274         lpString[nMaxCount-1] = 0;
2275     HeapFree( GetProcessHeap(), 0, buffer );
2276     return strlen(lpString);
2277 }
2278
2279
2280 /*******************************************************************
2281  *              InternalGetWindowText (USER32.@)
2282  */
2283 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2284 {
2285     WND *win;
2286
2287     if (nMaxCount <= 0) return 0;
2288     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2289     if (win != WND_OTHER_PROCESS)
2290     {
2291         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2292         else lpString[0] = 0;
2293         WIN_ReleasePtr( win );
2294     }
2295     else
2296     {
2297         get_server_window_text( hwnd, lpString, nMaxCount );
2298     }
2299     return strlenW(lpString);
2300 }
2301
2302
2303 /*******************************************************************
2304  *              GetWindowTextW (USER32.@)
2305  */
2306 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2307 {
2308     if (WIN_IsCurrentProcess( hwnd ))
2309         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2310
2311     /* when window belongs to other process, don't send a message */
2312     if (nMaxCount <= 0) return 0;
2313     get_server_window_text( hwnd, lpString, nMaxCount );
2314     return strlenW(lpString);
2315 }
2316
2317
2318 /*******************************************************************
2319  *              SetWindowText  (USER32.@)
2320  *              SetWindowTextA (USER32.@)
2321  */
2322 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2323 {
2324     if (!WIN_IsCurrentProcess( hwnd ))
2325     {
2326         FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2327         SetLastError( ERROR_ACCESS_DENIED );
2328         return FALSE;
2329     }
2330     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2331 }
2332
2333
2334 /*******************************************************************
2335  *              SetWindowTextW (USER32.@)
2336  */
2337 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2338 {
2339     if (!WIN_IsCurrentProcess( hwnd ))
2340     {
2341         FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2342         SetLastError( ERROR_ACCESS_DENIED );
2343         return FALSE;
2344     }
2345     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2346 }
2347
2348
2349 /*******************************************************************
2350  *              GetWindowTextLengthA (USER32.@)
2351  */
2352 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2353 {
2354     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2355 }
2356
2357 /*******************************************************************
2358  *              GetWindowTextLengthW (USER32.@)
2359  */
2360 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2361 {
2362     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2363 }
2364
2365
2366 /*******************************************************************
2367  *              IsWindow (USER32.@)
2368  */
2369 BOOL WINAPI IsWindow( HWND hwnd )
2370 {
2371     WND *ptr;
2372     BOOL ret;
2373
2374     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2375
2376     if (ptr != WND_OTHER_PROCESS)
2377     {
2378         WIN_ReleasePtr( ptr );
2379         return TRUE;
2380     }
2381
2382     /* check other processes */
2383     SERVER_START_REQ( get_window_info )
2384     {
2385         req->handle = hwnd;
2386         ret = !wine_server_call_err( req );
2387     }
2388     SERVER_END_REQ;
2389     return ret;
2390 }
2391
2392
2393 /***********************************************************************
2394  *              GetWindowThreadProcessId (USER32.@)
2395  */
2396 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2397 {
2398     WND *ptr;
2399     DWORD tid = 0;
2400
2401     if (!(ptr = WIN_GetPtr( hwnd )))
2402     {
2403         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2404         return 0;
2405     }
2406
2407     if (ptr != WND_OTHER_PROCESS)
2408     {
2409         /* got a valid window */
2410         tid = ptr->tid;
2411         if (process) *process = GetCurrentProcessId();
2412         WIN_ReleasePtr( ptr );
2413         return tid;
2414     }
2415
2416     /* check other processes */
2417     SERVER_START_REQ( get_window_info )
2418     {
2419         req->handle = hwnd;
2420         if (!wine_server_call_err( req ))
2421         {
2422             tid = (DWORD)reply->tid;
2423             if (process) *process = (DWORD)reply->pid;
2424         }
2425     }
2426     SERVER_END_REQ;
2427     return tid;
2428 }
2429
2430
2431 /*****************************************************************
2432  *              GetParent (USER32.@)
2433  */
2434 HWND WINAPI GetParent( HWND hwnd )
2435 {
2436     WND *wndPtr;
2437     HWND retvalue = 0;
2438
2439     if (!(wndPtr = WIN_GetPtr( hwnd )))
2440     {
2441         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2442         return 0;
2443     }
2444     if (wndPtr == WND_OTHER_PROCESS)
2445     {
2446         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2447         if (style & (WS_POPUP | WS_CHILD))
2448         {
2449             SERVER_START_REQ( get_window_tree )
2450             {
2451                 req->handle = hwnd;
2452                 if (!wine_server_call_err( req ))
2453                 {
2454                     if (style & WS_POPUP) retvalue = reply->owner;
2455                     else if (style & WS_CHILD) retvalue = reply->parent;
2456                 }
2457             }
2458             SERVER_END_REQ;
2459         }
2460     }
2461     else
2462     {
2463         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2464         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2465         WIN_ReleasePtr( wndPtr );
2466     }
2467     return retvalue;
2468 }
2469
2470
2471 /*****************************************************************
2472  *              GetAncestor (USER32.@)
2473  */
2474 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2475 {
2476     WND *win;
2477     HWND *list, ret = 0;
2478
2479     switch(type)
2480     {
2481     case GA_PARENT:
2482         if (!(win = WIN_GetPtr( hwnd )))
2483         {
2484             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2485             return 0;
2486         }
2487         if (win != WND_OTHER_PROCESS)
2488         {
2489             ret = win->parent;
2490             WIN_ReleasePtr( win );
2491         }
2492         else /* need to query the server */
2493         {
2494             SERVER_START_REQ( get_window_tree )
2495             {
2496                 req->handle = hwnd;
2497                 if (!wine_server_call_err( req )) ret = reply->parent;
2498             }
2499             SERVER_END_REQ;
2500         }
2501         break;
2502
2503     case GA_ROOT:
2504         if (!(list = WIN_ListParents( hwnd ))) return 0;
2505
2506         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2507         else
2508         {
2509             int count = 2;
2510             while (list[count]) count++;
2511             ret = list[count - 2];  /* get the one before the desktop */
2512         }
2513         HeapFree( GetProcessHeap(), 0, list );
2514         break;
2515
2516     case GA_ROOTOWNER:
2517         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2518         for (;;)
2519         {
2520             HWND parent = GetParent( ret );
2521             if (!parent) break;
2522             ret = parent;
2523         }
2524         break;
2525     }
2526     return ret;
2527 }
2528
2529
2530 /*****************************************************************
2531  *              SetParent (USER32.@)
2532  */
2533 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2534 {
2535     WND *wndPtr;
2536     HWND retvalue, full_handle;
2537     BOOL was_visible;
2538
2539     if (!parent) parent = GetDesktopWindow();
2540     else parent = WIN_GetFullHandle( parent );
2541
2542     if (!IsWindow( parent ))
2543     {
2544         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2545         return 0;
2546     }
2547
2548     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2549         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2550
2551     hwnd = full_handle;
2552
2553     if (USER_Driver.pSetParent)
2554         return USER_Driver.pSetParent( hwnd, parent );
2555
2556     /* Windows hides the window first, then shows it again
2557      * including the WM_SHOWWINDOW messages and all */
2558     was_visible = ShowWindow( hwnd, SW_HIDE );
2559
2560     if (!IsWindow( parent )) return 0;
2561     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2562
2563     retvalue = wndPtr->parent;  /* old parent */
2564     if (parent != retvalue)
2565     {
2566         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2567
2568         if (parent != GetDesktopWindow()) /* a child window */
2569         {
2570             if (!(wndPtr->dwStyle & WS_CHILD))
2571             {
2572                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2573                 if (menu) DestroyMenu( menu );
2574             }
2575         }
2576     }
2577     WIN_ReleasePtr( wndPtr );
2578
2579     /* SetParent additionally needs to make hwnd the topmost window
2580        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2581        WM_WINDOWPOSCHANGED notification messages.
2582     */
2583     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2584                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2585     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2586      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2587     return retvalue;
2588 }
2589
2590
2591 /*******************************************************************
2592  *              IsChild (USER32.@)
2593  */
2594 BOOL WINAPI IsChild( HWND parent, HWND child )
2595 {
2596     HWND *list = WIN_ListParents( child );
2597     int i;
2598     BOOL ret;
2599
2600     if (!list) return FALSE;
2601     parent = WIN_GetFullHandle( parent );
2602     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2603     ret = (list[i] != 0);
2604     HeapFree( GetProcessHeap(), 0, list );
2605     return ret;
2606 }
2607
2608
2609 /***********************************************************************
2610  *              IsWindowVisible (USER32.@)
2611  */
2612 BOOL WINAPI IsWindowVisible( HWND hwnd )
2613 {
2614     HWND *list;
2615     BOOL retval;
2616     int i;
2617
2618     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2619     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2620     for (i = 0; list[i]; i++)
2621         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2622     retval = !list[i];
2623     HeapFree( GetProcessHeap(), 0, list );
2624     return retval;
2625 }
2626
2627
2628 /***********************************************************************
2629  *           WIN_IsWindowDrawable
2630  *
2631  * hwnd is drawable when it is visible, all parents are not
2632  * minimized, and it is itself not minimized unless we are
2633  * trying to draw its default class icon.
2634  */
2635 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2636 {
2637     HWND *list;
2638     BOOL retval;
2639     int i;
2640     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2641
2642     if (!(style & WS_VISIBLE)) return FALSE;
2643     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2644
2645     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2646     for (i = 0; list[i]; i++)
2647         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2648             break;
2649     retval = !list[i];
2650     HeapFree( GetProcessHeap(), 0, list );
2651     return retval;
2652 }
2653
2654
2655 /*******************************************************************
2656  *              GetTopWindow (USER32.@)
2657  */
2658 HWND WINAPI GetTopWindow( HWND hwnd )
2659 {
2660     if (!hwnd) hwnd = GetDesktopWindow();
2661     return GetWindow( hwnd, GW_CHILD );
2662 }
2663
2664
2665 /*******************************************************************
2666  *              GetWindow (USER32.@)
2667  */
2668 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2669 {
2670     HWND retval = 0;
2671
2672     if (rel == GW_OWNER)  /* this one may be available locally */
2673     {
2674         WND *wndPtr = WIN_GetPtr( hwnd );
2675         if (!wndPtr)
2676         {
2677             SetLastError( ERROR_INVALID_HANDLE );
2678             return 0;
2679         }
2680         if (wndPtr != WND_OTHER_PROCESS)
2681         {
2682             retval = wndPtr->owner;
2683             WIN_ReleasePtr( wndPtr );
2684             return retval;
2685         }
2686         /* else fall through to server call */
2687     }
2688
2689     SERVER_START_REQ( get_window_tree )
2690     {
2691         req->handle = hwnd;
2692         if (!wine_server_call_err( req ))
2693         {
2694             switch(rel)
2695             {
2696             case GW_HWNDFIRST:
2697                 retval = reply->first_sibling;
2698                 break;
2699             case GW_HWNDLAST:
2700                 retval = reply->last_sibling;
2701                 break;
2702             case GW_HWNDNEXT:
2703                 retval = reply->next_sibling;
2704                 break;
2705             case GW_HWNDPREV:
2706                 retval = reply->prev_sibling;
2707                 break;
2708             case GW_OWNER:
2709                 retval = reply->owner;
2710                 break;
2711             case GW_CHILD:
2712                 retval = reply->first_child;
2713                 break;
2714             }
2715         }
2716     }
2717     SERVER_END_REQ;
2718     return retval;
2719 }
2720
2721
2722 /***********************************************************************
2723  *           WIN_InternalShowOwnedPopups
2724  *
2725  * Internal version of ShowOwnedPopups; Wine functions should use this
2726  * to avoid interfering with application calls to ShowOwnedPopups
2727  * and to make sure the application can't prevent showing/hiding.
2728  *
2729  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2730  *
2731  */
2732
2733 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2734 {
2735     int count = 0;
2736     WND *pWnd;
2737     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2738
2739     if (!win_array) return TRUE;
2740
2741     /*
2742      * Show windows Lowest first, Highest last to preserve Z-Order
2743      */
2744     while (win_array[count]) count++;
2745     while (--count >= 0)
2746     {
2747         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2748         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2749
2750         if (pWnd->dwStyle & WS_POPUP)
2751         {
2752             if (fShow)
2753             {
2754                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2755                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2756                 {
2757                     /*
2758                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2759                      */
2760                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2761                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2762                 }
2763             }
2764             else
2765             {
2766                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2767                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2768                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2769                 {
2770                     /*
2771                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2772                      */
2773                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2774                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2775                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2776                 }
2777             }
2778         }
2779         WIN_ReleaseWndPtr( pWnd );
2780     }
2781     HeapFree( GetProcessHeap(), 0, win_array );
2782
2783     return TRUE;
2784 }
2785
2786 /*******************************************************************
2787  *              ShowOwnedPopups (USER32.@)
2788  */
2789 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2790 {
2791     int count = 0;
2792     WND *pWnd;
2793     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2794
2795     if (!win_array) return TRUE;
2796
2797     while (win_array[count]) count++;
2798     while (--count >= 0)
2799     {
2800         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2801         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2802
2803         if (pWnd->dwStyle & WS_POPUP)
2804         {
2805             if (fShow)
2806             {
2807                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2808                 {
2809                     /* In Windows, ShowOwnedPopups(TRUE) generates
2810                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2811                      * regardless of the state of the owner
2812                      */
2813                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2814                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2815                 }
2816             }
2817             else
2818             {
2819                 if (IsWindowVisible(pWnd->hwndSelf))
2820                 {
2821                     /* In Windows, ShowOwnedPopups(FALSE) generates
2822                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2823                      * regardless of the state of the owner
2824                      */
2825                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2826                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2827                 }
2828             }
2829         }
2830         WIN_ReleaseWndPtr( pWnd );
2831     }
2832     HeapFree( GetProcessHeap(), 0, win_array );
2833     return TRUE;
2834 }
2835
2836
2837 /*******************************************************************
2838  *              GetLastActivePopup (USER32.@)
2839  */
2840 HWND WINAPI GetLastActivePopup( HWND hwnd )
2841 {
2842     HWND retval = hwnd;
2843
2844     SERVER_START_REQ( get_window_info )
2845     {
2846         req->handle = hwnd;
2847         if (!wine_server_call_err( req )) retval = reply->last_active;
2848     }
2849     SERVER_END_REQ;
2850     return retval;
2851 }
2852
2853
2854 /*******************************************************************
2855  *           WIN_ListParents
2856  *
2857  * Build an array of all parents of a given window, starting with
2858  * the immediate parent. The array must be freed with HeapFree.
2859  * Returns NULL if window is a top-level window.
2860  */
2861 HWND *WIN_ListParents( HWND hwnd )
2862 {
2863     WND *win;
2864     HWND current, *list;
2865     int pos = 0, size = 16, count = 0;
2866
2867     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2868
2869     current = hwnd;
2870     for (;;)
2871     {
2872         if (!(win = WIN_GetPtr( current ))) goto empty;
2873         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2874         list[pos] = win->parent;
2875         WIN_ReleasePtr( win );
2876         if (!(current = list[pos]))
2877         {
2878             if (!pos) goto empty;
2879             return list;
2880         }
2881         if (++pos == size - 1)
2882         {
2883             /* need to grow the list */
2884             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2885             if (!new_list) goto empty;
2886             list = new_list;
2887             size += 16;
2888         }
2889     }
2890
2891     /* at least one parent belongs to another process, have to query the server */
2892
2893     for (;;)
2894     {
2895         count = 0;
2896         SERVER_START_REQ( get_window_parents )
2897         {
2898             req->handle = hwnd;
2899             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2900             if (!wine_server_call( req )) count = reply->count;
2901         }
2902         SERVER_END_REQ;
2903         if (!count) goto empty;
2904         if (size > count)
2905         {
2906             list[count] = 0;
2907             return list;
2908         }
2909         HeapFree( GetProcessHeap(), 0, list );
2910         size = count + 1;
2911         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2912     }
2913
2914  empty:
2915     HeapFree( GetProcessHeap(), 0, list );
2916     return NULL;
2917 }
2918
2919
2920 /*******************************************************************
2921  *           WIN_ListChildren
2922  *
2923  * Build an array of the children of a given window. The array must be
2924  * freed with HeapFree. Returns NULL when no windows are found.
2925  */
2926 HWND *WIN_ListChildren( HWND hwnd )
2927 {
2928     return list_window_children( hwnd, 0, 0 );
2929 }
2930
2931
2932 /*******************************************************************
2933  *              EnumWindows (USER32.@)
2934  */
2935 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2936 {
2937     HWND *list;
2938     BOOL ret = TRUE;
2939     int i, iWndsLocks;
2940
2941     /* We have to build a list of all windows first, to avoid */
2942     /* unpleasant side-effects, for instance if the callback */
2943     /* function changes the Z-order of the windows.          */
2944
2945     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2946
2947     /* Now call the callback function for every window */
2948
2949     iWndsLocks = WIN_SuspendWndsLock();
2950     for (i = 0; list[i]; i++)
2951     {
2952         /* Make sure that the window still exists */
2953         if (!IsWindow( list[i] )) continue;
2954         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2955     }
2956     WIN_RestoreWndsLock(iWndsLocks);
2957     HeapFree( GetProcessHeap(), 0, list );
2958     return ret;
2959 }
2960
2961
2962 /**********************************************************************
2963  *              EnumThreadWindows (USER32.@)
2964  */
2965 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2966 {
2967     HWND *list;
2968     int i, iWndsLocks;
2969
2970     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2971
2972     /* Now call the callback function for every window */
2973
2974     iWndsLocks = WIN_SuspendWndsLock();
2975     for (i = 0; list[i]; i++)
2976         if (!func( list[i], lParam )) break;
2977     WIN_RestoreWndsLock(iWndsLocks);
2978     HeapFree( GetProcessHeap(), 0, list );
2979     return TRUE;
2980 }
2981
2982
2983 /**********************************************************************
2984  *           WIN_EnumChildWindows
2985  *
2986  * Helper function for EnumChildWindows().
2987  */
2988 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2989 {
2990     HWND *childList;
2991     BOOL ret = FALSE;
2992
2993     for ( ; *list; list++)
2994     {
2995         /* Make sure that the window still exists */
2996         if (!IsWindow( *list )) continue;
2997         /* skip owned windows */
2998         if (GetWindow( *list, GW_OWNER )) continue;
2999         /* Build children list first */
3000         childList = WIN_ListChildren( *list );
3001
3002         ret = func( *list, lParam );
3003
3004         if (childList)
3005         {
3006             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3007             HeapFree( GetProcessHeap(), 0, childList );
3008         }
3009         if (!ret) return FALSE;
3010     }
3011     return TRUE;
3012 }
3013
3014
3015 /**********************************************************************
3016  *              EnumChildWindows (USER32.@)
3017  */
3018 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3019 {
3020     HWND *list;
3021     int iWndsLocks;
3022
3023     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3024     iWndsLocks = WIN_SuspendWndsLock();
3025     WIN_EnumChildWindows( list, func, lParam );
3026     WIN_RestoreWndsLock(iWndsLocks);
3027     HeapFree( GetProcessHeap(), 0, list );
3028     return TRUE;
3029 }
3030
3031
3032 /*******************************************************************
3033  *              AnyPopup (USER.52)
3034  */
3035 BOOL16 WINAPI AnyPopup16(void)
3036 {
3037     return AnyPopup();
3038 }
3039
3040
3041 /*******************************************************************
3042  *              AnyPopup (USER32.@)
3043  */
3044 BOOL WINAPI AnyPopup(void)
3045 {
3046     int i;
3047     BOOL retvalue;
3048     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3049
3050     if (!list) return FALSE;
3051     for (i = 0; list[i]; i++)
3052     {
3053         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3054     }
3055     retvalue = (list[i] != 0);
3056     HeapFree( GetProcessHeap(), 0, list );
3057     return retvalue;
3058 }
3059
3060
3061 /*******************************************************************
3062  *              FlashWindow (USER32.@)
3063  */
3064 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3065 {
3066     WND *wndPtr = WIN_FindWndPtr(hWnd);
3067
3068     TRACE("%p\n", hWnd);
3069
3070     if (!wndPtr) return FALSE;
3071     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
3072
3073     if (wndPtr->dwStyle & WS_MINIMIZE)
3074     {
3075         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3076         {
3077             HDC hDC = GetDC(hWnd);
3078
3079             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3080                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3081
3082             ReleaseDC( hWnd, hDC );
3083             wndPtr->flags |= WIN_NCACTIVATED;
3084         }
3085         else
3086         {
3087             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3088             wndPtr->flags &= ~WIN_NCACTIVATED;
3089         }
3090         WIN_ReleaseWndPtr(wndPtr);
3091         return TRUE;
3092     }
3093     else
3094     {
3095         WPARAM16 wparam;
3096         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3097         else wparam = (hWnd == GetForegroundWindow());
3098
3099         WIN_ReleaseWndPtr(wndPtr);
3100         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3101         return wparam;
3102     }
3103 }
3104
3105
3106 /*******************************************************************
3107  *              GetWindowContextHelpId (USER32.@)
3108  */
3109 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3110 {
3111     DWORD retval;
3112     WND *wnd = WIN_FindWndPtr( hwnd );
3113     if (!wnd) return 0;
3114     retval = wnd->helpContext;
3115     WIN_ReleaseWndPtr(wnd);
3116     return retval;
3117 }
3118
3119
3120 /*******************************************************************
3121  *              SetWindowContextHelpId (USER32.@)
3122  */
3123 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3124 {
3125     WND *wnd = WIN_FindWndPtr( hwnd );
3126     if (!wnd) return FALSE;
3127     wnd->helpContext = id;
3128     WIN_ReleaseWndPtr(wnd);
3129     return TRUE;
3130 }
3131
3132
3133 /*******************************************************************
3134  *              DragDetect (USER32.@)
3135  */
3136 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3137 {
3138     MSG msg;
3139     RECT rect;
3140
3141     rect.left = pt.x - wDragWidth;
3142     rect.right = pt.x + wDragWidth;
3143
3144     rect.top = pt.y - wDragHeight;
3145     rect.bottom = pt.y + wDragHeight;
3146
3147     SetCapture(hWnd);
3148
3149     while(1)
3150     {
3151         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3152         {
3153             if( msg.message == WM_LBUTTONUP )
3154             {
3155                 ReleaseCapture();
3156                 return 0;
3157             }
3158             if( msg.message == WM_MOUSEMOVE )
3159             {
3160                 POINT tmp;
3161                 tmp.x = LOWORD(msg.lParam);
3162                 tmp.y = HIWORD(msg.lParam);
3163                 if( !PtInRect( &rect, tmp ))
3164                 {
3165                     ReleaseCapture();
3166                     return 1;
3167                 }
3168             }
3169         }
3170         WaitMessage();
3171     }
3172     return 0;
3173 }
3174
3175 /******************************************************************************
3176  *              GetWindowModuleFileNameA (USER32.@)
3177  */
3178 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3179 {
3180     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3181           hwnd, lpszFileName, cchFileNameMax);
3182     return 0;
3183 }
3184
3185 /******************************************************************************
3186  *              GetWindowModuleFileNameW (USER32.@)
3187  */
3188 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3189 {
3190     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3191           hwnd, lpszFileName, cchFileNameMax);
3192     return 0;
3193 }
3194
3195 /******************************************************************************
3196  *              GetWindowInfo (USER32.@)
3197  * hwnd: in
3198  * pwi:  out.
3199  * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3200  *    this may be because this structure changed over time. If this is the
3201  *    the case, then please: FIXME.
3202  *    Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3203  */
3204 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3205 {
3206     WND *wndInfo = NULL;
3207     if (!pwi) return FALSE;
3208     if (pwi->cbSize != sizeof(WINDOWINFO))
3209     {
3210         FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3211         return FALSE;
3212     }
3213     wndInfo = WIN_GetPtr(hwnd);
3214     if (!wndInfo) return FALSE;
3215     if (wndInfo == WND_OTHER_PROCESS)
3216     {
3217         FIXME("window belong to other process\n");
3218         return FALSE;
3219     }
3220
3221     pwi->rcWindow = wndInfo->rectWindow;
3222     pwi->rcClient = wndInfo->rectClient;
3223     pwi->dwStyle = wndInfo->dwStyle;
3224     pwi->dwExStyle = wndInfo->dwExStyle;
3225     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3226                     /* if active WS_ACTIVECAPTION, else 0 */
3227
3228     pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3229                     GetSystemMetrics(SM_CXBORDER) : 0);
3230     pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3231                     GetSystemMetrics(SM_CYBORDER) : 0);
3232     /* above two: I'm presuming that borders widths are the same
3233      * for each window - so long as its actually using a border.. */
3234
3235     pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3236     pwi->wCreatorVersion = GetVersion();
3237                     /* Docs say this should be the version that
3238                      * CREATED the window. But eh?.. Isn't that just the
3239                      * version we are running.. Unless ofcourse its some wacky
3240                      * RPC stuff or something */
3241
3242     WIN_ReleasePtr(wndInfo);
3243     return TRUE;
3244 }