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