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